"""Admin sound management routes.""" from flask import Blueprint, jsonify, request from app.models.sound import Sound from app.services.sound_scanner_service import SoundScannerService from app.services.sound_normalizer_service import SoundNormalizerService from app.services.decorators import require_admin bp = Blueprint("admin_sounds", __name__, url_prefix="/api/admin/sounds") @bp.route("/scan", methods=["POST"]) @require_admin def scan_sounds(): """Manually trigger sound scanning.""" try: data = request.get_json() or {} directory = data.get("directory") result = SoundScannerService.scan_soundboard_directory(directory) if result["success"]: return jsonify(result), 200 else: return jsonify(result), 400 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("/scan/status", methods=["GET"]) @require_admin def get_scan_status(): """Get current scan statistics and status.""" try: stats = SoundScannerService.get_scan_statistics() return jsonify(stats), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("/normalize", methods=["POST"]) @require_admin def normalize_sounds(): """Normalize sounds (all or specific).""" try: data = request.get_json() or {} sound_id = data.get("sound_id") overwrite = data.get("overwrite", False) two_pass = data.get("two_pass", True) limit = data.get("limit") if sound_id: # Normalize specific sound result = SoundNormalizerService.normalize_sound( sound_id, overwrite, two_pass ) else: # Normalize all sounds result = SoundNormalizerService.normalize_all_sounds( overwrite, limit, two_pass ) if result["success"]: return jsonify(result), 200 else: return jsonify(result), 400 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("/normalize/status", methods=["GET"]) @require_admin def get_normalization_status(): """Get normalization statistics and status.""" try: status = SoundNormalizerService.get_normalization_status() return jsonify(status), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("/ffmpeg/check", methods=["GET"]) @require_admin def check_ffmpeg(): """Check ffmpeg availability and capabilities.""" try: ffmpeg_status = SoundNormalizerService.check_ffmpeg_availability() return jsonify(ffmpeg_status), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("/list", methods=["GET"]) @require_admin def list_sounds(): """Get detailed list of all sounds with normalization status.""" try: sound_type = request.args.get("type", "SDB") page = int(request.args.get("page", 1)) per_page = int(request.args.get("per_page", 50)) # Validate sound type if sound_type not in ["SDB", "SAY", "STR"]: return jsonify({"error": "Invalid sound type"}), 400 # Get paginated results sounds_query = Sound.query.filter_by(type=sound_type) total = sounds_query.count() sounds = ( sounds_query.offset((page - 1) * per_page).limit(per_page).all() ) # Convert to detailed dict format sounds_data = [] for sound in sounds: sound_dict = sound.to_dict() # Add file existence status import os from pathlib import Path original_path = os.path.join( "sounds", sound.type.lower(), sound.filename ) sound_dict["original_exists"] = os.path.exists(original_path) if sound.is_normalized and sound.normalized_filename: normalized_path = os.path.join( "sounds", "normalized", sound.type.lower(), sound.normalized_filename, ) sound_dict["normalized_exists"] = os.path.exists( normalized_path ) else: sound_dict["normalized_exists"] = False sounds_data.append(sound_dict) return jsonify( { "sounds": sounds_data, "pagination": { "page": page, "per_page": per_page, "total": total, "pages": (total + per_page - 1) // per_page, }, "type": sound_type, } ), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("/", methods=["DELETE"]) @require_admin def delete_sound(sound_id: int): """Delete a sound and its files.""" try: sound = Sound.query.get(sound_id) if not sound: return jsonify({"error": "Sound not found"}), 404 if not sound.is_deletable: return jsonify({"error": "Sound is not deletable"}), 403 # Delete normalized file if exists if sound.is_normalized and sound.normalized_filename: import os normalized_path = os.path.join( "sounds", "normalized", sound.type.lower(), sound.normalized_filename, ) if os.path.exists(normalized_path): try: os.remove(normalized_path) except Exception as e: return jsonify( {"error": f"Failed to delete normalized file: {e}"} ), 500 # Delete original file import os original_path = os.path.join( "sounds", sound.type.lower(), sound.filename ) if os.path.exists(original_path): try: os.remove(original_path) except Exception as e: return jsonify( {"error": f"Failed to delete original file: {e}"} ), 500 # Delete database record from app.database import db db.session.delete(sound) db.session.commit() return jsonify( { "message": f"Sound '{sound.name}' deleted successfully", "sound_id": sound_id, } ), 200 except Exception as e: return jsonify({"error": str(e)}), 500 @bp.route("//normalize", methods=["POST"]) @require_admin def normalize_single_sound(sound_id: int): """Normalize a specific sound.""" try: data = request.get_json() or {} overwrite = data.get("overwrite", False) two_pass = data.get("two_pass", True) result = SoundNormalizerService.normalize_sound( sound_id, overwrite, two_pass ) if result["success"]: return jsonify(result), 200 else: return jsonify(result), 400 except Exception as e: return jsonify({"error": str(e)}), 500