|
|
|
|
|
|
|
|
from flask import Flask, request, Response, stream_with_context |
|
|
import requests |
|
|
import subprocess |
|
|
import tempfile |
|
|
import os |
|
|
import shutil |
|
|
import time |
|
|
|
|
|
ffmpeg_app = Flask(__name__) |
|
|
|
|
|
@ffmpeg_app.route('/convert', methods=['GET']) |
|
|
def convert_media(): |
|
|
""" |
|
|
Downloads the raw media file from the provided URL and converts it using FFmpeg. |
|
|
""" |
|
|
media_url = request.args.get('url') |
|
|
target_format = request.args.get('format') |
|
|
|
|
|
if not media_url or not target_format: |
|
|
return "Missing 'url' or 'format' parameter", 400 |
|
|
|
|
|
temp_dir = tempfile.mkdtemp() |
|
|
|
|
|
|
|
|
input_ext = media_url.split('.')[-1].split('?')[0] |
|
|
input_file_path = os.path.join(temp_dir, f"input.{input_ext}") |
|
|
output_file_path = os.path.join(temp_dir, f"output.{target_format}") |
|
|
|
|
|
try: |
|
|
start_time = time.time() |
|
|
print(f"[{time.strftime('%H:%M:%S')}] Starting conversion for {target_format} from URL: {media_url[:100]}...") |
|
|
|
|
|
|
|
|
with requests.get(media_url, stream=True, timeout=120) as r: |
|
|
r.raise_for_status() |
|
|
content_length = int(r.headers.get('content-length', 0)) |
|
|
print(f"[{time.strftime('%H:%M:%S')}] Raw media size: {content_length/1024/1024:.2f} MB") |
|
|
with open(input_file_path, 'wb') as f: |
|
|
for chunk in r.iter_content(chunk_size=8192): |
|
|
f.write(chunk) |
|
|
|
|
|
download_time = time.time() |
|
|
print(f"[{time.strftime('%H:%M:%S')}] Download complete. Time taken: {download_time - start_time:.2f} seconds.") |
|
|
|
|
|
|
|
|
command = [ |
|
|
'ffmpeg', |
|
|
'-y', |
|
|
'-i', input_file_path, |
|
|
|
|
|
'-q:a', '0', |
|
|
'-map', 'a', |
|
|
|
|
|
'-c:a', 'libmp3lame' if target_format == 'mp3' else |
|
|
('pcm_s16le' if target_format == 'wav' else 'aac'), |
|
|
'-f', target_format, |
|
|
output_file_path |
|
|
] |
|
|
|
|
|
subprocess.run(command, check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=180) |
|
|
|
|
|
conversion_time = time.time() |
|
|
print(f"[{time.strftime('%H:%M:%S')}] FFmpeg conversion complete. Time taken: {conversion_time - download_time:.2f} seconds.") |
|
|
|
|
|
|
|
|
def stream_output_file(): |
|
|
with open(output_file_path, 'rb') as f: |
|
|
chunk = True |
|
|
while chunk: |
|
|
chunk = f.read(8192) |
|
|
yield chunk |
|
|
|
|
|
mime_type = f'audio/{target_format}' if target_format != 'm4a' else 'audio/mp4' |
|
|
|
|
|
return Response(stream_with_context(stream_output_file()), |
|
|
mimetype=mime_type) |
|
|
|
|
|
except subprocess.CalledProcessError as e: |
|
|
print(f"[{time.strftime('%H:%M:%S')}] FFmpeg command failed with error: {e.stderr.decode()}") |
|
|
return f"Conversion failed: {e.stderr.decode()}", 500 |
|
|
except requests.exceptions.Timeout: |
|
|
return "Media download or conversion timed out.", 504 |
|
|
except Exception as e: |
|
|
print(f"[{time.strftime('%H:%M:%S')}] An error occurred in the FFmpeg service: {e}") |
|
|
return f"Internal Server Error: {e}", 500 |
|
|
|
|
|
finally: |
|
|
|
|
|
if os.path.exists(temp_dir): |
|
|
shutil.rmtree(temp_dir) |
|
|
print(f"[{time.strftime('%H:%M:%S')}] Cleaned up temp directory: {temp_dir}") |
|
|
|
|
|
@ffmpeg_app.route('/', methods=['GET']) |
|
|
def index(): |
|
|
return "FFmpeg Conversion Service is running." |
|
|
|
|
|
if __name__ == '__main__': |
|
|
|
|
|
|
|
|
ffmpeg_app.run(host='0.0.0.0', port=7860, debug=True) |