Add bulk downloading

This commit is contained in:
gluap 2023-04-11 21:06:27 +02:00 committed by Paul Bienkowski
parent fb3e8bf701
commit a946ea53c9
2 changed files with 57 additions and 6 deletions

View file

@ -1,16 +1,17 @@
import logging
import queue
import re
import tarfile
from json import load as jsonload
from os.path import join, exists, isfile
from sanic.exceptions import InvalidUsage, NotFound, Forbidden
from sanic.response import file_stream, empty
from sqlalchemy import select, func, and_
from sqlalchemy.orm import joinedload
from obs.api.db import Track, User, Comment, DuplicateTrackFileError
from obs.api.app import api, require_auth, read_api_key, json
from sanic.response import file_stream, empty
from sanic.exceptions import InvalidUsage, NotFound, Forbidden
from obs.api.db import Track, Comment, DuplicateTrackFileError
log = logging.getLogger(__name__)
@ -58,6 +59,39 @@ async def _return_tracks(req, extend_query, limit, offset, order_by=None):
},
)
class StreamerHelper:
def __init__(self, response):
self.response = response
self.towrite = queue.Queue()
def write(self, data):
self.towrite.put(data)
async def send_all(self):
while True:
try:
tosend = self.towrite.get(block=False)
await self.response.send(tosend)
except queue.Empty:
break
async def tar_of_tracks(req, files):
response = await req.respond(content_type="application/x-gtar", headers={'Content-Disposition': 'attachment; filename="tracks.tar.bz2"'})
helper = StreamerHelper(response)
tar = tarfile.open(name=None, fileobj=helper, mode="w|bz2", bufsize=256 * 512)
for fname in files:
logging.info(f"sending {fname}")
with open(fname, "rb") as fobj:
tar.addfile(tar.gettarinfo(fname),fobj)
await helper.send_all()
tar.close()
await helper.send_all()
await response.eof()
@api.get("/tracks")
async def get_tracks(req):
@ -135,13 +169,15 @@ async def tracks_bulk_action(req):
action = body["action"]
track_slugs = body["tracks"]
if action not in ("delete", "makePublic", "makePrivate", "reprocess"):
if action not in ("delete", "makePublic", "makePrivate", "reprocess", "download"):
raise InvalidUsage("invalid action")
query = select(Track).where(
and_(Track.author_id == req.ctx.user.id, Track.slug.in_(track_slugs))
)
files = set()
for track in (await req.ctx.db.execute(query)).scalars():
if action == "delete":
await req.ctx.db.delete(track)
@ -155,9 +191,15 @@ async def tracks_bulk_action(req):
track.public = False
elif action == "reprocess":
track.queue_processing()
elif action == "download":
files.add(track.get_original_file_path(req.app.config))
await req.ctx.db.commit()
if action == "download":
await tar_of_tracks(req, files)
return
return empty()

View file

@ -27,6 +27,8 @@ import { Page, FormattedDate, Visibility } from "components";
import api from "api";
import { useCallbackRef, formatDistance, formatDuration } from "utils";
import download from "downloadjs";
const COLOR_BY_STATUS: Record<ProcessingStatus, SemanticCOLORS> = {
error: "red",
complete: "green",
@ -233,12 +235,16 @@ function TracksTable({ title }) {
};
const bulkAction = async (action: string) => {
await api.post("/tracks/bulk", {
const data = await api.post("/tracks/bulk", {
body: {
action,
tracks: Object.keys(selectedTracks),
},
returnResponse: true
});
if (action === "download") {
download(await data.blob(), "tracks.tar.bz2", "application/x-gtar");
}
setShowBulkDelete(false);
setSelectedTracks({});
@ -263,6 +269,9 @@ function TracksTable({ title }) {
<Dropdown.Item onClick={() => bulkAction("reprocess")}>
Reprocess
</Dropdown.Item>
<Dropdown.Item onClick={() => bulkAction("download")}>
Download
</Dropdown.Item>
<Dropdown.Item onClick={() => setShowBulkDelete(true)}>
Delete
</Dropdown.Item>