Files
personal_development/ServerManagerWebApp/backend/app/routers/duplicates.py
T
2026-01-09 19:24:41 +00:00

134 lines
4.4 KiB
Python

from fastapi import APIRouter, Depends, BackgroundTasks, HTTPException
from fastapi.responses import FileResponse
from sqlalchemy.orm import Session
from pydantic import BaseModel
from ..duplicates_manager import DuplicatesManager
from ..config import settings, Settings
from ..database import get_db, SessionLocal
from ..samba_manager import SambaManager
from .. import models
import os
import json
from typing import List
router = APIRouter()
class ScanConfig(BaseModel):
paths: List[str] = ["/videos"]
algorithm: str = "phash"
scan_type: str = "fast" # fast or scene
class DeleteRequest(BaseModel):
ids: List[int]
class ExclusionRequest(BaseModel):
path: str
def run_scan_videos_background(paths, algorithm, scan_type):
db = SessionLocal()
app_settings = Settings()
manager = DuplicatesManager(app_settings, db)
samba_manager = SambaManager(
app_settings.samba_server_ip,
"isolation",
app_settings.samba_username,
app_settings.samba_password,
)
try:
manager.scan_videos(samba_manager, paths, algorithm, scan_type)
finally:
samba_manager.close()
db.close()
@router.post("/scan/start")
def start_scan(config: ScanConfig, background_tasks: BackgroundTasks):
background_tasks.add_task(run_scan_videos_background, config.paths, config.algorithm, config.scan_type)
return {"message": "Scan started"}
@router.post("/scan/cancel")
def cancel_scan():
try:
os.makedirs("logs", exist_ok=True)
with open("logs/duplicates_scan.cancel", 'w') as f:
f.write("cancel")
except Exception as e:
raise HTTPException(status_code=500, detail=f"Failed to cancel scan: {e}")
return {"message": "Cancellation requested"}
@router.get("/scan/log")
def get_scan_log(limit: int = 100):
log_file = "logs/duplicates_scan.log"
if not os.path.exists(log_file):
return {"lines": []}
try:
# Simple read and tail (not efficient for huge files but fine here)
with open(log_file, "r", encoding="utf-8", errors="replace") as f:
lines = f.readlines()
return {"lines": lines[-limit:]}
except Exception as e:
return {"lines": [f"Error reading log: {e}"]}
@router.get("/scan/progress")
def get_scan_progress():
path = "logs/duplicates_scan.json"
if os.path.exists(path):
try:
with open(path, 'r') as f:
return json.load(f)
except:
return {"status": "error", "message": "Read failed"}
return {"status": "idle"}
@router.get("/exclusions")
def get_exclusions(db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
return manager.exclusions
@router.post("/exclusions")
def add_exclusion(req: ExclusionRequest, db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
manager.add_exclusion(req.path)
return {"message": "Added"}
@router.delete("/exclusions")
def remove_exclusion(req: ExclusionRequest, db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
manager.remove_exclusion(req.path)
return {"message": "Removed"}
@router.post("/find")
def find_duplicates(threshold: float = 0.95, method: str = "fast", db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
return manager.find_duplicates(threshold, method)
@router.get("/reports")
def get_reports(db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
return manager.get_reports()
@router.get("/report/{report_id}")
def get_report(report_id: int, db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
res = manager.get_report(report_id)
if not res: raise HTTPException(status_code=404)
return res
@router.delete("/files")
def delete_files(request: DeleteRequest, db: Session = Depends(get_db)):
manager = DuplicatesManager(settings, db)
deleted = manager.delete_files(request.ids)
return {"deleted_ids": deleted}
@router.get("/thumbnails/{video_id}")
def get_thumbnail(video_id: int, db: Session = Depends(get_db)):
video = db.query(models.VideoFile).get(video_id)
if not video or not video.contact_sheet_path:
raise HTTPException(status_code=404, detail="Thumbnail not found")
path = os.path.join("resources/cache/thumbnails", video.contact_sheet_path)
if not os.path.exists(path):
raise HTTPException(status_code=404, detail="Thumbnail file missing")
return FileResponse(path)