feat: add legacy key/data file migration to database
- Add migration_legacy_files_completed flag to SystemSettings model - Create legacy_file_migration service to migrate series from key/data files - Integrate legacy migration into initialization_service startup flow - Add integration tests for legacy file migration - Update DATABASE.md documentation with migration details - Fix various test and service issues (nfo_repair, tmdb_client, download_service) - Add test_database_schema unit tests
This commit is contained in:
@@ -7,6 +7,7 @@ import structlog
|
||||
|
||||
from src.config.settings import settings
|
||||
from src.server.services.anime_service import sync_series_from_data_files
|
||||
from src.server.services.legacy_file_migration import migrate_series_from_files_to_db
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
|
||||
@@ -99,6 +100,57 @@ async def _mark_initial_scan_completed() -> None:
|
||||
)
|
||||
|
||||
|
||||
async def _check_legacy_migration_status() -> bool:
|
||||
"""Check if legacy key/data file migration has been completed.
|
||||
|
||||
Returns:
|
||||
bool: True if migration was completed, False otherwise
|
||||
"""
|
||||
return await _check_scan_status(
|
||||
check_method=lambda svc, db: svc.is_migration_legacy_files_completed(db),
|
||||
scan_type="legacy_migration",
|
||||
log_completed_msg="Legacy file migration already completed, skipping",
|
||||
log_not_completed_msg="Legacy file migration not yet run, will check for files"
|
||||
)
|
||||
|
||||
|
||||
async def _mark_legacy_migration_completed() -> None:
|
||||
"""Mark the legacy file migration as completed in system settings."""
|
||||
await _mark_scan_completed(
|
||||
mark_method=lambda svc, db: svc.mark_migration_legacy_files_completed(db),
|
||||
scan_type="legacy_migration"
|
||||
)
|
||||
|
||||
|
||||
async def _migrate_legacy_files() -> int:
|
||||
"""Migrate series from legacy key/data files to database.
|
||||
|
||||
Returns:
|
||||
int: Number of series migrated
|
||||
"""
|
||||
from src.server.database.connection import get_db_session
|
||||
|
||||
logger.info("Checking for legacy key/data files to migrate...")
|
||||
|
||||
try:
|
||||
async with get_db_session() as db:
|
||||
migrated_count = await migrate_series_from_files_to_db(
|
||||
settings.anime_directory,
|
||||
db
|
||||
)
|
||||
|
||||
if migrated_count > 0:
|
||||
logger.info("Migrated %d series from legacy files", migrated_count)
|
||||
else:
|
||||
logger.info("No series found in legacy files to migrate")
|
||||
|
||||
return migrated_count
|
||||
|
||||
except Exception as e:
|
||||
logger.warning("Failed to migrate legacy files: %s", e)
|
||||
return 0
|
||||
|
||||
|
||||
async def _sync_anime_folders(progress_service=None) -> int:
|
||||
"""Scan anime folders and sync series to database.
|
||||
|
||||
@@ -181,18 +233,19 @@ async def _validate_anime_directory(progress_service=None) -> bool:
|
||||
|
||||
async def perform_initial_setup(progress_service=None):
|
||||
"""Perform initial setup including series sync and scan completion marking.
|
||||
|
||||
|
||||
This function is called both during application lifespan startup
|
||||
and when the setup endpoint is completed. It ensures that:
|
||||
1. Series are synced from data files to database
|
||||
2. Initial scan is marked as completed
|
||||
3. Series are loaded into memory
|
||||
4. NFO scan is performed if configured
|
||||
5. Media scan is performed
|
||||
|
||||
1. Legacy key/data files are migrated to database (one-time)
|
||||
2. Series are synced from data files to database
|
||||
3. Initial scan is marked as completed
|
||||
4. Series are loaded into memory
|
||||
5. NFO scan is performed if configured
|
||||
6. Media scan is performed
|
||||
|
||||
Args:
|
||||
progress_service: Optional ProgressService for emitting updates
|
||||
|
||||
|
||||
Returns:
|
||||
bool: True if initialization was performed, False if skipped
|
||||
"""
|
||||
@@ -225,17 +278,23 @@ async def perform_initial_setup(progress_service=None):
|
||||
|
||||
# Perform the actual initialization
|
||||
try:
|
||||
# First, run legacy file migration if needed (independent of initial scan)
|
||||
is_legacy_migration_done = await _check_legacy_migration_status()
|
||||
if not is_legacy_migration_done:
|
||||
await _migrate_legacy_files()
|
||||
await _mark_legacy_migration_completed()
|
||||
|
||||
# Sync series from anime folders to database
|
||||
await _sync_anime_folders(progress_service)
|
||||
|
||||
|
||||
# Mark the initial scan as completed
|
||||
await _mark_initial_scan_completed()
|
||||
|
||||
|
||||
# Load series into memory from database
|
||||
await _load_series_into_memory(progress_service)
|
||||
|
||||
|
||||
return True
|
||||
|
||||
|
||||
except (OSError, RuntimeError, ValueError) as e:
|
||||
logger.warning("Failed to perform initial setup: %s", e)
|
||||
return False
|
||||
|
||||
Reference in New Issue
Block a user