mirror of
https://github.com/spl0k/supysonic.git
synced 2024-12-22 17:06:17 +00:00
Switch to using zipstream-ng
to generate and stream zip files
- Fixes zip downloads failing when zipping enough data that Zip64 extensions are required by automatically enabling them if needed. - Fixes zip downloads failing when a file has a datestamp that zipfiles cannot store (pre-1980 or post-2108) by clamping them within the supported range. - Massively speeds up zip downloads by disabling compression (audio files generally don't compress well anyway) - Computes the total size of a generated zip file before streaming it and sets the `Content-Length` header. This allows clients to show a final size and progress bar while downloading, as well as detect if the download fails. - Adds a check to prevent sending an empty zip file to the client if there was no content to download (will error out instead).
This commit is contained in:
parent
5490189484
commit
387a5e3de3
2
setup.py
2
setup.py
@ -18,7 +18,7 @@ reqs = [
|
|||||||
"requests>=1.0.0",
|
"requests>=1.0.0",
|
||||||
"mediafile",
|
"mediafile",
|
||||||
"watchdog>=0.8.0",
|
"watchdog>=0.8.0",
|
||||||
"zipstream",
|
"zipstream-ng>=1.1.0,<2.0.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
|
@ -22,8 +22,7 @@ from flask import current_app
|
|||||||
from PIL import Image
|
from PIL import Image
|
||||||
from pony.orm import ObjectNotFound
|
from pony.orm import ObjectNotFound
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
from zipfile import ZIP_DEFLATED
|
from zipstream import ZipStream
|
||||||
from zipstream import ZipFile
|
|
||||||
|
|
||||||
from ..cache import CacheMiss
|
from ..cache import CacheMiss
|
||||||
from ..db import Track, Album, Folder, now
|
from ..db import Track, Album, Folder, now
|
||||||
@ -251,16 +250,20 @@ def download_media():
|
|||||||
raise NotFound("Folder")
|
raise NotFound("Folder")
|
||||||
|
|
||||||
# Stream a zip of the tracks + cover art to the client
|
# Stream a zip of the tracks + cover art to the client
|
||||||
z = ZipFile(compression=ZIP_DEFLATED)
|
z = ZipStream(sized=True)
|
||||||
for track in rv.tracks:
|
for track in rv.tracks:
|
||||||
z.write(track.path, os.path.basename(track.path))
|
z.add_path(track.path)
|
||||||
|
|
||||||
cover_path = _cover_from_collection(rv, extract=False)
|
cover_path = _cover_from_collection(rv, extract=False)
|
||||||
if cover_path:
|
if cover_path:
|
||||||
z.write(cover_path, os.path.basename(cover_path))
|
z.add_path(cover_path)
|
||||||
|
|
||||||
|
if not z:
|
||||||
|
raise GenericError("Nothing to download")
|
||||||
|
|
||||||
resp = Response(z, mimetype="application/zip")
|
resp = Response(z, mimetype="application/zip")
|
||||||
resp.headers["Content-Disposition"] = "attachment; filename={}.zip".format(rv.name)
|
resp.headers["Content-Disposition"] = "attachment; filename={}.zip".format(rv.name)
|
||||||
|
resp.headers["Content-Length"] = len(z)
|
||||||
return resp
|
return resp
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user