/** * This file was auto-generated by openapi-typescript. * Do not make direct changes to the file. */ export interface paths { "/api/v1/admin/genius": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get: operations["getGeniusStats"]; put?: never; post: operations["controlGenius"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/tracks/{id}/genius": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get: operations["getTrackGenius"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/healthz": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Живость процесса */ get: operations["getHealthz"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/readyz": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Готовность обслуживать запросы (зависимости доступны) */ get: operations["getReadyz"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/server-info": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Сведения о сервере для клиентов * @description Вызывается без аутентификации: веб и Android проверяют версию сервера, * совместимость клиента и поддерживаемые языки (экран подключения). */ get: operations["getServerInfo"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/auth/login": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Вход по логину и паролю * @description Веб (`client_type: web`) получает refresh-токен в cookie `pipu_rt` * (`HttpOnly; Secure; SameSite=Strict; Path=/api/v1/auth`), Android — в поле `refresh_token`. * Неверный логин или пароль, а также временно заблокированный перебором вход — всегда * `401 auth.invalid_credentials`. Превышен лимит попыток с адреса — `429 auth.too_many_attempts`. */ post: operations["login"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/auth/refresh": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Ротация refresh-токена * @description Refresh-токен берётся из cookie `pipu_rt` (веб) или из тела (Android). Старый токен * становится использованным; его повторное предъявление отзывает всю семью токенов. */ post: operations["refreshTokens"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/auth/logout": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Выход — отзыв текущей сессии */ post: operations["logout"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/auth/logout-all": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Выход на всех устройствах */ post: operations["logoutAll"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Текущий пользователь */ get: operations["getMe"]; put?: never; post?: never; delete?: never; options?: never; head?: never; /** * Изменить имя, язык, настройки интерфейса * @description Поля `ui_prefs` сливаются с сохранёнными; не переданные поля не меняются. */ patch: operations["updateMe"]; trace?: never; }; "/api/v1/me/password": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Сменить пароль * @description `current_password` обязателен, кроме случая `must_change_password` (вход по временному паролю). * Все сессии отзываются; текущему устройству выдаётся новая пара токенов. */ post: operations["changePassword"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/bootstrap-credentials": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Первый запуск — новые логин и пароль администратора * @description Только при `must_change_credentials`. Пароль должен отличаться от текущего. * Все прочие сессии отзываются, выдаётся новая пара токенов. */ post: operations["setBootstrapCredentials"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/sessions": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Активные сессии (устройства) */ get: operations["listMySessions"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/sessions/{id}": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; post?: never; /** Завершить сессию на устройстве */ delete: operations["revokeMySession"]; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/users": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Пользователи (admin, moderator) * @description Сортировка по логину. `q` ищет по логину и имени без учёта регистра. */ get: operations["listUsers"]; put?: never; /** * Создать пользователя * @description Пароль генерирует сервер и возвращает **один раз**; при первом входе его нужно сменить. * Модератор создаёт только `user`, админ — любые роли. */ post: operations["createUser"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/users/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; get?: never; put?: never; post?: never; /** Удалить пользователя (admin) */ delete: operations["deleteUser"]; options?: never; head?: never; /** * Изменить имя, роль, блокировку * @description Роль меняет только админ. Смена роли и блокировка мгновенно отзывают токены пользователя. * Последнего активного админа нельзя понизить или заблокировать — `409 users.last_admin`. */ patch: operations["updateUser"]; trace?: never; }; "/api/v1/admin/users/{id}/reset-password": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; get?: never; put?: never; /** * Сбросить пароль * @description Новый временный пароль возвращается один раз; все сессии пользователя завершаются. */ post: operations["resetUserPassword"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/users/{id}/reset-recommendations": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; get?: never; put?: never; /** * Сбросить рекомендации * @description Рекомендации начинаются с нуля: стираются профиль вкуса (онбординг, CF-вектор, бандит), * статистика прослушиваний и показы волны; онбординг покажется снова. * Лайки, дизлайки и история остаются. */ post: operations["resetUserRecommendations"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads/quota": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Квота очереди на добавление (moderator, admin) */ get: operations["getUploadQuota"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads/precheck": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Предпроверка дублей до загрузки (moderator, admin) * @description Ничего не резервирует. SHA-256 и теги клиент считает сам (docs/uploads.md#4). */ post: operations["precheckUploads"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Создать пачку и зарезервировать место (moderator, admin) * @description Для принятых файлов — `tus_url` (tus 1.0.0, только HEAD / PATCH, куски до 64 МБ). Не поместившиеся — * `uploads.queue_full` / `uploads.user_quota_full`, дубли — `uploads.duplicate`, без места в квоте. */ post: operations["createUploadBatch"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads/mine": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Мои предложения (moderator, admin) */ get: operations["listMyUploads"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads/unseen": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Сколько решений по своим предложениям с прошлого визита (moderator, admin) */ get: operations["unseenUploadDecisions"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads/seen": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Отметить свои предложения просмотренными */ post: operations["markUploadsSeen"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/uploads/files/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; put?: never; post?: never; /** * Отозвать своё предложение до решения * @description HEAD / PATCH по этому же адресу — приём файла по tus (вне контракта OpenAPI). */ delete: operations["withdrawUpload"]; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/uploads": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Очередь на добавление (admin) */ get: operations["listUploads"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/uploads/files/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; put?: never; post?: never; delete?: never; options?: never; head?: never; /** * Править метаданные и хранилище (admin) * @description Путь в хранилище пересчитывается; правленые теги записываются в файл при импорте. */ patch: operations["updateUpload"]; trace?: never; }; "/api/v1/admin/uploads/files/{id}/retry": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; put?: never; /** Повторить импорт после import_failed (admin) */ post: operations["retryUploadImport"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/uploads/files/{id}/stream": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Прослушать файл из staging (подпись, как у стрима трека) * @description Ссылку даёт `stream_url` файла очереди. Range поддерживается. */ get: operations["streamUpload"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/uploads/batches/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; put?: never; post?: never; delete?: never; options?: never; head?: never; /** * Правка метаданных и обложки на всю пачку (admin) * @description Исполнитель, альбом и год применяются к файлам в pending_review и import_failed. Обложка встраивается при импорте. */ patch: operations["updateUploadBatch"]; trace?: never; }; "/api/v1/admin/uploads/review": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Одобрить / отклонить файлы (admin) */ post: operations["reviewUploads"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/settings/uploads": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Настройки очереди (admin) */ get: operations["getUploadSettings"]; put?: never; post?: never; delete?: never; options?: never; head?: never; /** * Изменить настройки очереди (admin) * @description Уменьшение лимита ниже занятого ничего не удаляет — новые загрузки ждут, пока очередь освободится. */ patch: operations["updateUploadSettings"]; trace?: never; }; "/api/v1/admin/audit": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Журнал действий (admin), новые сверху */ get: operations["listAudit"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Хранилища (admin) */ get: operations["listSources"]; put?: never; /** * Подключить хранилище (admin) * @description `local` — подпапка в каталоге LIBRARY_HOST сервера; `nfs` — монтирует storage-agent. * Хранилище сохраняется, даже если подключиться не удалось: статус и сообщение — в ответе. */ post: operations["createSource"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; /** Хранилище (admin) */ get: operations["getSource"]; put?: never; post?: never; /** * Отключить и удалить хранилище (admin) * @description Треки, файлы которых были только в этом хранилище, удаляются из каталога. */ delete: operations["deleteSource"]; options?: never; head?: never; /** * Изменить хранилище (admin) * @description Изменение адреса NFS или папки переподключает хранилище. */ patch: operations["updateSource"]; trace?: never; }; "/api/v1/admin/sources/{id}/test": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; get?: never; put?: never; /** Проверить подключение (admin) */ post: operations["testSource"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources/{id}/patterns": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; /** Шаблоны путей (admin) */ get: operations["getSourcePatterns"]; /** * Заменить шаблоны путей (admin) * @description Ошибка компиляции — `422 validation.pattern_invalid` с `params.index` и `params.reason`. */ put: operations["putSourcePatterns"]; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources/{id}/patterns/preview": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; get?: never; put?: never; /** Предпросмотр разбора путей без сохранения (admin) */ post: operations["previewSourcePatterns"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources/{id}/write-template/suggest": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; get?: never; put?: never; /** * Подобрать шаблон пути по существующей структуре (admin) * @description Выражение хранилища, совпавшее с наибольшим числом путей выборки, превращается в шаблон. * Не удалось (нет файлов или выражения не переводятся) — `422 library.template_unavailable`. */ post: operations["suggestWriteTemplate"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources/{id}/write-template/check": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; get?: never; put?: never; /** * Проверить шаблон на обратимость (admin) * @description Шаблон применяется к 50 трекам хранилища, пути разбираются его выражениями обратно. */ post: operations["checkWriteTemplate"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/sources/{id}/scan": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; get?: never; put?: never; /** * Запустить скан (admin) * @description Скан идёт в фоне; прогресс — в `GET /admin/library/status`. Уже идёт — `409 library.scan_running`. */ post: operations["scanSource"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/library/status": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Состояние библиотеки (admin, moderator) */ get: operations["getLibraryStatus"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/library/errors": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Файлы, которые не удалось прочитать (admin) */ get: operations["listLibraryErrors"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/library/host-dirs": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Подпапки каталога LIBRARY_HOST — выбор папки для local-хранилища (admin) */ get: operations["listHostDirs"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/artists/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; /** Исполнитель */ get: operations["getArtist"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/artists/{id}/albums": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; /** Альбомы исполнителя (свои и сборники с его треками) */ get: operations["listArtistAlbums"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/artists/{id}/top-tracks": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; /** Популярные треки исполнителя (по прослушиваниям всех пользователей) */ get: operations["listArtistTopTracks"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/albums/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; /** Альбом с треками */ get: operations["getAlbum"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/tracks/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; /** Трек */ get: operations["getTrack"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/search/suggest": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Выпадающий список поиска — до 3 исполнителей, 3 альбомов, 5 треков * @description Если по запросу ничего не найдено, сервер повторяет его в другой раскладке клавиатуры * («ghbdtn» → «привет») и возвращает исправленный запрос в `corrected_query`. */ get: operations["searchSuggest"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/search": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Страница поиска * @description `type=all` — по несколько результатов каждого вида без пагинации; * конкретный тип — страницы с `next_cursor`. */ get: operations["search"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/library/analysis/retry": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Вернуть в очередь треки, которые не удалось проанализировать (admin) */ post: operations["retryAnalysis"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/admin/search/reindex": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Пересобрать поисковые индексы (admin) */ post: operations["reindexSearch"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/covers/{id}": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Обложка альбома (WebP) * @description Ссылку целиком даёт `cover_url` альбома (подписана, без срока: обложка с данным `v` неизменна); * клиент добавляет `size`. Файл отдаёт nginx через X-Accel-Redirect. */ get: operations["getCover"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/stream/{id}": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Аудио трека (поддерживает Range) * @description Ссылку целиком даёт `stream_url` трека (подпись пользователя и срок 12 ч); клиент может добавить `q`. * Файл отдаёт nginx через X-Accel-Redirect: оригинал из хранилища или транскод в Opus из кэша. */ get: operations["streamTrack"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/tracks/batch": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Треки по списку id (восстановление очереди) */ post: operations["getTracksBatch"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/events": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** * Пачка событий прослушивания (до 500) * @description Повторно присланные события (тот же id) не учитываются дважды. */ post: operations["postEvents"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/playback-state": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Последнее состояние плеера (трек, позиция, очередь) */ get: operations["getPlaybackState"]; /** Сохранить состояние плеера (last-write-wins) */ put: operations["putPlaybackState"]; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/history": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** История прослушиваний, новые сверху */ get: operations["getHistory"]; put?: never; post?: never; /** Очистить историю (события остаются для статистики) */ delete: operations["clearHistory"]; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/likes": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Лайки, новые сверху */ get: operations["getLikes"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/dislikes": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Дизлайки, новые сверху */ get: operations["getDislikes"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/reactions/tracks/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; /** Лайк или дизлайк трека */ put: operations["setTrackReaction"]; post?: never; /** Снять реакцию */ delete: operations["clearTrackReaction"]; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/onboarding": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Анкета рекомендаций — варианты, сохранённые ответы и необходимость заполнения * @description `required` — пользователь не проходил и не пропускал анкету либо администратор сбросил рекомендации. * `choice` содержит ответы с текущей приблизительной возрастной группой; исходная группа и год хранятся на сервере. */ get: operations["getOnboarding"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/onboarding": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; /** Сохранить выбор онбординга (или пропуск — пустые списки) */ put: operations["saveOnboarding"]; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/wave/options": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Занятия и настроения (ключи для i18n и иконки) */ get: operations["getWaveOptions"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/wave/sessions": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get?: never; put?: never; /** Начать «Мою волну» */ post: operations["startWave"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/wave/sessions/{id}": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; put?: never; post?: never; /** Завершить сессию волны */ delete: operations["endWave"]; options?: never; head?: never; /** Сменить занятие / настроение на лету — пачка пересобирается */ patch: operations["updateWave"]; trace?: never; }; "/api/v1/wave/sessions/{id}/next": { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; get?: never; put?: never; /** Следующая пачка с учётом реакций на выданные треки */ post: operations["nextWave"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/app/clients": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Клиенты последних релизов (Android и десктоп) * @description Тот же релиз Gitea, что и для Android: APK, установщик Windows, .deb, DMG. * У каждой платформы `older` — предыдущие сборки (до 8 релизов, сколько есть с файлами). * Нет настроек Gitea или файлов клиентов — `404 app.update_unavailable`. */ get: operations["getAppClients"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/app/download/{client}/{version}": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** Файл клиента (кэшируется на сервере, поддерживает Range) */ get: operations["downloadAppClient"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/app/android/latest": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** * Последняя версия Android-приложения (из релизов Gitea через сервер) * @description Сервер сам опрашивает Gitea своим токеном и кэширует ответ на 10 минут, поэтому приложению * не нужен доступ к Gitea. Нет настроек Gitea или релиза с APK — `404 app.update_unavailable`. */ get: operations["getAndroidLatest"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/app/android/download/{version}": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; /** APK версии (кэшируется на сервере, поддерживает Range для докачки) */ get: operations["downloadAndroidApk"]; put?: never; post?: never; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/playlists": { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; get: operations["listPlaylists"]; put?: never; post: operations["createPlaylist"]; delete?: never; options?: never; head?: never; patch?: never; trace?: never; }; "/api/v1/me/playlists/{id}": { parameters: { query?: never; header?: never; path: { id: string; }; cookie?: never; }; get: operations["getPlaylist"]; put: operations["updatePlaylist"]; post?: never; delete: operations["deletePlaylist"]; options?: never; head?: never; patch?: never; trace?: never; }; } export type webhooks = Record; export interface components { schemas: { PlaylistInput: { name: string; description: string; track_ids: string[]; }; PlaylistUpdate: components["schemas"]["PlaylistInput"] & { revision: number; }; PlaylistSummary: { /** Format: uuid */ id: string; name: string; description: string; revision: number; track_count: number; /** Format: int64 */ duration_ms: number; /** Format: date-time */ created_at: string; /** Format: date-time */ updated_at: string; }; Playlist: components["schemas"]["PlaylistSummary"] & { tracks: components["schemas"]["Track"][]; }; PlaylistList: { items: components["schemas"]["PlaylistSummary"][]; }; Onboarding: { required: boolean; choice?: components["schemas"]["OnboardingChoice"]; artists: { /** Format: uuid */ id: string; name: string; track_count: number; /** @description Обложка самого большого альбома исполнителя */ cover_url: string | null; cover_colors: string[]; }[]; genres: { name: string; track_count: number; }[]; }; OnboardingChoice: { /** @enum {string|null} */ gender?: "male" | "female" | "other" | null; /** * @description Текущая приблизительная возрастная группа. Сервер хранит год выбора и учитывает прошедшие годы. * @enum {string|null} */ age_group?: "under_13" | "13_19" | "20_29" | "30_39" | "40_49" | "50_59" | "60_plus" | null; /** @description Год последнего выбора возрастной группы. */ readonly age_group_year?: number; artist_ids: string[]; genres: string[]; }; UserRef: { /** Format: uuid */ id: string; username: string; }; /** @enum {string} */ UploadStatus: "uploading" | "processing" | "pending_review" | "approved" | "importing" | "imported" | "import_failed" | "duplicate" | "invalid" | "rejected" | "withdrawn" | "expired"; UploadQuota: { /** Format: int64 */ limit_bytes: number; /** Format: int64 */ used_bytes: number; /** Format: int64 */ per_user_limit_bytes: number | null; /** Format: int64 */ user_used_bytes: number; /** Format: int64 */ max_file_bytes: number; }; UploadPrecheckRequest: { files: { client_id: string; /** Format: int64 */ size: number; sha256: string; artist?: string; title?: string; duration_ms?: number; album?: string; }[]; }; UploadPrecheckResult: { files: { client_id: string; /** @enum {string} */ result: "accepted" | "duplicate" | "too_large"; /** * Format: uuid * @description С каким треком совпал (дубль или похожие метаданные) */ track_id: string | null; /** @description Совпали только метаданные — файл примут, админ решит */ possible_duplicate: boolean; }[]; }; UploadBatchRequest: { comment?: string; files: { client_id: string; name: string; /** @description Относительный путь в перетащенной папке */ rel_path?: string; /** Format: int64 */ size: number; sha256: string; }[]; }; UploadBatchCreated: { /** Format: uuid */ batch_id: string; files: { client_id: string; /** Format: uuid */ upload_file_id: string | null; tus_url: string | null; /** @description Код отказа — uploads.queue_full, uploads.user_quota_full, uploads.too_large, uploads.duplicate, uploads.unsupported_format */ rejected: string | null; /** Format: uuid */ track_id: string | null; }[]; }; UploadMeta: { artist: string; albumartist: string; album: string; title: string; genre: string; year: number | null; track: number | null; disc: number | null; }; UploadFile: { /** Format: uuid */ id: string; /** Format: uuid */ batch_id: string; batch_comment: string | null; author: components["schemas"]["UserRef"]; status: components["schemas"]["UploadStatus"]; original_name: string; client_rel_path: string | null; /** Format: int64 */ size_bytes: number; /** Format: int64 */ received_bytes: number; format: string | null; codec: string | null; bitrate: number | null; sample_rate: number | null; bit_depth: number | null; duration_ms: number | null; tags: { [key: string]: string; }; metadata: components["schemas"]["UploadMeta"] | null; metadata_edited: boolean; /** * Format: uuid * @description Найден в каталоге — файл добавится к существующему исполнителю */ matched_artist_id: string | null; /** * Format: uuid * @description Найден в каталоге — «будет добавлено к существующему альбому» */ matched_album_id: string | null; /** Format: uuid */ duplicate_of_track_id: string | null; /** @enum {string|null} */ duplicate_level: "sha256" | "metadata" | "fingerprint" | null; possible_duplicate: boolean; /** @description Тот же трек, но лучшего качества — ждёт решения, если включён allow_quality_upgrade */ quality_upgrade: boolean; /** Format: uuid */ target_source_id: string | null; /** @description Путь в хранилище по write_template (null — не построился, причина в status_reason) */ target_rel_path: string | null; status_reason: string | null; /** Format: date-time */ reviewed_at: string | null; /** Format: date-time */ created_at: string; /** Format: date-time */ updated_at: string; /** @description Только автору и пока файл в статусе uploading */ tus_url: string | null; /** @description Подписанная ссылка прослушивания из staging; null, если файла уже нет */ stream_url: string | null; }; UploadFilePage: { items: components["schemas"]["UploadFile"][]; next_cursor: string | null; }; UploadPatch: { metadata?: components["schemas"]["UploadMeta"]; /** Format: uuid */ target_source_id?: string; }; /** @description Пустые поля не меняют файлы. cover_base64 null снимает обложку пачки. */ UploadBatchPatch: { artist?: string; album?: string; year?: number | null; /** @description JPEG, PNG или WebP, не больше 8 МБ после декодирования */ cover_base64?: string | null; }; UploadReviewRequest: { file_ids: string[]; /** @enum {string} */ decision: "approve" | "reject"; /** @description Причина отклонения — её видит автор */ reason?: string; }; UploadReviewResult: { items: { /** Format: uuid */ id: string; ok: boolean; error: components["schemas"]["Problem"] | null; }[]; }; UploadSettings: { /** Format: int64 */ queue_limit_bytes: number; /** Format: int64 */ per_user_limit_bytes: number | null; /** Format: int64 */ max_file_bytes: number; /** Format: uuid */ default_source_id: string | null; /** @description Тот же трек в лучшем качестве идёт на рассмотрение, а не в дубли */ allow_quality_upgrade: boolean; }; /** @description Лимит на пользователя и хранилище по умолчанию передаются всегда (null — выключить / не задано). */ UploadSettingsPatch: { /** Format: int64 */ queue_limit_bytes?: number; /** * Format: int64 * @description null — выключить лимит на пользователя */ per_user_limit_bytes: number | null; /** Format: int64 */ max_file_bytes?: number; /** * Format: uuid * @description null — без хранилища по умолчанию */ default_source_id: string | null; allow_quality_upgrade?: boolean; }; HealthStatus: { /** @enum {string} */ status: "ok"; }; ReadyStatus: { /** @enum {string} */ status: "ok" | "degraded"; /** @description Результат проверки каждой зависимости */ checks: { [key: string]: string; }; }; ServerInfo: { /** @example pipu-music */ name: string; /** * @description Версия сервера (SemVer) * @example 0.1.0 */ version: string; /** @example v1 */ api_version: string; /** * @example [ * "ru", * "en" * ] */ supported_locales: string[]; /** * @description Минимальный versionCode Android-приложения, которое поддерживает сервер * @example 10099 */ min_android_version_code: number; /** @description Первый вход администратора ещё не завершён — клиент может показать подсказку */ bootstrap_required: boolean; }; /** @enum {string} */ Role: "admin" | "moderator" | "user"; /** @enum {string} */ ClientType: "web" | "android" | "desktop"; LoginRequest: { username: string; password: string; client_type: components["schemas"]["ClientType"]; /** @description Например «Chrome / Windows», «Pixel 8» */ device_name?: string; }; RefreshRequest: { /** @description Android и desktop; веб передаёт токен в cookie */ refresh_token?: string; }; AuthTokens: { access_token: string; /** @enum {string} */ token_type: "Bearer"; /** @description Срок жизни access-токена, секунды */ expires_in: number; /** @description Для `client_type: android` и `client_type: desktop` */ refresh_token?: string; user: components["schemas"]["Me"]; }; UiPrefs: { /** @enum {string} */ theme?: "dark" | "light" | "system"; /** @enum {string} */ wave_variant?: "orb" | "liquid"; /** @enum {string} */ web_player?: "bar" | "island"; /** * @description Где в топбаре веба поиск (по умолчанию center) * @enum {string} */ search_position?: "center" | "left" | "right"; /** @description Сворачивать поиск в кнопку с лупой без фокуса (по умолчанию false) */ search_collapse?: boolean; /** @description Показывать на главной веба выбор занятия (по умолчанию true) */ home_activities?: boolean; /** @description Показывать на главной веба выбор настроения (по умолчанию true) */ home_moods?: boolean; /** @enum {string} */ mobile_player?: "cover" | "wave"; ambient?: boolean; crossfade_s?: number; normalize?: boolean; }; Me: { /** Format: uuid */ id: string; username: string; display_name: string | null; role: components["schemas"]["Role"]; /** @description Может рассматривать очередь на добавление. Не следует из роли и может быть у нескольких людей сразу */ reviews_uploads: boolean; locale: string; ui_prefs: components["schemas"]["UiPrefs"]; must_change_password: boolean; must_change_credentials: boolean; /** Format: date-time */ created_at: string; }; UpdateMeRequest: { /** @description Пустая строка — сбросить имя */ display_name?: string; locale?: string; ui_prefs?: components["schemas"]["UiPrefs"]; }; ChangePasswordRequest: { current_password?: string; new_password: string; }; BootstrapCredentialsRequest: { new_username: string; new_password: string; }; AdminUser: { /** Format: uuid */ id: string; username: string; display_name: string | null; role: components["schemas"]["Role"]; /** @description Может рассматривать очередь на добавление. Не следует из роли и может быть у нескольких людей сразу */ reviews_uploads: boolean; locale: string; is_blocked: boolean; must_change_password: boolean; must_change_credentials: boolean; /** Format: date-time */ created_at: string; /** Format: date-time */ last_login_at: string | null; }; AdminUserPage: { items: components["schemas"]["AdminUser"][]; next_cursor: string | null; }; CreateUserRequest: { username: string; display_name?: string; role: components["schemas"]["Role"]; /** @description Сразу выдать аудит загрузок. Может задать только админ */ reviews_uploads?: boolean; }; CreatedUser: { user: components["schemas"]["AdminUser"]; /** @description Показывается один раз */ temporary_password: string; }; UpdateUserRequest: { /** @description Новый логин. Может менять только администратор, в том числе у себя */ username?: string; /** @description Пустая строка — сбросить имя */ display_name?: string; role?: components["schemas"]["Role"]; is_blocked?: boolean; /** @description Выдать или забрать аудит загрузок. Может менять только админ, в том числе у себя */ reviews_uploads?: boolean; }; TemporaryPassword: { temporary_password: string; }; AuditActor: { /** Format: uuid */ id: string; username: string; }; AuditEntry: { /** Format: uuid */ id: string; /** @description null — система или удалённый пользователь */ actor: components["schemas"]["AuditActor"] | null; /** @example user.create */ action: string; target_type: string | null; /** Format: uuid */ target_id: string | null; payload: { [key: string]: unknown; } | null; /** Format: date-time */ created_at: string; }; AuditPage: { items: components["schemas"]["AuditEntry"][]; next_cursor: string | null; }; /** @enum {string} */ SourceType: "nfs" | "local"; /** @enum {string} */ SourceStatus: "pending" | "mounted" | "error" | "disabled"; /** @enum {string} */ TagPriority: "tags_first" | "path_first"; Source: { /** Format: uuid */ id: string; name: string; type: components["schemas"]["SourceType"]; nfs_server: string | null; nfs_export: string | null; nfs_options: string; /** @description Подпапка относительно LIBRARY_HOST, пусто — весь каталог */ local_path: string | null; tag_priority: components["schemas"]["TagPriority"]; /** @description Автоматический скан, null — только вручную */ scan_interval_minutes: number | null; /** @description Принимает импорт из очереди на добавление (NFS монтируется агентом ещё и на запись) */ accepts_uploads: boolean; /** @description Шаблон пути новых файлов (docs/uploads.md#7), null — не задан */ write_template: string | null; status: components["schemas"]["SourceStatus"]; status_message: string | null; /** Format: date-time */ last_scan_at: string | null; /** Format: date-time */ created_at: string; scan: components["schemas"]["ScanProgress"] | null; }; SourceList: { items: components["schemas"]["Source"][]; }; SourceInput: { name: string; type: components["schemas"]["SourceType"]; nfs_server?: string; nfs_export?: string; nfs_options?: string; local_path?: string; tag_priority?: components["schemas"]["TagPriority"]; scan_interval_minutes?: number | null; accepts_uploads?: boolean; write_template?: string; }; SourcePatch: { name?: string; nfs_server?: string; nfs_export?: string; nfs_options?: string; local_path?: string; tag_priority?: components["schemas"]["TagPriority"]; /** @description 0 — отключить автоматический скан */ scan_interval_minutes?: number; /** @description false — отключить хранилище (треки становятся недоступны), true — подключить снова */ enabled?: boolean; /** @description Смена переподключает NFS-хранилище (rw-точка агента) */ accepts_uploads?: boolean; /** * @description Шаблон пути новых файлов; пусто — убрать. Неверный синтаксис — `422 validation.template_invalid` * с `params.reason`. Проверка обратимости не обязательна для сохранения — её показывает `write-template/check`. */ write_template?: string; }; SourceTestResult: { ok: boolean; message: string; /** @description Сколько аудиофайлов найдено (проверка останавливается на 1000) */ audio_files: number; /** @description Удалось создать и удалить `.pipu-write-test` (только для accepts_uploads; иначе null) */ write_ok?: boolean | null; write_message?: string | null; }; WriteTemplateSuggestion: { template: string; }; WriteTemplateCheckRequest: { template: string; }; WriteTemplateMismatch: { /** @description Реальный путь файла */ rel_path: string; /** @description Путь по шаблону, null — не построился */ rendered: string | null; /** @description Поля, которые регэкспы хранилища распознали не так; `pattern` — не совпало ни одно выражение */ fields: string[]; error: string | null; }; WriteTemplateCheck: { /** @description Все пути разобраны обратно без изменений и ≥ 90% совпали с реальными */ ok: boolean; total: number; round_trip: number; same_path: number; mismatches: components["schemas"]["WriteTemplateMismatch"][]; }; PathPattern: { regex: string; is_enabled: boolean; }; PatternList: { patterns: components["schemas"]["PathPattern"][]; }; PatternPreviewRequest: { patterns: components["schemas"]["PathPattern"][]; /** @default 50 */ sample: number; }; TrackMeta: { artist: string; album_artist: string; album: string; title: string; genres: string[]; year: number | null; track: number | null; disc: number | null; }; PreviewItem: { rel_path: string; /** @description Номер совпавшего шаблона, null — ни один */ pattern_index: number | null; skipped: boolean; path_fields: { [key: string]: string; }; tags: { [key: string]: string; }; result: components["schemas"]["TrackMeta"]; error: string | null; }; PatternPreview: { items: components["schemas"]["PreviewItem"][]; unmatched: number; }; ScanRequest: { /** @description Перечитать все файлы, а не только новые и изменённые */ full?: boolean; }; ScanProgress: { running: boolean; full: boolean; /** Format: date-time */ started_at: string; /** Format: date-time */ finished_at: string | null; found: number; to_process: number; processed: number; added: number; updated: number; moved: number; missing: number; errors: number; error: string | null; }; LibraryStatus: { analysis: components["schemas"]["AnalysisStatus"]; wave: components["schemas"]["WaveMetrics"]; artists: number; albums: number; tracks: number; files: number; missing_files: number; file_errors: number; sources: components["schemas"]["SourceStatusItem"][]; }; SourceStatusItem: { /** Format: uuid */ id: string; name: string; status: components["schemas"]["SourceStatus"]; status_message: string | null; /** Format: date-time */ last_scan_at: string | null; scan: components["schemas"]["ScanProgress"] | null; }; LibraryError: { /** Format: uuid */ file_id: string; /** Format: uuid */ source_id: string; rel_path: string; error: string; }; LibraryErrorPage: { items: components["schemas"]["LibraryError"][]; next_cursor: string | null; }; HostDirList: { path: string; dirs: string[]; }; ArtistRef: { /** Format: uuid */ id: string; name: string; }; AlbumRef: { /** Format: uuid */ id: string; title: string; year: number | null; cover_url: string | null; cover_colors: string[]; }; Track: { /** Format: uuid */ id: string; title: string; duration_ms: number; artists: components["schemas"]["ArtistRef"][]; album: components["schemas"]["AlbumRef"]; genres: string[]; disc_no: number | null; track_no: number | null; /** @description Есть доступный файл (хранилище подключено, файл на месте) */ available: boolean; /** @description Подписанная ссылка на аудио (12 ч); null — трек недоступен */ stream_url: string | null; reaction: components["schemas"]["Reaction"] | null; /** @description Аудиопризнаки (после анализа) — для анимации волны и выравнивания громкости */ features: components["schemas"]["TrackFeatures"] | null; }; GeniusStats: { configured: boolean; paused: boolean; running: boolean; total: number; pending: number; matched: number; lyrics: number; annotations: number; images: number; unmatched: number; errors: number; last_error: string; /** Format: date-time */ cooldown_until: string; }; GeniusContent: { status: string; lyrics: string; source_url: string; song_image_url: string; artist_image_url: string; description: string; annotations: components["schemas"]["GeniusAnnotation"][]; }; GeniusAnnotation: { fragment: string; text: string; url: string; verified: boolean; authors: string; }; Artist: { image_url?: string; /** Format: uuid */ id: string; name: string; album_count: number; track_count: number; }; AlbumSummary: { /** Format: uuid */ id: string; title: string; year: number | null; cover_url: string | null; cover_colors: string[]; artist: components["schemas"]["ArtistRef"]; track_count: number; }; AlbumSummaryList: { items: components["schemas"]["AlbumSummary"][]; }; Album: { /** Format: uuid */ id: string; title: string; year: number | null; cover_url: string | null; cover_colors: string[]; artist: components["schemas"]["ArtistRef"]; duration_ms: number; tracks: components["schemas"]["Track"][]; }; SearchResults: { artists: components["schemas"]["ArtistRef"][]; albums: components["schemas"]["AlbumSummary"][]; tracks: components["schemas"]["Track"][]; /** @description Оценка общего числа совпадений */ totals: { artists: number; albums: number; tracks: number; }; /** @description Запрос в другой раскладке, если по исходному ничего не нашлось */ corrected_query: string | null; next_cursor: string | null; }; TrackFeatures: { bpm: number | null; energy: number | null; loudness_lufs: number | null; }; /** @enum {string} */ StreamQuality: "auto" | "original" | "high" | "medium" | "low"; /** @enum {string} */ Reaction: "like" | "dislike"; TrackIds: { ids: string[]; }; TrackList: { items: components["schemas"]["Track"][]; }; PlayEvent: { /** * Format: uuid * @description UUIDv7 от клиента — ключ идемпотентности */ id: string; /** @enum {string} */ type: "play_start" | "play_end" | "skip" | "seek" | "pause" | "resume" | "like" | "unlike" | "dislike" | "undislike"; /** Format: uuid */ track_id: string; /** Format: date-time */ occurred_at: string; position_ms?: number; played_ms?: number; from_ms?: number; /** @enum {string} */ context_type?: "wave" | "album" | "artist" | "search" | "collection" | "history" | "queue"; context_id?: string; /** Format: uuid */ wave_session_id?: string; offline?: boolean; }; EventBatch: { events: components["schemas"]["PlayEvent"][]; }; EventBatchResult: { accepted: number; duplicates: number; /** @description Слишком старые (> 30 дней) или с неизвестным треком */ rejected: number; }; PlaybackContext: { type?: string; id?: string; label?: string; /** Format: uuid */ wave_session_id?: string; }; PlaybackStateInput: { /** Format: uuid */ track_id: string | null; position_ms: number; queue: string[]; queue_index: number; context?: components["schemas"]["PlaybackContext"]; shuffle?: boolean; /** @enum {string} */ repeat_mode?: "off" | "one" | "all"; volume?: number; device_id?: string; }; PlaybackState: { /** Format: uuid */ track_id: string | null; position_ms: number; queue: string[]; queue_index: number; context: components["schemas"]["PlaybackContext"] | null; shuffle: boolean; /** @enum {string} */ repeat_mode: "off" | "one" | "all"; volume: number; device_id: string | null; /** Format: date-time */ updated_at: string | null; }; HistoryItem: { /** Format: uuid */ id: string; /** Format: date-time */ played_at: string; track: components["schemas"]["Track"]; }; HistoryPage: { items: components["schemas"]["HistoryItem"][]; next_cursor: string | null; }; ReactedTrack: { /** Format: date-time */ created_at: string; track: components["schemas"]["Track"]; }; ReactedTrackPage: { items: components["schemas"]["ReactedTrack"][]; total: number; next_cursor: string | null; }; ReactionInput: { reaction: components["schemas"]["Reaction"]; }; WaveOption: { /** @example running */ key: string; /** @description Имя иконки Material Symbols */ icon: string; }; WaveOptions: { activities: components["schemas"]["WaveOption"][]; moods: components["schemas"]["WaveOption"][]; }; WaveContext: { activity?: string | null; mood?: string | null; }; WaveStart: { activity?: string | null; mood?: string | null; seed?: { /** @enum {string} */ type: "track" | "album" | "artist"; /** Format: uuid */ id: string; }; }; WaveFeedback: { /** Format: uuid */ track_id: string; /** @enum {string} */ outcome: "complete" | "skip" | "skip_early" | "like" | "dislike"; }; WaveNext: { feedback?: components["schemas"]["WaveFeedback"][]; }; WaveBatch: { /** Format: uuid */ session_id: string; activity: string | null; mood: string | null; tracks: components["schemas"]["Track"][]; /** @description Рекомендатель недоступен — пачка собрана упрощённо (лайки, любимые исполнители) */ fallback: boolean; }; AnalysisStatus: { queued: number; running: number; done: number; failed: number; analyzer_ver: string | null; /** @description Самая частая ошибка среди неудавшихся — подсказка, что чинить */ top_error: string | null; }; /** @description Метрики волны за 7 дней */ WaveMetrics: { served: number; listen_through_rate: number | null; early_skip_rate: number | null; /** @description Лайков на 100 треков */ like_rate: number | null; sessions: number; /** @description Те же метрики по версии модели показа (v1 / ALS / ранжировщик) — сравнение онлайн */ by_model: components["schemas"]["WaveModelMetrics"][]; }; WaveModelMetrics: { model_ver: string; served: number; listen_through_rate: number | null; early_skip_rate: number | null; like_rate: number | null; }; /** @enum {string} */ AppClient: "android" | "windows" | "linux" | "macos"; AppClientBuild: { version: string; filename: string; /** Format: int64 */ size: number; sha256?: string; download_url: string; }; AppClientFile: { client: components["schemas"]["AppClient"]; version?: string; filename: string; /** Format: int64 */ size: number; sha256?: string; download_url: string; older?: components["schemas"]["AppClientBuild"][]; }; AppClients: { version: string; version_code: number; notes_md: string; clients: components["schemas"]["AppClientFile"][]; }; AndroidRelease: { /** @example 0.6.1 */ version: string; version_code: number; /** @description Что нового (Markdown из релиза) */ notes_md: string; /** Format: int64 */ size: number; sha256: string; download_url: string; /** @description Версии ниже обязаны обновиться */ min_supported: number; }; Session: { /** Format: uuid */ id: string; device_name: string | null; client_type: components["schemas"]["ClientType"]; /** * Format: date-time * @description Время входа */ created_at: string; /** Format: date-time */ last_used_at: string; /** @description Сессия, из которой сделан запрос */ current: boolean; }; SessionList: { items: components["schemas"]["Session"][]; }; FieldError: { field: string; code: string; }; Problem: { /** @default about:blank */ type: string; status: number; /** @description Машинный код ошибки для i18n, например `auth.invalid_credentials` */ code: string; /** @description Пояснение для логов (не для показа пользователю) */ detail?: string; params?: { [key: string]: unknown; }; /** @description Ошибки отдельных полей запроса */ errors?: components["schemas"]["FieldError"][]; }; }; responses: { /** @description Ошибка (RFC 9457) */ Problem: { headers: { [name: string]: unknown; }; content: { "application/problem+json": components["schemas"]["Problem"]; }; }; }; parameters: { SourceId: string; EntityId: string; Limit: number; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ Cursor: string; /** @description Статусы через запятую */ UploadStatusFilter: components["schemas"]["UploadStatus"][]; UserId: string; }; requestBodies: never; headers: never; pathItems: never; } export type $defs = Record; export interface operations { getGeniusStats: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Persistent enrichment statistics (admin only) */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["GeniusStats"]; }; }; }; }; controlGenius: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": { /** @enum {string} */ action: "start" | "pause" | "retry"; }; }; }; responses: { /** @description Updated statistics */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["GeniusStats"]; }; }; }; }; getTrackGenius: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Cached lyrics and annotations; never makes an upstream request */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["GeniusContent"]; }; }; }; }; getHealthz: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Процесс жив */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["HealthStatus"]; }; }; }; }; getReadyz: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Все зависимости доступны */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["ReadyStatus"]; }; }; /** @description Одна или несколько зависимостей недоступны */ 503: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["ReadyStatus"]; }; }; }; }; getServerInfo: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Сведения о сервере */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["ServerInfo"]; }; }; default: components["responses"]["Problem"]; }; }; login: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["LoginRequest"]; }; }; responses: { /** @description Успешный вход */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AuthTokens"]; }; }; default: components["responses"]["Problem"]; }; }; refreshTokens: { parameters: { query?: never; header?: never; path?: never; cookie?: { pipu_rt?: string; }; }; requestBody?: { content: { "application/json": components["schemas"]["RefreshRequest"]; }; }; responses: { /** @description Новая пара токенов */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AuthTokens"]; }; }; default: components["responses"]["Problem"]; }; }; logout: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Сессия завершена, cookie `pipu_rt` очищена */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; logoutAll: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Все сессии пользователя завершены */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; getMe: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Профиль */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Me"]; }; }; default: components["responses"]["Problem"]; }; }; updateMe: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UpdateMeRequest"]; }; }; responses: { /** @description Обновлённый профиль */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Me"]; }; }; default: components["responses"]["Problem"]; }; }; changePassword: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["ChangePasswordRequest"]; }; }; responses: { /** @description Пароль изменён, новая пара токенов */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AuthTokens"]; }; }; default: components["responses"]["Problem"]; }; }; setBootstrapCredentials: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["BootstrapCredentialsRequest"]; }; }; responses: { /** @description Учётные данные заменены, новая пара токенов */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AuthTokens"]; }; }; default: components["responses"]["Problem"]; }; }; listMySessions: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Список сессий, новые сверху */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["SessionList"]; }; }; default: components["responses"]["Problem"]; }; }; revokeMySession: { parameters: { query?: never; header?: never; path: { id: string; }; cookie?: never; }; requestBody?: never; responses: { /** @description Сессия завершена */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; listUsers: { parameters: { query?: { q?: string; role?: components["schemas"]["Role"]; limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница пользователей */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AdminUserPage"]; }; }; default: components["responses"]["Problem"]; }; }; createUser: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["CreateUserRequest"]; }; }; responses: { /** @description Пользователь создан */ 201: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["CreatedUser"]; }; }; default: components["responses"]["Problem"]; }; }; deleteUser: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Удалён */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; updateUser: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UpdateUserRequest"]; }; }; responses: { /** @description Обновлённый пользователь */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AdminUser"]; }; }; default: components["responses"]["Problem"]; }; }; resetUserPassword: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Временный пароль */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["TemporaryPassword"]; }; }; default: components["responses"]["Problem"]; }; }; resetUserRecommendations: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["UserId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Сброшено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; getUploadQuota: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Лимиты и занятое место */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadQuota"]; }; }; default: components["responses"]["Problem"]; }; }; precheckUploads: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UploadPrecheckRequest"]; }; }; responses: { /** @description Итог по каждому файлу */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadPrecheckResult"]; }; }; default: components["responses"]["Problem"]; }; }; createUploadBatch: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UploadBatchRequest"]; }; }; responses: { /** @description Пачка создана */ 201: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadBatchCreated"]; }; }; default: components["responses"]["Problem"]; }; }; listMyUploads: { parameters: { query?: { /** @description Статусы через запятую */ status?: components["parameters"]["UploadStatusFilter"]; limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница предложений */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadFilePage"]; }; }; default: components["responses"]["Problem"]; }; }; unseenUploadDecisions: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Число */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { count: number; }; }; }; default: components["responses"]["Problem"]; }; }; markUploadsSeen: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Отмечено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; withdrawUpload: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Отозвано, место освобождено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; listUploads: { parameters: { query?: { /** @description Статусы через запятую */ status?: components["parameters"]["UploadStatusFilter"]; author?: string; batch?: string; possible_duplicate?: boolean; limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница очереди */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadFilePage"]; }; }; default: components["responses"]["Problem"]; }; }; updateUpload: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UploadPatch"]; }; }; responses: { /** @description Файл */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadFile"]; }; }; default: components["responses"]["Problem"]; }; }; retryUploadImport: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Файл снова одобрен */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadFile"]; }; }; default: components["responses"]["Problem"]; }; }; streamUpload: { parameters: { query: { exp: number; sig: string; }; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Аудио из staging */ 200: { headers: { [name: string]: unknown; }; content: { "audio/*": string; }; }; default: components["responses"]["Problem"]; }; }; updateUploadBatch: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UploadBatchPatch"]; }; }; responses: { /** @description Обновлённые файлы пачки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { items: components["schemas"]["UploadFile"][]; }; }; }; default: components["responses"]["Problem"]; }; }; reviewUploads: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UploadReviewRequest"]; }; }; responses: { /** @description Итог по каждому файлу */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadReviewResult"]; }; }; default: components["responses"]["Problem"]; }; }; getUploadSettings: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Настройки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadSettings"]; }; }; default: components["responses"]["Problem"]; }; }; updateUploadSettings: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["UploadSettingsPatch"]; }; }; responses: { /** @description Настройки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["UploadSettings"]; }; }; default: components["responses"]["Problem"]; }; }; listAudit: { parameters: { query?: { limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница журнала */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AuditPage"]; }; }; default: components["responses"]["Problem"]; }; }; listSources: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Список хранилищ */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["SourceList"]; }; }; default: components["responses"]["Problem"]; }; }; createSource: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["SourceInput"]; }; }; responses: { /** @description Хранилище создано */ 201: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Source"]; }; }; default: components["responses"]["Problem"]; }; }; getSource: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Хранилище */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Source"]; }; }; default: components["responses"]["Problem"]; }; }; deleteSource: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Удалено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; updateSource: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["SourcePatch"]; }; }; responses: { /** @description Хранилище */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Source"]; }; }; default: components["responses"]["Problem"]; }; }; testSource: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Результат проверки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["SourceTestResult"]; }; }; default: components["responses"]["Problem"]; }; }; getSourcePatterns: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Шаблоны по порядку */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["PatternList"]; }; }; default: components["responses"]["Problem"]; }; }; putSourcePatterns: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["PatternList"]; }; }; responses: { /** @description Сохранённые шаблоны */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["PatternList"]; }; }; default: components["responses"]["Problem"]; }; }; previewSourcePatterns: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["PatternPreviewRequest"]; }; }; responses: { /** @description Разбор выборки файлов */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["PatternPreview"]; }; }; default: components["responses"]["Problem"]; }; }; suggestWriteTemplate: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Предложенный шаблон */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["WriteTemplateSuggestion"]; }; }; default: components["responses"]["Problem"]; }; }; checkWriteTemplate: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["WriteTemplateCheckRequest"]; }; }; responses: { /** @description Итог проверки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["WriteTemplateCheck"]; }; }; default: components["responses"]["Problem"]; }; }; scanSource: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["SourceId"]; }; cookie?: never; }; requestBody?: { content: { "application/json": components["schemas"]["ScanRequest"]; }; }; responses: { /** @description Скан запущен */ 202: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["ScanProgress"]; }; }; default: components["responses"]["Problem"]; }; }; getLibraryStatus: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Счётчики и сканы */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["LibraryStatus"]; }; }; default: components["responses"]["Problem"]; }; }; listLibraryErrors: { parameters: { query?: { limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница ошибок */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["LibraryErrorPage"]; }; }; default: components["responses"]["Problem"]; }; }; listHostDirs: { parameters: { query?: { /** @description Путь относительно корня, пусто — корень */ path?: string; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Подпапки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["HostDirList"]; }; }; default: components["responses"]["Problem"]; }; }; getArtist: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Исполнитель */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Artist"]; }; }; default: components["responses"]["Problem"]; }; }; listArtistAlbums: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Альбомы исполнителя (свои и сборники с его треками) */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AlbumSummaryList"]; }; }; default: components["responses"]["Problem"]; }; }; listArtistTopTracks: { parameters: { query?: { limit?: number; }; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Треки, самые слушаемые первыми */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["TrackList"]; }; }; default: components["responses"]["Problem"]; }; }; getAlbum: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Альбом с треками */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Album"]; }; }; default: components["responses"]["Problem"]; }; }; getTrack: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Трек */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Track"]; }; }; default: components["responses"]["Problem"]; }; }; searchSuggest: { parameters: { query: { q: string; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Подсказки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["SearchResults"]; }; }; default: components["responses"]["Problem"]; }; }; search: { parameters: { query: { q: string; type?: "all" | "artists" | "albums" | "tracks"; limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Результаты */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["SearchResults"]; }; }; default: components["responses"]["Problem"]; }; }; retryAnalysis: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Сколько задач снова в очереди */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": { requeued: number; }; }; }; default: components["responses"]["Problem"]; }; }; reindexSearch: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Переиндексация запущена */ 202: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; getCover: { parameters: { query: { v: string; sig: string; size?: 64 | 300 | 1200; }; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Картинка */ 200: { headers: { [name: string]: unknown; }; content: { "image/webp": string; }; }; default: components["responses"]["Problem"]; }; }; streamTrack: { parameters: { query: { u: string; exp: number; sig: string; q?: components["schemas"]["StreamQuality"]; }; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Аудио */ 200: { headers: { [name: string]: unknown; }; content: { "audio/*": string; }; }; default: components["responses"]["Problem"]; }; }; getTracksBatch: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["TrackIds"]; }; }; responses: { /** @description Треки в порядке запроса; удалённые пропущены */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["TrackList"]; }; }; default: components["responses"]["Problem"]; }; }; postEvents: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["EventBatch"]; }; }; responses: { /** @description Принято */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["EventBatchResult"]; }; }; default: components["responses"]["Problem"]; }; }; getPlaybackState: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Состояние; пусто — плеер ещё не запускался */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["PlaybackState"]; }; }; default: components["responses"]["Problem"]; }; }; putPlaybackState: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["PlaybackStateInput"]; }; }; responses: { /** @description Сохранённое состояние */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["PlaybackState"]; }; }; default: components["responses"]["Problem"]; }; }; getHistory: { parameters: { query?: { limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница истории */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["HistoryPage"]; }; }; default: components["responses"]["Problem"]; }; }; clearHistory: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Очищено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; getLikes: { parameters: { query?: { limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["ReactedTrackPage"]; }; }; default: components["responses"]["Problem"]; }; }; getDislikes: { parameters: { query?: { limit?: components["parameters"]["Limit"]; /** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */ cursor?: components["parameters"]["Cursor"]; }; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Страница */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["ReactedTrackPage"]; }; }; default: components["responses"]["Problem"]; }; }; setTrackReaction: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["ReactionInput"]; }; }; responses: { /** @description Сохранено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; clearTrackReaction: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Снято */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; getOnboarding: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Варианты и состояние */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Onboarding"]; }; }; default: components["responses"]["Problem"]; }; }; saveOnboarding: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["OnboardingChoice"]; }; }; responses: { /** @description Сохранено */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; getWaveOptions: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Варианты */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["WaveOptions"]; }; }; default: components["responses"]["Problem"]; }; }; startWave: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: { content: { "application/json": components["schemas"]["WaveStart"]; }; }; responses: { /** @description Сессия и первая пачка */ 201: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["WaveBatch"]; }; }; default: components["responses"]["Problem"]; }; }; endWave: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: never; responses: { /** @description Завершена */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; updateWave: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["WaveContext"]; }; }; responses: { /** @description Новая пачка */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["WaveBatch"]; }; }; default: components["responses"]["Problem"]; }; }; nextWave: { parameters: { query?: never; header?: never; path: { id: components["parameters"]["EntityId"]; }; cookie?: never; }; requestBody?: { content: { "application/json": components["schemas"]["WaveNext"]; }; }; responses: { /** @description Пачка */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["WaveBatch"]; }; }; default: components["responses"]["Problem"]; }; }; getAppClients: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Доступные сборки */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AppClients"]; }; }; default: components["responses"]["Problem"]; }; }; downloadAppClient: { parameters: { query?: never; header?: never; path: { client: components["schemas"]["AppClient"]; version: string; }; cookie?: never; }; requestBody?: never; responses: { /** @description Установщик или APK */ 200: { headers: { [name: string]: unknown; }; content: { "application/octet-stream": string; }; }; default: components["responses"]["Problem"]; }; }; getAndroidLatest: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Последний релиз */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["AndroidRelease"]; }; }; default: components["responses"]["Problem"]; }; }; downloadAndroidApk: { parameters: { query?: never; header?: never; path: { version: string; }; cookie?: never; }; requestBody?: never; responses: { /** @description APK */ 200: { headers: { [name: string]: unknown; }; content: { "application/vnd.android.package-archive": string; }; }; default: components["responses"]["Problem"]; }; }; listPlaylists: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody?: never; responses: { /** @description Success */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["PlaylistList"]; }; }; default: components["responses"]["Problem"]; }; }; createPlaylist: { parameters: { query?: never; header?: never; path?: never; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["PlaylistInput"]; }; }; responses: { /** @description Success */ 201: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Playlist"]; }; }; default: components["responses"]["Problem"]; }; }; getPlaylist: { parameters: { query?: never; header?: never; path: { id: string; }; cookie?: never; }; requestBody?: never; responses: { /** @description Success */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Playlist"]; }; }; default: components["responses"]["Problem"]; }; }; updatePlaylist: { parameters: { query?: never; header?: never; path: { id: string; }; cookie?: never; }; requestBody: { content: { "application/json": components["schemas"]["PlaylistUpdate"]; }; }; responses: { /** @description Success */ 200: { headers: { [name: string]: unknown; }; content: { "application/json": components["schemas"]["Playlist"]; }; }; default: components["responses"]["Problem"]; }; }; deletePlaylist: { parameters: { query?: never; header?: never; path: { id: string; }; cookie?: never; }; requestBody?: never; responses: { /** @description Deleted */ 204: { headers: { [name: string]: unknown; }; content?: never; }; default: components["responses"]["Problem"]; }; }; }