initial commit
Some checks failed
Build Images and Deploy / Update-PROD-Stack (push) Failing after 1m2s
Some checks failed
Build Images and Deploy / Update-PROD-Stack (push) Failing after 1m2s
This commit is contained in:
201
app.py
Normal file
201
app.py
Normal file
@@ -0,0 +1,201 @@
|
||||
import os
|
||||
import subprocess
|
||||
import uuid
|
||||
from flask import Flask, render_template, request, send_file, jsonify
|
||||
from werkzeug.utils import secure_filename
|
||||
import json
|
||||
|
||||
app = Flask(__name__)
|
||||
app.config['UPLOAD_FOLDER'] = 'uploads'
|
||||
app.config['OUTPUT_FOLDER'] = 'outputs'
|
||||
app.config['MAX_CONTENT_LENGTH'] = 500 * 1024 * 1024 # 500MB max file size
|
||||
|
||||
# Create necessary folders
|
||||
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
|
||||
os.makedirs(app.config['OUTPUT_FOLDER'], exist_ok=True)
|
||||
|
||||
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'mkv', 'wmv', 'flv', 'webm'}
|
||||
|
||||
def allowed_file(filename):
|
||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
||||
|
||||
def get_video_info(video_path):
|
||||
"""Get video information using ffprobe"""
|
||||
try:
|
||||
cmd = [
|
||||
'ffprobe',
|
||||
'-v', 'quiet',
|
||||
'-print_format', 'json',
|
||||
'-show_format',
|
||||
'-show_streams',
|
||||
video_path
|
||||
]
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
info = json.loads(result.stdout)
|
||||
|
||||
# Extract video stream info
|
||||
video_stream = next((s for s in info['streams'] if s['codec_type'] == 'video'), None)
|
||||
if video_stream:
|
||||
return {
|
||||
'width': video_stream.get('width'),
|
||||
'height': video_stream.get('height'),
|
||||
'duration': float(info['format'].get('duration', 0)),
|
||||
'codec': video_stream.get('codec_name')
|
||||
}
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"Error getting video info: {e}")
|
||||
return None
|
||||
|
||||
@app.route('/')
|
||||
def index():
|
||||
return render_template('index.html')
|
||||
|
||||
@app.route('/upload', methods=['POST'])
|
||||
def upload_video():
|
||||
if 'video' not in request.files:
|
||||
return jsonify({'error': 'No video file provided'}), 400
|
||||
|
||||
file = request.files['video']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'No file selected'}), 400
|
||||
|
||||
if file and allowed_file(file.filename):
|
||||
# Generate unique filename
|
||||
file_id = str(uuid.uuid4())
|
||||
ext = file.filename.rsplit('.', 1)[1].lower()
|
||||
filename = f"{file_id}.{ext}"
|
||||
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
||||
file.save(filepath)
|
||||
|
||||
# Get video information
|
||||
video_info = get_video_info(filepath)
|
||||
|
||||
return jsonify({
|
||||
'file_id': file_id,
|
||||
'filename': filename,
|
||||
'original_name': file.filename,
|
||||
'info': video_info
|
||||
})
|
||||
|
||||
return jsonify({'error': 'Invalid file type'}), 400
|
||||
|
||||
@app.route('/process', methods=['POST'])
|
||||
def process_video():
|
||||
try:
|
||||
data = request.get_json()
|
||||
file_id = data.get('file_id')
|
||||
|
||||
if not file_id:
|
||||
return jsonify({'error': 'No file ID provided'}), 400
|
||||
|
||||
# Find the uploaded file
|
||||
uploaded_files = [f for f in os.listdir(app.config['UPLOAD_FOLDER']) if f.startswith(file_id)]
|
||||
if not uploaded_files:
|
||||
return jsonify({'error': 'File not found'}), 404
|
||||
|
||||
input_path = os.path.join(app.config['UPLOAD_FOLDER'], uploaded_files[0])
|
||||
output_filename = f"{file_id}_processed.mp4"
|
||||
output_path = os.path.join(app.config['OUTPUT_FOLDER'], output_filename)
|
||||
|
||||
# Build ffmpeg command
|
||||
cmd = ['ffmpeg', '-i', input_path]
|
||||
|
||||
# Add trim parameters if specified
|
||||
start_time = data.get('start_time')
|
||||
end_time = data.get('end_time')
|
||||
if start_time is not None and start_time > 0:
|
||||
cmd.extend(['-ss', str(start_time)])
|
||||
if end_time is not None:
|
||||
duration = end_time - (start_time if start_time else 0)
|
||||
if duration > 0:
|
||||
cmd.extend(['-t', str(duration)])
|
||||
|
||||
# Build filter complex for crop and scale
|
||||
filters = []
|
||||
|
||||
# Add crop filter if specified
|
||||
crop = data.get('crop')
|
||||
if crop:
|
||||
x = crop.get('x', 0)
|
||||
y = crop.get('y', 0)
|
||||
width = crop.get('width')
|
||||
height = crop.get('height')
|
||||
if width and height:
|
||||
filters.append(f"crop={width}:{height}:{x}:{y}")
|
||||
|
||||
# Add scale filter if resolution specified
|
||||
resolution = data.get('resolution')
|
||||
if resolution:
|
||||
width = resolution.get('width')
|
||||
height = resolution.get('height')
|
||||
if width and height:
|
||||
filters.append(f"scale={width}:{height}")
|
||||
|
||||
# Apply filters if any
|
||||
if filters:
|
||||
cmd.extend(['-vf', ','.join(filters)])
|
||||
|
||||
# Output settings for H.264 MP4
|
||||
cmd.extend([
|
||||
'-c:v', 'libx264',
|
||||
'-preset', 'medium',
|
||||
'-crf', '23',
|
||||
'-c:a', 'aac',
|
||||
'-b:a', '128k',
|
||||
'-movflags', '+faststart',
|
||||
'-y', # Overwrite output file
|
||||
output_path
|
||||
])
|
||||
|
||||
# Execute ffmpeg
|
||||
print(f"Executing: {' '.join(cmd)}")
|
||||
result = subprocess.run(cmd, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"FFmpeg error: {result.stderr}")
|
||||
return jsonify({'error': 'Video processing failed', 'details': result.stderr}), 500
|
||||
|
||||
return jsonify({
|
||||
'success': True,
|
||||
'output_file': output_filename,
|
||||
'file_id': file_id
|
||||
})
|
||||
|
||||
except Exception as e:
|
||||
print(f"Processing error: {e}")
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/download/<file_id>')
|
||||
def download_video(file_id):
|
||||
try:
|
||||
output_filename = f"{file_id}_processed.mp4"
|
||||
output_path = os.path.join(app.config['OUTPUT_FOLDER'], output_filename)
|
||||
|
||||
if not os.path.exists(output_path):
|
||||
return jsonify({'error': 'File not found'}), 404
|
||||
|
||||
return send_file(output_path, as_attachment=True, download_name='processed_video.mp4')
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
@app.route('/cleanup/<file_id>', methods=['DELETE'])
|
||||
def cleanup_files(file_id):
|
||||
"""Clean up uploaded and processed files"""
|
||||
try:
|
||||
# Clean up upload folder
|
||||
for f in os.listdir(app.config['UPLOAD_FOLDER']):
|
||||
if f.startswith(file_id):
|
||||
os.remove(os.path.join(app.config['UPLOAD_FOLDER'], f))
|
||||
|
||||
# Clean up output folder
|
||||
for f in os.listdir(app.config['OUTPUT_FOLDER']):
|
||||
if f.startswith(file_id):
|
||||
os.remove(os.path.join(app.config['OUTPUT_FOLDER'], f))
|
||||
|
||||
return jsonify({'success': True})
|
||||
except Exception as e:
|
||||
return jsonify({'error': str(e)}), 500
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(host='0.0.0.0', port=5000, debug=True)
|
||||
Reference in New Issue
Block a user