mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 17:12:13 -06:00
not even the deprecationwarning that got silently generated burning 20~30% of all CPU-time without actually displaying it anywhere, nice python 3.12.0 is now only 5% slower than 3.11.6 also fixes some other, less-performance-fatal deprecations
112 lines
2.9 KiB
Python
Executable file
112 lines
2.9 KiB
Python
Executable file
#!/usr/bin/env python3
|
|
|
|
import hashlib
|
|
import json
|
|
import sys
|
|
from datetime import datetime, timezone
|
|
|
|
|
|
_ = r"""
|
|
this hook will produce a single sha512 file which
|
|
covers all recent uploads (plus metadata comments)
|
|
|
|
use this with --xiu, which makes copyparty buffer
|
|
uploads until server is idle, providing file infos
|
|
on stdin (filepaths or json)
|
|
|
|
example usage as global config:
|
|
--xiu i5,j,bin/hooks/xiu-sha.py
|
|
|
|
example usage as a volflag (per-volume config):
|
|
-v srv/inc:inc:r:rw,ed:c,xiu=i5,j,bin/hooks/xiu-sha.py
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
(share filesystem-path srv/inc as volume /inc,
|
|
readable by everyone, read-write for user 'ed',
|
|
running this plugin on batches of uploads with the params listed below)
|
|
|
|
parameters explained,
|
|
xiu = execute after uploads...
|
|
i5 = ...after volume has been idle for 5sec
|
|
j = provide json instead of filepath list
|
|
|
|
note the "f" (fork) flag is not set, so this xiu
|
|
will block other xiu hooks while it's running
|
|
"""
|
|
|
|
|
|
try:
|
|
from copyparty.util import fsenc
|
|
except:
|
|
|
|
def fsenc(p):
|
|
return p
|
|
|
|
|
|
UTC = timezone.utc
|
|
|
|
|
|
def humantime(ts):
|
|
return datetime.fromtimestamp(ts, UTC).strftime("%Y-%m-%d %H:%M:%S")
|
|
|
|
|
|
def find_files_root(inf):
|
|
di = 9000
|
|
for f1, f2 in zip(inf, inf[1:]):
|
|
p1 = f1["ap"].replace("\\", "/").rsplit("/", 1)[0]
|
|
p2 = f2["ap"].replace("\\", "/").rsplit("/", 1)[0]
|
|
di = min(len(p1), len(p2), di)
|
|
di = next((i for i in range(di) if p1[i] != p2[i]), di)
|
|
|
|
return di + 1
|
|
|
|
|
|
def find_vol_root(inf):
|
|
return len(inf[0]["ap"][: -len(inf[0]["vp"])])
|
|
|
|
|
|
def main():
|
|
zb = sys.stdin.buffer.read()
|
|
zs = zb.decode("utf-8", "replace")
|
|
inf = json.loads(zs)
|
|
|
|
# root directory (where to put the sha512 file);
|
|
# di = find_files_root(inf) # next to the file closest to volume root
|
|
di = find_vol_root(inf) # top of the entire volume
|
|
|
|
ret = []
|
|
total_sz = 0
|
|
for md in inf:
|
|
ap = md["ap"]
|
|
rp = ap[di:]
|
|
total_sz += md["sz"]
|
|
fsize = "{:,}".format(md["sz"])
|
|
mtime = humantime(md["mt"])
|
|
up_ts = humantime(md["at"])
|
|
|
|
h = hashlib.sha512()
|
|
with open(fsenc(md["ap"]), "rb", 512 * 1024) as f:
|
|
while True:
|
|
buf = f.read(512 * 1024)
|
|
if not buf:
|
|
break
|
|
|
|
h.update(buf)
|
|
|
|
cksum = h.hexdigest()
|
|
meta = " | ".join([md["wark"], up_ts, mtime, fsize, md["ip"]])
|
|
ret.append("# {}\n{} *{}".format(meta, cksum, rp))
|
|
|
|
ret.append("# {} files, {} bytes total".format(len(inf), total_sz))
|
|
ret.append("")
|
|
ftime = datetime.now(UTC).strftime("%Y-%m%d-%H%M%S.%f")
|
|
fp = "{}xfer-{}.sha512".format(inf[0]["ap"][:di], ftime)
|
|
with open(fsenc(fp), "wb") as f:
|
|
f.write("\n".join(ret).encode("utf-8", "replace"))
|
|
|
|
print("wrote checksums to {}".format(fp))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|