Spaces:
Sleeping
Sleeping
| from flask import Flask, render_template, request, jsonify, send_file | |
| from werkzeug.exceptions import HTTPException | |
| import os | |
| import subprocess | |
| import uuid | |
| app = Flask(__name__) | |
| app.config['UPLOAD_FOLDER'] = 'uploads' | |
| app.config['OUTPUT_FOLDER'] = 'outputs' | |
| app.config['MAX_CONTENT_LENGTH'] = 100 * 1024 * 1024 # 100MB limit to prevent server overload | |
| os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) | |
| os.makedirs(app.config['OUTPUT_FOLDER'], exist_ok=True) | |
| import shutil | |
| import time | |
| import traceback | |
| # Check if ffmpeg is installed | |
| FFMPEG_AVAILABLE = shutil.which('ffmpeg') is not None | |
| def cleanup_old_files(): | |
| """Cleanup files older than 1 hour""" | |
| try: | |
| now = time.time() | |
| for folder in [app.config['UPLOAD_FOLDER'], app.config['OUTPUT_FOLDER']]: | |
| if not os.path.exists(folder): | |
| continue | |
| for filename in os.listdir(folder): | |
| filepath = os.path.join(folder, filename) | |
| # Remove if older than 1 hour | |
| if os.path.isfile(filepath) and os.path.getmtime(filepath) < now - 3600: | |
| try: | |
| os.remove(filepath) | |
| except Exception: | |
| pass | |
| except Exception: | |
| pass | |
| def internal_error(error): | |
| return jsonify({ | |
| "error": "服务器内部错误 (Internal Server Error)", | |
| "details": str(error), | |
| "trace": traceback.format_exc(), | |
| "suggestion": "请尝试上传较小的文件,或检查文件格式是否正确。" | |
| }), 500 | |
| def request_entity_too_large(error): | |
| return jsonify({ | |
| "error": "文件过大 (File Too Large)", | |
| "details": "上传的文件超过了服务器限制 (100MB)。" | |
| }), 413 | |
| def handle_exception(e): | |
| # Pass through HTTP errors | |
| if isinstance(e, HTTPException): | |
| return e | |
| # Log the full traceback | |
| print("Error occurred:") | |
| traceback.print_exc() | |
| # Now you're handling non-HTTP exceptions only | |
| return jsonify({ | |
| "error": "Unexpected Error", | |
| "details": str(e), | |
| "trace": traceback.format_exc() # Return trace to client for debugging | |
| }), 500 | |
| def index(): | |
| return render_template('index.html', ffmpeg_available=FFMPEG_AVAILABLE) | |
| def convert(): | |
| cleanup_old_files() | |
| if 'video' not in request.files: | |
| return jsonify({"error": "No video file"}), 400 | |
| video = request.files['video'] | |
| filename = str(uuid.uuid4()) | |
| input_path = os.path.join(app.config['UPLOAD_FOLDER'], filename + '.webm') | |
| output_path = os.path.join(app.config['OUTPUT_FOLDER'], filename + '.mp4') | |
| try: | |
| video.save(input_path) | |
| if not FFMPEG_AVAILABLE: | |
| return jsonify({"error": "FFmpeg not installed on server", "fallback": True}), 503 | |
| # FFmpeg conversion | |
| # -vf "pad=ceil(iw/2)*2:ceil(ih/2)*2" ensures dimensions are even for libx264 | |
| # -pix_fmt yuv420p is often required for broad compatibility | |
| # Added -movflags +faststart for better web playback | |
| cmd = [ | |
| 'ffmpeg', '-y', '-i', input_path, | |
| '-c:v', 'libx264', '-preset', 'fast', '-crf', '23', | |
| '-pix_fmt', 'yuv420p', | |
| '-c:a', 'aac', '-b:a', '192k', | |
| '-vf', 'pad=ceil(iw/2)*2:ceil(ih/2)*2', | |
| '-movflags', '+faststart', | |
| output_path | |
| ] | |
| # Log command for debugging | |
| print(f"Running command: {' '.join(cmd)}") | |
| subprocess.run(cmd, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | |
| return jsonify({"url": f"/download/{filename}.mp4"}) | |
| except subprocess.CalledProcessError as e: | |
| print(f"FFmpeg Error: {e.stderr.decode() if e.stderr else str(e)}") | |
| return jsonify({"error": "Conversion failed", "details": str(e)}), 500 | |
| except Exception as e: | |
| print(f"General Error: {str(e)}") | |
| return jsonify({"error": "Internal server error", "details": str(e)}), 500 | |
| finally: | |
| # Cleanup input | |
| if os.path.exists(input_path): | |
| try: | |
| os.remove(input_path) | |
| except: | |
| pass | |
| def download_file(filename): | |
| return send_file(os.path.join(app.config['OUTPUT_FOLDER'], filename), as_attachment=True) | |
| if __name__ == '__main__': | |
| app.run(host='0.0.0.0', port=7860) | |