mirror of
https://github.com/Dvorinka/swingmusic-extended.git
synced 2026-06-04 12:33:03 +00:00
try streaming files as chunks
This commit is contained in:
+50
-4
@@ -4,7 +4,7 @@ Contains all the track routes.
|
||||
|
||||
import os
|
||||
|
||||
from flask import Blueprint, send_file, request
|
||||
from flask import Blueprint, send_file, request, Response
|
||||
from flask_openapi3 import APIBlueprint, Tag
|
||||
from pydantic import BaseModel, Field
|
||||
from app.api.apischemas import TrackHashSchema
|
||||
@@ -37,7 +37,7 @@ def send_track_file(path: TrackHashSchema, query: SendTrackFileQuery):
|
||||
ext = filename.rsplit(".", maxsplit=1)[-1]
|
||||
return f"audio/{ext}"
|
||||
|
||||
# If filepath is provide, try to send that
|
||||
# If filepath is provided, try to send that
|
||||
if filepath is not None:
|
||||
try:
|
||||
track = TrackStore.get_tracks_by_filepaths([filepath])[0]
|
||||
@@ -48,7 +48,7 @@ def send_track_file(path: TrackHashSchema, query: SendTrackFileQuery):
|
||||
|
||||
if track_exists:
|
||||
audio_type = get_mime(filepath)
|
||||
return send_file(filepath, mimetype=audio_type)
|
||||
return send_file_as_chunks(track.filepath, audio_type)
|
||||
|
||||
# Else, find file by trackhash
|
||||
tracks = TrackStore.get_tracks_by_trackhashes([trackhash])
|
||||
@@ -60,13 +60,59 @@ def send_track_file(path: TrackHashSchema, query: SendTrackFileQuery):
|
||||
audio_type = get_mime(track.filepath)
|
||||
|
||||
try:
|
||||
return send_file(track.filepath, mimetype=audio_type)
|
||||
return send_file_as_chunks(track.filepath, audio_type)
|
||||
except (FileNotFoundError, OSError) as e:
|
||||
return msg, 404
|
||||
|
||||
return msg, 404
|
||||
|
||||
|
||||
def send_file_as_chunks(filepath: str, audio_type: str) -> Response:
|
||||
file_size = os.path.getsize(filepath)
|
||||
start = 0
|
||||
end = file_size - 1
|
||||
|
||||
range_header = request.headers.get("Range")
|
||||
if range_header:
|
||||
start, end = parse_range_header(range_header, file_size)
|
||||
|
||||
chunk_size = 1024 * 1024 # 1MB chunk size (adjust as needed)
|
||||
|
||||
def generate_chunks():
|
||||
with open(filepath, "rb") as file:
|
||||
file.seek(start)
|
||||
remaining_bytes = end - start + 1
|
||||
|
||||
while remaining_bytes > 0:
|
||||
chunk = file.read(min(chunk_size, remaining_bytes))
|
||||
yield chunk
|
||||
remaining_bytes -= len(chunk)
|
||||
|
||||
response = Response(
|
||||
generate_chunks(),
|
||||
206, # Partial Content status code
|
||||
mimetype=audio_type,
|
||||
content_type=audio_type,
|
||||
direct_passthrough=True,
|
||||
)
|
||||
response.headers.add("Content-Range", f"bytes {start}-{end}/{file_size}")
|
||||
response.headers.add("Accept-Ranges", "bytes")
|
||||
response.headers.add("Content-Length", str(end - start + 1))
|
||||
|
||||
return response
|
||||
|
||||
|
||||
def parse_range_header(range_header: str, file_size: int) -> tuple[int, int]:
|
||||
try:
|
||||
range_start, range_end = range_header.strip().split("=")[1].split("-")
|
||||
start = int(range_start)
|
||||
end = min(int(range_end), file_size - 1)
|
||||
except ValueError:
|
||||
return 0, file_size - 1
|
||||
|
||||
return start, end
|
||||
|
||||
|
||||
class GetAudioSilenceBody(BaseModel):
|
||||
ending_file: str = Field(
|
||||
description="The ending file's path",
|
||||
|
||||
Reference in New Issue
Block a user