feat(storage): S3-compatible storage adapter + storage_uri rename

Add S3FileStorage adapter (any S3-compatible backend: AWS, MinIO, Garage)
alongside the local adapter, selected via STORAGE_BACKEND. Proxied range
streaming via get_object+Range; as_local_path downloads to a tempfile for
ffmpeg/fpcalc. Rename track.file_path -> storage_uri across domain entity,
ORM, repositories, port, and services, with an Alembic migration. Adds
mocked S3 unit tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Senko-san
2026-06-08 17:11:35 +03:00
parent a8348e145a
commit 5c5df5d3cc
15 changed files with 1377 additions and 498 deletions
+2 -2
View File
@@ -73,7 +73,7 @@ class StreamingService:
if track is None:
raise NotFoundError("Track not found.")
stat = await self._storage.stat(track.file_path)
stat = await self._storage.stat(track.storage_uri)
total_size = stat.size
content_type = stat.content_type or _FORMAT_CONTENT_TYPE.get(
track.file_format.lower(), "application/octet-stream"
@@ -81,7 +81,7 @@ class StreamingService:
start, end, is_partial = _parse_range(range_header, total_size)
stream, _ = await self._storage.open_range(track.file_path, start, end)
stream, _ = await self._storage.open_range(track.storage_uri, start, end)
actual_end = end if end is not None else total_size - 1
content_length = actual_end - start + 1
+1 -1
View File
@@ -92,7 +92,7 @@ class UploadService:
id=track_id,
title=title,
artist_id=artist.id,
file_path=key,
storage_uri=key,
file_format=ext,
file_size=file_size,
source="upload",