major server manager overhaul
This commit is contained in:
@@ -1,19 +1,30 @@
|
||||
from fastapi import APIRouter, Depends, BackgroundTasks
|
||||
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 DeleteFilesRequest(BaseModel):
|
||||
filepaths: List[str]
|
||||
class ScanConfig(BaseModel):
|
||||
paths: List[str] = ["/videos"]
|
||||
algorithm: str = "phash"
|
||||
scan_type: str = "fast" # fast or scene
|
||||
|
||||
def run_scan_videos_background():
|
||||
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)
|
||||
@@ -24,42 +35,72 @@ def run_scan_videos_background():
|
||||
app_settings.samba_password,
|
||||
)
|
||||
try:
|
||||
manager.scan_videos(samba_manager)
|
||||
manager.scan_videos(samba_manager, paths, algorithm, scan_type)
|
||||
finally:
|
||||
samba_manager.close()
|
||||
db.close()
|
||||
|
||||
@router.post("/scan")
|
||||
def scan_videos(background_tasks: BackgroundTasks):
|
||||
background_tasks.add_task(run_scan_videos_background)
|
||||
return {"message": "Video scan started in the background."}
|
||||
@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/pause")
|
||||
def pause_scan():
|
||||
with open("logs/duplicates_scan.pause", 'w') as f:
|
||||
pass
|
||||
return {"message": "Video scan paused."}
|
||||
@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.post("/scan/resume")
|
||||
def resume_scan():
|
||||
if os.path.exists("logs/duplicates_scan.pause"):
|
||||
os.remove("logs/duplicates_scan.pause")
|
||||
return {"message": "Video scan resumed."}
|
||||
@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/status")
|
||||
def get_scan_status():
|
||||
if os.path.exists("logs/duplicates_scan.pause"):
|
||||
return {"status": "Paused"}
|
||||
if os.path.exists("logs/duplicates_scan.progress") or os.path.exists("logs/duplicates_scan.state"):
|
||||
return {"status": "Scanning"}
|
||||
return {"status": "Idle"}
|
||||
@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, db: Session = Depends(get_db)):
|
||||
def find_duplicates(threshold: float = 0.95, method: str = "fast", db: Session = Depends(get_db)):
|
||||
manager = DuplicatesManager(settings, db)
|
||||
result = manager.find_duplicates(threshold)
|
||||
return result
|
||||
return manager.find_duplicates(threshold, method)
|
||||
|
||||
@router.get("/reports")
|
||||
def get_reports(db: Session = Depends(get_db)):
|
||||
@@ -69,9 +110,24 @@ def get_reports(db: Session = Depends(get_db)):
|
||||
@router.get("/report/{report_id}")
|
||||
def get_report(report_id: int, db: Session = Depends(get_db)):
|
||||
manager = DuplicatesManager(settings, db)
|
||||
return manager.get_duplicate_report(report_id)
|
||||
res = manager.get_report(report_id)
|
||||
if not res: raise HTTPException(status_code=404)
|
||||
return res
|
||||
|
||||
@router.delete("/files")
|
||||
def delete_files(request: DeleteFilesRequest, db: Session = Depends(get_db)):
|
||||
def delete_files(request: DeleteRequest, db: Session = Depends(get_db)):
|
||||
manager = DuplicatesManager(settings, db)
|
||||
return manager.delete_files(request.filepaths)
|
||||
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)
|
||||
|
||||
Reference in New Issue
Block a user