fix: store media paths relative to data dir

This commit is contained in:
James Pine
2026-03-20 15:06:07 -07:00
parent e6f419cd70
commit b108bb1cb1
13 changed files with 130 additions and 86 deletions
+11 -27
View File
@@ -34,7 +34,7 @@ def run_migrations(engine) -> None:
_migrate_generations(engine, inspector, tables)
_migrate_effect_presets(engine, inspector, tables)
_migrate_generation_versions(engine, inspector, tables)
_resolve_relative_paths(engine, tables)
_normalize_storage_paths(engine, tables)
# -- helpers ---------------------------------------------------------------
@@ -182,24 +182,11 @@ def _migrate_generation_versions(engine, inspector, tables: set[str]) -> None:
_add_column(engine, "generation_versions", "source_version_id VARCHAR", "source_version_id")
def _resolve_relative_paths(engine, tables: set[str]) -> None:
"""Resolve any relative file paths in the database to absolute paths.
Earlier versions stored paths relative to CWD (e.g. "data/generations/abc.wav").
These break when the production binary's CWD differs from the data directory.
This migration converts them to absolute paths using the configured data dir.
Idempotent: absolute paths are left untouched.
Strategy: paths like "data/generations/abc.wav" are rebased onto the
configured data directory. If the path starts with "data/", strip that
prefix and prepend get_data_dir(). Otherwise, join the relative path
directly under get_data_dir().
directly under get_data_dir(). If the rebased path still does not exist,
fall back to resolving relative to CWD.
"""
def _normalize_storage_paths(engine, tables: set[str]) -> None:
"""Normalize stored file paths to be relative to the configured data dir."""
from pathlib import Path
from ..config import get_data_dir
from ..config import get_data_dir, to_storage_path, resolve_storage_path
data_dir = get_data_dir()
@@ -222,21 +209,18 @@ def _resolve_relative_paths(engine, tables: set[str]) -> None:
if not path_val:
continue
p = Path(path_val)
if p.is_absolute():
resolved = resolve_storage_path(p)
if resolved is None:
continue
parts = p.parts
if parts and parts[0] == "data":
rebased = (data_dir / Path(*parts[1:])).resolve()
else:
rebased = (data_dir / p).resolve()
resolved = rebased if rebased.exists() else p.resolve()
if resolved.exists():
normalized = to_storage_path(resolved)
if normalized != path_val:
conn.execute(
text(f"UPDATE {table} SET {column} = :path WHERE id = :id"),
{"path": str(resolved), "id": row_id},
{"path": normalized, "id": row_id},
)
total_fixed += 1
if total_fixed > 0:
conn.commit()
logger.info("Resolved %d relative file paths to absolute", total_fixed)
logger.info("Normalized %d stored file paths", total_fixed)
+4 -2
View File
@@ -3,7 +3,8 @@
import json
import logging
import uuid
from pathlib import Path
from .. import config
logger = logging.getLogger(__name__)
@@ -25,7 +26,8 @@ def backfill_generation_versions(SessionLocal, Generation, GenerationVersion) ->
for gen in generations:
if gen.id in existing_version_gen_ids:
continue
if not Path(gen.audio_path).exists():
resolved_audio_path = config.resolve_storage_path(gen.audio_path)
if resolved_audio_path is None or not resolved_audio_path.exists():
continue
version = GenerationVersion(
id=str(uuid.uuid4()),