mirror of
https://github.com/9001/copyparty.git
synced 2026-06-18 20:22:27 -06:00
download-as-zip: toplevel optional
This commit is contained in:
parent
c28aa08b35
commit
cc5420a324
|
|
@ -836,6 +836,7 @@ you can also zip a selection of files or folders by clicking them in the browser
|
||||||
|
|
||||||
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
|
cool trick: download a folder by appending url-params `?tar&opus` or `?tar&mp3` to transcode all audio files (except aac|m4a|mp3|ogg|opus|wma) to opus/mp3 before they're added to the archive
|
||||||
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
|
* super useful if you're 5 minutes away from takeoff and realize you don't have any music on your phone but your server only has flac files and downloading those will burn through all your data + there wouldn't be enough time anyways
|
||||||
|
* and url-param `&name=foo` changes the name of the toplevel folder in the archive to `foo`, and just `&name` removes the folder entirely
|
||||||
* and url-param `&nodot` skips dotfiles/dotfolders; they are included by default if your account has permission to see them
|
* and url-param `&nodot` skips dotfiles/dotfolders; they are included by default if your account has permission to see them
|
||||||
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
|
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
|
||||||
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
||||||
|
|
|
||||||
|
|
@ -900,20 +900,14 @@ class VFS(object):
|
||||||
|
|
||||||
def zipgen(
|
def zipgen(
|
||||||
self,
|
self,
|
||||||
vpath: str,
|
folder: str,
|
||||||
vrem: str,
|
vrem: str,
|
||||||
flt: set[str],
|
flt: set[str],
|
||||||
uname: str,
|
uname: str,
|
||||||
dirs: bool,
|
dirs: bool,
|
||||||
dots: int,
|
dots: int,
|
||||||
scandir: bool,
|
scandir: bool,
|
||||||
wrap: bool = True,
|
|
||||||
) -> Generator[dict[str, Any], None, None]:
|
) -> Generator[dict[str, Any], None, None]:
|
||||||
|
|
||||||
# if multiselect: add all items to archive root
|
|
||||||
# if single folder: the folder itself is the top-level item
|
|
||||||
folder = "" if flt or not wrap else (vpath.split("/")[-1].lstrip(".") or "top")
|
|
||||||
|
|
||||||
g = self.walk(folder, vrem, [], uname, [[True, False]], dots, scandir, False)
|
g = self.walk(folder, vrem, [], uname, [[True, False]], dots, scandir, False)
|
||||||
for _, _, vpath, apath, files, rd, vd in g:
|
for _, _, vpath, apath, files, rd, vd in g:
|
||||||
if flt:
|
if flt:
|
||||||
|
|
|
||||||
|
|
@ -1823,14 +1823,13 @@ class HttpCli(object):
|
||||||
# because lstat=true would not recurse into subfolders
|
# because lstat=true would not recurse into subfolders
|
||||||
# and this is a rare case where we actually want that
|
# and this is a rare case where we actually want that
|
||||||
fgen = vn.zipgen(
|
fgen = vn.zipgen(
|
||||||
rem,
|
"",
|
||||||
rem,
|
rem,
|
||||||
set(),
|
set(),
|
||||||
self.uname,
|
self.uname,
|
||||||
True,
|
True,
|
||||||
1,
|
1,
|
||||||
not self.args.no_scandir,
|
not self.args.no_scandir,
|
||||||
wrap=False,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
elif depth == "0":
|
elif depth == "0":
|
||||||
|
|
@ -5163,6 +5162,16 @@ class HttpCli(object):
|
||||||
if items:
|
if items:
|
||||||
fn = "sel-" + fn
|
fn = "sel-" + fn
|
||||||
|
|
||||||
|
if "name" in self.ouparam:
|
||||||
|
# user-selected name for toplevel folder, or blank for none
|
||||||
|
vpath = undot(self.ouparam["name"])
|
||||||
|
elif items:
|
||||||
|
# multiselect; add all items to archive root
|
||||||
|
vpath = ""
|
||||||
|
else:
|
||||||
|
# single folder; the folder itself is the top-level item
|
||||||
|
vpath = vpath.split("/")[-1].lstrip(".") or "top"
|
||||||
|
|
||||||
if vn.flags.get("zipmax") and not (
|
if vn.flags.get("zipmax") and not (
|
||||||
vn.flags.get("zipmaxu") and self.uname != "*"
|
vn.flags.get("zipmaxu") and self.uname != "*"
|
||||||
):
|
):
|
||||||
|
|
@ -5209,7 +5218,7 @@ class HttpCli(object):
|
||||||
|
|
||||||
if cfmt:
|
if cfmt:
|
||||||
self.log("transcoding to [{}]".format(cfmt))
|
self.log("transcoding to [{}]".format(cfmt))
|
||||||
fgen = gfilter(fgen, self.thumbcli, self.uname, vpath, cfmt)
|
fgen = gfilter(fgen, self.thumbcli, self.uname, self.vpath, vpath, cfmt)
|
||||||
|
|
||||||
now = time.time()
|
now = time.time()
|
||||||
self.dl_id = "%s:%s" % (self.ip, self.addr[1])
|
self.dl_id = "%s:%s" % (self.ip, self.addr[1])
|
||||||
|
|
|
||||||
|
|
@ -700,7 +700,7 @@ class HttpSrv(object):
|
||||||
if not fmts:
|
if not fmts:
|
||||||
continue
|
continue
|
||||||
log("starting for volume /%s" % (vn.vpath,), 6)
|
log("starting for volume /%s" % (vn.vpath,), 6)
|
||||||
g = vn.walk("x", "/", [], LEELOO_DALLAS, [[True]], 2, scandir, False, False)
|
g = vn.walk("", "/", [], LEELOO_DALLAS, [[True]], 2, scandir, False, False)
|
||||||
g = gfilter2(g, self, vn.vpath, fmts.split(","))
|
g = gfilter2(g, self, vn.vpath, fmts.split(","))
|
||||||
for f in g:
|
for f in g:
|
||||||
nfiles += 1
|
nfiles += 1
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,7 @@ def gfilter(
|
||||||
thumbcli: ThumbCli,
|
thumbcli: ThumbCli,
|
||||||
uname: str,
|
uname: str,
|
||||||
vtop: str,
|
vtop: str,
|
||||||
|
vname: str,
|
||||||
fmt: str,
|
fmt: str,
|
||||||
) -> Generator[dict[str, Any], None, None]:
|
) -> Generator[dict[str, Any], None, None]:
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
|
|
@ -70,7 +71,7 @@ def gfilter(
|
||||||
_pools[tp] = 1
|
_pools[tp] = 1
|
||||||
try:
|
try:
|
||||||
for f in fgen:
|
for f in fgen:
|
||||||
task = tp.submit(enthumb, thumbcli, uname, vtop, f, fmt)
|
task = tp.submit(enthumb, thumbcli, uname, vtop, vname, f, fmt)
|
||||||
pend.append((task, f))
|
pend.append((task, f))
|
||||||
if pend[0][0].done() or len(pend) > CORES * 4:
|
if pend[0][0].done() or len(pend) > CORES * 4:
|
||||||
task, f = pend.pop(0)
|
task, f = pend.pop(0)
|
||||||
|
|
@ -130,7 +131,7 @@ def gfilter2(
|
||||||
try:
|
try:
|
||||||
f = {"vp": vp, "st": fi[1]}
|
f = {"vp": vp, "st": fi[1]}
|
||||||
task = tp.submit(
|
task = tp.submit(
|
||||||
enthumb, hsrv.thumbcli, LEELOO_DALLAS, vtop, f, fmt
|
enthumb, hsrv.thumbcli, LEELOO_DALLAS, vtop, "", f, fmt
|
||||||
)
|
)
|
||||||
pend.append((task, f))
|
pend.append((task, f))
|
||||||
if pend[0][0].done() or len(pend) > CORES * 4:
|
if pend[0][0].done() or len(pend) > CORES * 4:
|
||||||
|
|
@ -152,14 +153,17 @@ def gfilter2(
|
||||||
|
|
||||||
|
|
||||||
def enthumb(
|
def enthumb(
|
||||||
thumbcli: ThumbCli, uname: str, vtop: str, f: dict[str, Any], fmt: str
|
thumbcli: ThumbCli, uname: str, vtop: str, vname: str, f: dict[str, Any], fmt: str
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
rem = f["vp"]
|
rem = f["vp"]
|
||||||
ext = rem.rsplit(".", 1)[-1].lower()
|
ext = rem.rsplit(".", 1)[-1].lower()
|
||||||
if (fmt == "mp3" and ext == "mp3") or (fmt == "opus" and ext in TAR_NO_OPUS):
|
if (fmt == "mp3" and ext == "mp3") or (fmt == "opus" and ext in TAR_NO_OPUS):
|
||||||
raise Exception()
|
raise Exception()
|
||||||
|
|
||||||
|
if vname:
|
||||||
vp = vjoin(vtop, rem.split("/", 1)[1])
|
vp = vjoin(vtop, rem.split("/", 1)[1])
|
||||||
|
else:
|
||||||
|
vp = vjoin(vtop, rem)
|
||||||
vn, rem = thumbcli.asrv.vfs.get(vp, uname, True, False)
|
vn, rem = thumbcli.asrv.vfs.get(vp, uname, True, False)
|
||||||
dbv, vrem = vn.get_dbv(rem)
|
dbv, vrem = vn.get_dbv(rem)
|
||||||
thp = thumbcli.get(dbv, vrem, f["st"].st_mtime, fmt)
|
thp = thumbcli.get(dbv, vrem, f["st"].st_mtime, fmt)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue