Fix Choppy streaming
This commit is contained in:
1 parent
676a52199c
commit
1d447fdba4
1 file changed
+44
-2
@@ -1,9 +1,10 @@
|
|||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import sys
|
import sys
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
from flask import Flask, abort, render_template, send_file
|
from flask import Flask, Response, abort, render_template, request
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
@@ -51,7 +52,48 @@ def play(path):
|
|||||||
@app.route("/video/<path:path>")
|
@app.route("/video/<path:path>")
|
||||||
def serve_video(path):
|
def serve_video(path):
|
||||||
full = _validate_path(path)
|
full = _validate_path(path)
|
||||||
return send_file(full, mimetype="video/mp4")
|
file_size = full.stat().st_size
|
||||||
|
range_header = request.headers.get("Range")
|
||||||
|
|
||||||
|
if not range_header:
|
||||||
|
return _stream_file(full, 0, file_size - 1, file_size, 200)
|
||||||
|
|
||||||
|
match = re.match(r"bytes=(\d+)-(\d*)", range_header)
|
||||||
|
if not match:
|
||||||
|
abort(416)
|
||||||
|
|
||||||
|
start = int(match.group(1))
|
||||||
|
end_str = match.group(2)
|
||||||
|
end = int(end_str) if end_str else file_size - 1
|
||||||
|
|
||||||
|
if start >= file_size or end >= file_size or start > end:
|
||||||
|
abort(416)
|
||||||
|
|
||||||
|
content_length = end - start + 1
|
||||||
|
return _stream_file(full, start, end, content_length, 206)
|
||||||
|
|
||||||
|
|
||||||
|
def _stream_file(path, start, end, content_length, status):
|
||||||
|
def generate():
|
||||||
|
with open(path, "rb") as f:
|
||||||
|
f.seek(start)
|
||||||
|
remaining = content_length
|
||||||
|
while remaining > 0:
|
||||||
|
chunk_size = min(8192, remaining)
|
||||||
|
data = f.read(chunk_size)
|
||||||
|
if not data:
|
||||||
|
break
|
||||||
|
remaining -= len(data)
|
||||||
|
yield data
|
||||||
|
|
||||||
|
file_size = path.stat().st_size
|
||||||
|
headers = {
|
||||||
|
"Content-Range": f"bytes {start}-{end}/{file_size}",
|
||||||
|
"Accept-Ranges": "bytes",
|
||||||
|
"Content-Length": str(content_length),
|
||||||
|
"Content-Type": "video/mp4",
|
||||||
|
}
|
||||||
|
return Response(generate(), status=status, headers=headers)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|||||||
Reference in new issue
Block a user