feat: compress downloads to max 250MB via ffmpeg

This commit is contained in:
jetson committed 2026-09-28 09:39:56 +07:00
1 parent 7932119e17
commit 6f86bca204
2 files changed
+196 -1

No files matched your search

+39 -1
View File
@@ -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")