feat: storage writes via storage-agent, accepts_uploads and write_template (M5.5)
ci / api / api (push) Successful in 33s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 43s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m11s
ci / ts / ts (packages + web) (push) Successful in 1m10s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 51s
ci / api / api (push) Successful in 33s
ci / contract / contract (сгенерированный код совпадает с openapi.yaml) (push) Successful in 43s
ci / mobile / mobile (Metro-бандл Android) (push) Successful in 1m11s
ci / ts / ts (packages + web) (push) Successful in 1m10s
ci / docker / docker (образы собираются — их сервер собирает сам при обновлении) (push) Successful in 51s
- storage-agent: POST /internal/files copies a staged file into a source
(temp file, fsync, SHA-256 check, hard link so nothing is overwritten,
" (2)" suffix on conflict, owner PIPU_FILE_UID/GID) and
POST /internal/files/test. NFS sources that accept uploads are mounted
rw in an agent-only /library-rw and bind-mounted read-only for others;
local sources are written through /library-host-rw.
- meta: write templates ({track:02}, {disc:1-}, [optional]) with name
sanitising and length limits, suggestion from the source's regexes
and a reversibility check against 50 catalogue tracks.
- API and admin UI: accepts_uploads / write_template on sources,
write-template suggest and check endpoints, write test result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
9b50038bb4
commit
f66be2ba0a
27 files changed
+2422
-213
No files matched your search
+121
-1
@@ -532,6 +532,48 @@ paths:
|
||||
$ref: "#/components/schemas/PatternPreview"
|
||||
default:
|
||||
$ref: "#/components/responses/Problem"
|
||||
/api/v1/admin/sources/{id}/write-template/suggest:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/SourceId"
|
||||
post:
|
||||
operationId: suggestWriteTemplate
|
||||
tags: [library]
|
||||
summary: Подобрать шаблон пути по существующей структуре (admin)
|
||||
description: |
|
||||
Выражение хранилища, совпавшее с наибольшим числом путей выборки, превращается в шаблон.
|
||||
Не удалось (нет файлов или выражения не переводятся) — `422 library.template_unavailable`.
|
||||
responses:
|
||||
"200":
|
||||
description: Предложенный шаблон
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WriteTemplateSuggestion"
|
||||
default:
|
||||
$ref: "#/components/responses/Problem"
|
||||
/api/v1/admin/sources/{id}/write-template/check:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/SourceId"
|
||||
post:
|
||||
operationId: checkWriteTemplate
|
||||
tags: [library]
|
||||
summary: Проверить шаблон на обратимость (admin)
|
||||
description: Шаблон применяется к 50 трекам хранилища, пути разбираются его выражениями обратно.
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WriteTemplateCheckRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Итог проверки
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WriteTemplateCheck"
|
||||
default:
|
||||
$ref: "#/components/responses/Problem"
|
||||
/api/v1/admin/sources/{id}/scan:
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/SourceId"
|
||||
@@ -1453,7 +1495,7 @@ components:
|
||||
enum: [tags_first, path_first]
|
||||
Source:
|
||||
type: object
|
||||
required: [id, name, type, nfs_server, nfs_export, nfs_options, local_path, tag_priority, scan_interval_minutes, status, status_message, last_scan_at, created_at, scan]
|
||||
required: [id, name, type, nfs_server, nfs_export, nfs_options, local_path, tag_priority, scan_interval_minutes, accepts_uploads, write_template, status, status_message, last_scan_at, created_at, scan]
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
@@ -1480,6 +1522,13 @@ components:
|
||||
type: integer
|
||||
nullable: true
|
||||
description: Автоматический скан, null — только вручную
|
||||
accepts_uploads:
|
||||
type: boolean
|
||||
description: Принимает импорт из очереди на добавление (NFS монтируется агентом ещё и на запись)
|
||||
write_template:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Шаблон пути новых файлов (docs/uploads.md#7), null — не задан
|
||||
status:
|
||||
$ref: "#/components/schemas/SourceStatus"
|
||||
status_message:
|
||||
@@ -1527,6 +1576,11 @@ components:
|
||||
type: integer
|
||||
minimum: 5
|
||||
nullable: true
|
||||
accepts_uploads:
|
||||
type: boolean
|
||||
write_template:
|
||||
type: string
|
||||
maxLength: 500
|
||||
SourcePatch:
|
||||
type: object
|
||||
properties:
|
||||
@@ -1549,6 +1603,15 @@ components:
|
||||
enabled:
|
||||
type: boolean
|
||||
description: false — отключить хранилище (треки становятся недоступны), true — подключить снова
|
||||
accepts_uploads:
|
||||
type: boolean
|
||||
description: Смена переподключает NFS-хранилище (rw-точка агента)
|
||||
write_template:
|
||||
type: string
|
||||
maxLength: 500
|
||||
description: |
|
||||
Шаблон пути новых файлов; пусто — убрать. Неверный синтаксис — `422 validation.template_invalid`
|
||||
с `params.reason`. Проверка обратимости не обязательна для сохранения — её показывает `write-template/check`.
|
||||
SourceTestResult:
|
||||
type: object
|
||||
required: [ok, message, audio_files]
|
||||
@@ -1560,6 +1623,63 @@ components:
|
||||
audio_files:
|
||||
type: integer
|
||||
description: Сколько аудиофайлов найдено (проверка останавливается на 1000)
|
||||
write_ok:
|
||||
type: boolean
|
||||
nullable: true
|
||||
description: Удалось создать и удалить `.pipu-write-test` (только для accepts_uploads; иначе null)
|
||||
write_message:
|
||||
type: string
|
||||
nullable: true
|
||||
WriteTemplateSuggestion:
|
||||
type: object
|
||||
required: [template]
|
||||
properties:
|
||||
template:
|
||||
type: string
|
||||
WriteTemplateCheckRequest:
|
||||
type: object
|
||||
required: [template]
|
||||
properties:
|
||||
template:
|
||||
type: string
|
||||
maxLength: 500
|
||||
WriteTemplateMismatch:
|
||||
type: object
|
||||
required: [rel_path, rendered, fields, error]
|
||||
properties:
|
||||
rel_path:
|
||||
type: string
|
||||
description: Реальный путь файла
|
||||
rendered:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Путь по шаблону, null — не построился
|
||||
fields:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Поля, которые регэкспы хранилища распознали не так; `pattern` — не совпало ни одно выражение
|
||||
error:
|
||||
type: string
|
||||
nullable: true
|
||||
WriteTemplateCheck:
|
||||
type: object
|
||||
required: [ok, total, round_trip, same_path, mismatches]
|
||||
properties:
|
||||
ok:
|
||||
type: boolean
|
||||
description: Все пути разобраны обратно без изменений и ≥ 90% совпали с реальными
|
||||
total:
|
||||
type: integer
|
||||
round_trip:
|
||||
type: integer
|
||||
same_path:
|
||||
type: integer
|
||||
mismatches:
|
||||
type: array
|
||||
maxItems: 10
|
||||
items:
|
||||
$ref: "#/components/schemas/WriteTemplateMismatch"
|
||||
PathPattern:
|
||||
type: object
|
||||
required: [regex, is_enabled]
|
||||
|
||||
Reference in new issue
Block a user