generate proper filenames for bulk download, and use that as base folder inside tar

This commit is contained in:
Paul Bienkowski 2023-05-13 20:14:35 +02:00
parent 612a443dde
commit dd2e995720
4 changed files with 24 additions and 8 deletions

View file

@ -21,6 +21,7 @@ def _add_cors_headers(request, response, methods: Iterable[str]) -> None:
"origin, content-type, accept, " "origin, content-type, accept, "
"authorization, x-xsrf-token, x-request-id" "authorization, x-xsrf-token, x-request-id"
), ),
"Access-Control-Expose-Headers": "content-disposition",
} }
response.headers.extend(headers) response.headers.extend(headers)

View file

@ -1,10 +1,12 @@
import logging import logging
import re import re
from datetime import date
from json import load as jsonload from json import load as jsonload
from os.path import join, exists, isfile from os.path import join, exists, isfile
from sanic.exceptions import InvalidUsage, NotFound, Forbidden from sanic.exceptions import InvalidUsage, NotFound, Forbidden
from sanic.response import file_stream, empty from sanic.response import file_stream, empty
from slugify import slugify
from sqlalchemy import select, func, and_ from sqlalchemy import select, func, and_
from sqlalchemy.orm import joinedload from sqlalchemy.orm import joinedload
@ -163,7 +165,11 @@ async def tracks_bulk_action(req):
await req.ctx.db.commit() await req.ctx.db.commit()
if action == "download": if action == "download":
await tar_of_tracks(req, files) username_slug = slugify(req.ctx.user.username, separator="-")
date_str = date.today().isoformat()
file_basename = f"tracks_{username_slug}_{date_str}"
await tar_of_tracks(req, files, file_basename)
return return
return empty() return empty()

View file

@ -1,8 +1,8 @@
from datetime import datetime from datetime import datetime
import logging import logging
import os
import queue import queue
import tarfile import tarfile
from os.path import commonpath, relpath, join
import dateutil.parser import dateutil.parser
@ -86,22 +86,24 @@ class chunk:
break break
async def tar_of_tracks(req, files): async def tar_of_tracks(req, files, file_basename="tracks"):
response = await req.respond( response = await req.respond(
content_type="application/x-gtar", content_type="application/x-gtar",
headers={"Content-Disposition": 'attachment; filename="tracks.tar.bz2"'}, headers={
"content-disposition": f'attachment; filename="{file_basename}.tar.bz2"'
},
) )
helper = StreamerHelper(response) helper = StreamerHelper(response)
tar = tarfile.open(name=None, fileobj=helper, mode="w|bz2", bufsize=256 * 512) tar = tarfile.open(name=None, fileobj=helper, mode="w|bz2", bufsize=256 * 512)
root = os.path.commonpath(list(files)) root = commonpath(list(files))
for fname in files: for fname in files:
log.info("Write file to tar: %s", fname) log.info("Write file to tar: %s", fname)
with open(fname, "rb") as fobj: with open(fname, "rb") as fobj:
tarinfo = tar.gettarinfo(fname) tarinfo = tar.gettarinfo(fname)
tarinfo.name = os.path.relpath(fname, root) tarinfo.name = join(file_basename, relpath(fname, root))
tar.addfile(tarinfo, fobj) tar.addfile(tarinfo, fobj)
await helper.send_all() await helper.send_all()
tar.close() tar.close()

View file

@ -240,10 +240,17 @@ function TracksTable({ title }) {
action, action,
tracks: Object.keys(selectedTracks), tracks: Object.keys(selectedTracks),
}, },
returnResponse: true returnResponse: true,
}); });
if (action === "download") { if (action === "download") {
download(await response.blob(), "tracks.tar.bz2", "application/x-gtar"); const contentType =
response.headers.get("content-type") ?? "application/x-gtar";
const filename =
response.headers
.get("content-disposition")
?.match(/filename="([^"]+)"/)?.[1] ?? "tracks.tar.bz2";
download(await response.blob(), filename, contentType);
} }
setShowBulkDelete(false); setShowBulkDelete(false);