feat(api): library sources, scanner and catalog (M2)
ci / api / api (push) Successful in 26s
ci / mobile / mobile (Metro-бандл Android) (push) Failing after 22s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 37s
ci / ts / ts (packages + web) (push) Successful in 51s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 53s
ci / api / api (push) Successful in 26s
ci / mobile / mobile (Metro-бандл Android) (push) Failing after 22s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 37s
ci / ts / ts (packages + web) (push) Successful in 51s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 53s
- schema for sources, path patterns, media files, artists, albums, tracks, genres (migration 00003) - path patterns (RE2 with named groups, skip), merge with tags by source priority, fallbacks from the file name and folder, name normalization and multi-artist split - scanner: walk, skip unchanged files by size and mtime, ffprobe in 8 workers with a single catalog writer, renames by content hash keep the track, duplicates fold into one track with the best file as primary, missing files are kept 30 days - storage-agent mounts NFS with validated server, export and an option whitelist, no shell; test mount counts audio files - admin API: sources CRUD, connection test, patterns with preview, scan, library status, file errors, host folder picker; scheduled scans and health checks; mounts are restored on start - catalog API: artist, artist albums, album with tracks, track - api image is alpine with ffmpeg for ffprobe Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ab092def54
commit
c583991d14
24 files changed
+7467
-84
No files matched your search
@@ -322,6 +322,265 @@ export interface paths {
|
||||
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}/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/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;
|
||||
};
|
||||
}
|
||||
export type webhooks = Record<string, never>;
|
||||
export interface components {
|
||||
@@ -491,6 +750,217 @@ export interface components {
|
||||
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;
|
||||
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;
|
||||
};
|
||||
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;
|
||||
};
|
||||
SourceTestResult: {
|
||||
ok: boolean;
|
||||
message: string;
|
||||
/** @description Сколько аудиофайлов найдено (проверка останавливается на 1000) */
|
||||
audio_files: number;
|
||||
};
|
||||
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: {
|
||||
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;
|
||||
};
|
||||
Artist: {
|
||||
/** 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"][];
|
||||
};
|
||||
Session: {
|
||||
/** Format: uuid */
|
||||
id: string;
|
||||
@@ -540,6 +1010,8 @@ export interface components {
|
||||
};
|
||||
};
|
||||
parameters: {
|
||||
SourceId: string;
|
||||
EntityId: string;
|
||||
Limit: number;
|
||||
/** @description Непрозрачный курсор из `next_cursor` предыдущей страницы */
|
||||
Cursor: string;
|
||||
@@ -997,4 +1469,410 @@ export interface operations {
|
||||
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"];
|
||||
};
|
||||
};
|
||||
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"];
|
||||
};
|
||||
};
|
||||
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"];
|
||||
};
|
||||
};
|
||||
}
|
||||
Reference in new issue
Block a user