Spaces:
Sleeping
Sleeping
Commit
·
75d8495
1
Parent(s):
db7598d
cleanup
Browse files- app/__init__.py +0 -1
- app/error_handlers.py +0 -41
- app/proxy.py +0 -76
- app/templates/index.html +1 -1
- create_favicon.py +0 -27
app/__init__.py
CHANGED
|
@@ -1,6 +1,5 @@
|
|
| 1 |
from flask import Flask
|
| 2 |
from app.routes import main_bp, api_bp
|
| 3 |
-
from app.proxy import proxy_bp
|
| 4 |
import os
|
| 5 |
|
| 6 |
def create_app():
|
|
|
|
| 1 |
from flask import Flask
|
| 2 |
from app.routes import main_bp, api_bp
|
|
|
|
| 3 |
import os
|
| 4 |
|
| 5 |
def create_app():
|
app/error_handlers.py
DELETED
|
@@ -1,41 +0,0 @@
|
|
| 1 |
-
from flask import jsonify
|
| 2 |
-
from werkzeug.exceptions import HTTPException
|
| 3 |
-
import logging
|
| 4 |
-
|
| 5 |
-
def register_error_handlers(app):
|
| 6 |
-
# Set up logging
|
| 7 |
-
logging.basicConfig(level=logging.INFO)
|
| 8 |
-
logger = logging.getLogger(__name__)
|
| 9 |
-
|
| 10 |
-
@app.errorhandler(HTTPException)
|
| 11 |
-
def handle_http_error(error):
|
| 12 |
-
"""Handle all HTTP exceptions."""
|
| 13 |
-
response = {
|
| 14 |
-
'error': True,
|
| 15 |
-
'message': error.description,
|
| 16 |
-
'status_code': error.code
|
| 17 |
-
}
|
| 18 |
-
logger.error(f'HTTP error occurred: {error.code} - {error.description}')
|
| 19 |
-
return jsonify(response), error.code
|
| 20 |
-
|
| 21 |
-
@app.errorhandler(Exception)
|
| 22 |
-
def handle_generic_error(error):
|
| 23 |
-
"""Handle all unhandled exceptions."""
|
| 24 |
-
response = {
|
| 25 |
-
'error': True,
|
| 26 |
-
'message': 'An unexpected error occurred',
|
| 27 |
-
'status_code': 500
|
| 28 |
-
}
|
| 29 |
-
logger.error(f'Unhandled error: {str(error)}', exc_info=True)
|
| 30 |
-
return jsonify(response), 500
|
| 31 |
-
|
| 32 |
-
@app.errorhandler(413)
|
| 33 |
-
def handle_file_too_large(error):
|
| 34 |
-
"""Handle file size exceeding MAX_CONTENT_LENGTH."""
|
| 35 |
-
response = {
|
| 36 |
-
'error': True,
|
| 37 |
-
'message': 'File is too large. Maximum size allowed is 1GB.',
|
| 38 |
-
'status_code': 413
|
| 39 |
-
}
|
| 40 |
-
logger.error('File upload exceeded size limit')
|
| 41 |
-
return jsonify(response), 413
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/proxy.py
DELETED
|
@@ -1,76 +0,0 @@
|
|
| 1 |
-
from flask import Blueprint, request, jsonify, current_app, render_template, send_from_directory
|
| 2 |
-
import os
|
| 3 |
-
import logging
|
| 4 |
-
|
| 5 |
-
logger = logging.getLogger(__name__)
|
| 6 |
-
proxy_bp = Blueprint('proxy', __name__)
|
| 7 |
-
|
| 8 |
-
from app.services.encoder_service import encoder_service
|
| 9 |
-
|
| 10 |
-
@proxy_bp.route('/files/<path:filename>')
|
| 11 |
-
def serve_file(filename):
|
| 12 |
-
"""Serve files from the encoded directory"""
|
| 13 |
-
try:
|
| 14 |
-
encoded_dir = current_app.config['ENCODED_FOLDER']
|
| 15 |
-
# Split the filename to get the job_id and quality
|
| 16 |
-
parts = filename.split('/')
|
| 17 |
-
if len(parts) >= 2:
|
| 18 |
-
job_id = parts[0]
|
| 19 |
-
quality_file = parts[1]
|
| 20 |
-
# Construct the full path
|
| 21 |
-
job_dir = os.path.join(encoded_dir, job_id)
|
| 22 |
-
return send_from_directory(job_dir, quality_file)
|
| 23 |
-
else:
|
| 24 |
-
return {"error": "Invalid file path"}, 400
|
| 25 |
-
except Exception as e:
|
| 26 |
-
logger.error(f"Error serving file {filename}: {str(e)}")
|
| 27 |
-
return {"error": "File not found"}, 404
|
| 28 |
-
|
| 29 |
-
@proxy_bp.route('/uploads/<path:filename>')
|
| 30 |
-
def serve_upload(filename):
|
| 31 |
-
"""Serve files from the uploads directory"""
|
| 32 |
-
try:
|
| 33 |
-
upload_dir = current_app.config['UPLOAD_FOLDER']
|
| 34 |
-
return send_from_directory(upload_dir, filename)
|
| 35 |
-
except Exception as e:
|
| 36 |
-
logger.error(f"Error serving upload {filename}: {str(e)}")
|
| 37 |
-
return {"error": "File not found"}, 404
|
| 38 |
-
|
| 39 |
-
@proxy_bp.route('/video/<job_id>/<quality>')
|
| 40 |
-
def serve_video(job_id, quality):
|
| 41 |
-
"""Serve encoded video files"""
|
| 42 |
-
try:
|
| 43 |
-
job_info = encoder_service.get_job_info(job_id)
|
| 44 |
-
if not job_info:
|
| 45 |
-
return jsonify({
|
| 46 |
-
'error': True,
|
| 47 |
-
'message': 'Job not found'
|
| 48 |
-
}), 404
|
| 49 |
-
|
| 50 |
-
# Retrieve the video file path based on quality from the job info
|
| 51 |
-
video_file_path = None
|
| 52 |
-
for file in job_info.get('files', []):
|
| 53 |
-
if file['quality'] == quality:
|
| 54 |
-
video_file_path = file['path']
|
| 55 |
-
break
|
| 56 |
-
|
| 57 |
-
if video_file_path and os.path.exists(video_file_path):
|
| 58 |
-
directory, video_filename = os.path.split(video_file_path)
|
| 59 |
-
return send_from_directory(
|
| 60 |
-
directory,
|
| 61 |
-
video_filename,
|
| 62 |
-
mimetype='video/mp4',
|
| 63 |
-
as_attachment=True,
|
| 64 |
-
download_name=video_filename
|
| 65 |
-
)
|
| 66 |
-
else:
|
| 67 |
-
return jsonify({
|
| 68 |
-
'error': True,
|
| 69 |
-
'message': 'Video not found'
|
| 70 |
-
}), 404
|
| 71 |
-
except Exception as e:
|
| 72 |
-
logger.error(f"Failed to serve video: {str(e)}")
|
| 73 |
-
return jsonify({
|
| 74 |
-
'error': True,
|
| 75 |
-
'message': 'Failed to serve video'
|
| 76 |
-
}), 500
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
app/templates/index.html
CHANGED
|
@@ -306,7 +306,7 @@
|
|
| 306 |
return `
|
| 307 |
<div class="space-x-2">
|
| 308 |
${outputs.map(output => `
|
| 309 |
-
<a href="/video/${jobId}/${output.quality}"
|
| 310 |
class="text-xs bg-dark-700 hover:bg-dark-600 px-2 py-1 rounded transition-all duration-300"
|
| 311 |
download="${outputName || 'video'}_${output.quality}.mp4">
|
| 312 |
${output.quality}
|
|
|
|
| 306 |
return `
|
| 307 |
<div class="space-x-2">
|
| 308 |
${outputs.map(output => `
|
| 309 |
+
<a href="/api/video/${jobId}/${output.quality}"
|
| 310 |
class="text-xs bg-dark-700 hover:bg-dark-600 px-2 py-1 rounded transition-all duration-300"
|
| 311 |
download="${outputName || 'video'}_${output.quality}.mp4">
|
| 312 |
${output.quality}
|
create_favicon.py
DELETED
|
@@ -1,27 +0,0 @@
|
|
| 1 |
-
import base64
|
| 2 |
-
|
| 3 |
-
# Simple video camera icon in ICO format
|
| 4 |
-
icon_data = """
|
| 5 |
-
AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAABILAAASCwAAAAAA
|
| 6 |
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 7 |
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 8 |
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVVUBVVVVBlVVVQZVVVUBAAAAAAAA
|
| 9 |
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVVVQFVVVUjVVVVaVVVVWlVVVUjVVVV
|
| 10 |
-
AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVVVVAVVVVSNVVVWUVVVVzVVVVc1VVVWU
|
| 11 |
-
VVVVJFVVVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABVVVUBVVVVJFVVVZRVVVXpVVVV/1VVVf9V
|
| 12 |
-
VVXpVVVVlFVVVSRVVVUBAAAAAAAAAAAAAAAAVVVVAVVVVQZVVVUjVVVVlFVVVelVVVX/VVVV/1VV
|
| 13 |
-
Vf9VVVX/VVVVk1VVVSNVVVUGVVVVAQAAAAAAAAAAVVVVBlVVVSlVVVWUVVVV6VVVVf9VVVX/VVVV
|
| 14 |
-
/1VVVf9VVVX/VVVVlFVVVSlVVVUGAAAAAAAAAAAAAAAAAAAAAFVVVQZVVVUjVVVVlFVVVelVVVX/
|
| 15 |
-
VVVV/1VVVf9VVVX/VVVVlFVVVSNVVVUGAAAAAAAAAAAAAAAAAAAAAAAAAABVVVUBVVVVJFVVVZRV
|
| 16 |
-
VVXpVVVV/1VVVf9VVVXpVVVVlFVVVSRVVVUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFVV
|
| 17 |
-
VQFVVVUjVVVVlFVVVc1VVVXNVVVVlFVVVSNVVVUBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 18 |
-
AAAAAABVVVUBVVVVIlVVVWlVVVVpVVVVIlVVVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 19 |
-
AAAAAAAAAAAAAAAAAFVVVQFVVVUGVVVVBlVVVQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 20 |
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 21 |
-
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
|
| 22 |
-
AAA=
|
| 23 |
-
"""
|
| 24 |
-
|
| 25 |
-
# Decode base64 and write to file
|
| 26 |
-
with open('app/static/favicon.ico', 'wb') as f:
|
| 27 |
-
f.write(base64.b64decode(icon_data.strip()))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|