feat: compress downloads to max 250MB via ffmpeg
This commit is contained in:
1 parent
7932119e17
commit
6f86bca204
2 files changed
+196
-1
No files matched your search
@@ -3,7 +3,9 @@
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from flask import (
|
||||
@@ -204,6 +206,41 @@ def jobs_list():
|
||||
return render_template("jobs.html", jobs=jobs)
|
||||
|
||||
|
||||
def _compress_for_download(file_path: str, max_bytes: int = 250 * 1024 * 1024) -> str | None:
|
||||
"""Compress file_path with ffmpeg if larger than max_bytes.
|
||||
|
||||
Returns path to `<name>_compressed.mp4` next to the input, or None to
|
||||
fall back to the original file (small file, ffmpeg missing/failed).
|
||||
"""
|
||||
if not os.path.isfile(file_path):
|
||||
return None
|
||||
if os.path.getsize(file_path) <= max_bytes:
|
||||
return None
|
||||
out_path = os.path.splitext(file_path)[0] + "_compressed.mp4"
|
||||
if os.path.isfile(out_path):
|
||||
return out_path
|
||||
try:
|
||||
probe = subprocess.run(
|
||||
["ffprobe", "-v", "quiet", "-print_format", "json", "-show_format", file_path],
|
||||
capture_output=True, text=True, timeout=60,
|
||||
)
|
||||
duration = float(json.loads(probe.stdout).get("format", {}).get("duration") or 0)
|
||||
except (OSError, subprocess.SubprocessError, ValueError, TypeError, AttributeError):
|
||||
return None
|
||||
if duration <= 0:
|
||||
return None
|
||||
bitrate = int((max_bytes * 8 * 0.92) / duration)
|
||||
try:
|
||||
subprocess.run(
|
||||
["ffmpeg", "-y", "-i", file_path, "-c:v", "libx264",
|
||||
"-b:v", str(bitrate), "-c:a", "aac", "-b:a", "64k", out_path],
|
||||
capture_output=True, timeout=3600, check=True,
|
||||
)
|
||||
except (OSError, subprocess.SubprocessError):
|
||||
return None
|
||||
return out_path if os.path.isfile(out_path) else None
|
||||
|
||||
|
||||
@app.route("/download/<job_id>/<filename>")
|
||||
def download(job_id, filename):
|
||||
job = job_queue.get_job(job_id)
|
||||
@@ -216,7 +253,8 @@ def download(job_id, filename):
|
||||
return "File not found", 404
|
||||
if not os.path.isfile(file_path):
|
||||
return "File not found", 404
|
||||
return send_file(file_path, as_attachment=True)
|
||||
compressed = _compress_for_download(file_path)
|
||||
return send_file(compressed or file_path, as_attachment=True)
|
||||
|
||||
|
||||
@app.route("/api/videos")
|
||||
|
||||
Reference in new issue
Block a user