Files
you-music/backend/app/api/settings.py
T
2025-10-30 22:35:02 +11:00

133 lines
5.2 KiB
Python

from fastapi import APIRouter, Depends, BackgroundTasks
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from datetime import datetime
from typing import Optional
import logging
from app.db.session import get_db
from app.schemas.schemas import SettingsResponse, SettingsUpdate, ScanStatus
from app.models.models import AppSettings
from app.core.config import settings as app_settings
from app.services.scanner import full_scan, get_scan_status
from app.services.scheduler import update_scan_interval, enable_auto_scan
logger = logging.getLogger(__name__)
router = APIRouter()
async def get_setting(db: AsyncSession, key: str) -> Optional[str]:
"""Get a setting value from database"""
result = await db.execute(select(AppSettings).where(AppSettings.key == key))
setting = result.scalar_one_or_none()
return setting.value if setting else None
async def set_setting(db: AsyncSession, key: str, value: str):
"""Set a setting value in database"""
result = await db.execute(select(AppSettings).where(AppSettings.key == key))
setting = result.scalar_one_or_none()
if setting:
setting.value = value
setting.updated_at = datetime.utcnow()
else:
setting = AppSettings(key=key, value=value)
db.add(setting)
await db.commit()
@router.get("/", response_model=SettingsResponse)
async def get_settings(db: AsyncSession = Depends(get_db)):
"""Get current application settings"""
# Get settings from database or use defaults
local_music_dir = await get_setting(db, "local_music_dir")
scan_interval = await get_setting(db, "scan_interval")
delete_missing = await get_setting(db, "delete_missing_files")
auto_scan = await get_setting(db, "auto_scan_enabled")
last_scan = await get_setting(db, "last_scan_at")
return SettingsResponse(
local_music_dir=local_music_dir or app_settings.LOCAL_MUSIC_DIR,
scan_interval=int(scan_interval) if scan_interval else app_settings.SCAN_INTERVAL,
delete_missing_files=delete_missing.lower() == "true" if delete_missing else app_settings.DELETE_MISSING_FILES,
auto_scan_enabled=auto_scan.lower() == "true" if auto_scan else app_settings.AUTO_SCAN_ENABLED,
last_scan_at=datetime.fromisoformat(last_scan) if last_scan else None
)
@router.put("/", response_model=SettingsResponse)
async def update_settings(
settings_update: SettingsUpdate,
db: AsyncSession = Depends(get_db)
):
"""Update application settings"""
# Update each setting if provided
if settings_update.local_music_dir is not None:
await set_setting(db, "local_music_dir", settings_update.local_music_dir)
app_settings.LOCAL_MUSIC_DIR = settings_update.local_music_dir
logger.info(f"Updated LOCAL_MUSIC_DIR to: {settings_update.local_music_dir}")
if settings_update.scan_interval is not None:
await set_setting(db, "scan_interval", str(settings_update.scan_interval))
app_settings.SCAN_INTERVAL = settings_update.scan_interval
update_scan_interval(settings_update.scan_interval)
logger.info(f"Updated scan_interval to: {settings_update.scan_interval}")
if settings_update.delete_missing_files is not None:
await set_setting(db, "delete_missing_files", str(settings_update.delete_missing_files))
app_settings.DELETE_MISSING_FILES = settings_update.delete_missing_files
logger.info(f"Updated delete_missing_files to: {settings_update.delete_missing_files}")
if settings_update.auto_scan_enabled is not None:
await set_setting(db, "auto_scan_enabled", str(settings_update.auto_scan_enabled))
app_settings.AUTO_SCAN_ENABLED = settings_update.auto_scan_enabled
# Update scheduler
interval = settings_update.scan_interval or app_settings.SCAN_INTERVAL
enable_auto_scan(settings_update.auto_scan_enabled, interval)
logger.info(f"Updated auto_scan_enabled to: {settings_update.auto_scan_enabled}")
# Return updated settings
return await get_settings(db)
@router.post("/scan")
async def trigger_manual_scan(
background_tasks: BackgroundTasks,
db: AsyncSession = Depends(get_db)
):
"""Trigger a manual music library scan"""
# Get delete_missing setting
delete_missing = await get_setting(db, "delete_missing_files")
delete = delete_missing.lower() == "true" if delete_missing else app_settings.DELETE_MISSING_FILES
# Run scan in background
background_tasks.add_task(full_scan, db, delete)
logger.info("Manual scan triggered")
return {"message": "Scan started", "status": "processing"}
@router.get("/scan-status", response_model=ScanStatus)
async def get_scan_status_endpoint():
"""Get current scan status"""
status = get_scan_status()
return ScanStatus(
is_scanning=status["is_scanning"],
progress=status["progress"],
total=status["total"],
current_file=status["current_file"],
started_at=status["started_at"],
completed_at=status["completed_at"],
files_added=status["files_added"],
files_updated=status["files_updated"],
files_missing=status["files_missing"],
errors=status["errors"]
)