copyparty 1.13.1__py3-none-any.whl → 1.13.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- copyparty/__main__.py +28 -3
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +9 -0
- copyparty/broker_mp.py +2 -5
- copyparty/cfg.py +1 -0
- copyparty/httpcli.py +3 -5
- copyparty/httpsrv.py +1 -4
- copyparty/mtag.py +72 -3
- copyparty/smbd.py +1 -1
- copyparty/svchub.py +9 -2
- copyparty/th_cli.py +5 -0
- copyparty/th_srv.py +32 -5
- copyparty/up2k.py +14 -8
- copyparty/util.py +29 -6
- copyparty/web/a/u2c.py +14 -5
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/deps/marked.js.gz +0 -0
- copyparty/web/splash.js.gz +0 -0
- {copyparty-1.13.1.dist-info → copyparty-1.13.2.dist-info}/METADATA +7 -4
- {copyparty-1.13.1.dist-info → copyparty-1.13.2.dist-info}/RECORD +24 -24
- {copyparty-1.13.1.dist-info → copyparty-1.13.2.dist-info}/LICENSE +0 -0
- {copyparty-1.13.1.dist-info → copyparty-1.13.2.dist-info}/WHEEL +0 -0
- {copyparty-1.13.1.dist-info → copyparty-1.13.2.dist-info}/entry_points.txt +0 -0
- {copyparty-1.13.1.dist-info → copyparty-1.13.2.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -43,11 +43,13 @@ from .util import (
|
|
43
43
|
DEF_MTH,
|
44
44
|
IMPLICATIONS,
|
45
45
|
JINJA_VER,
|
46
|
+
MIMES,
|
46
47
|
PARTFTPY_VER,
|
47
48
|
PY_DESC,
|
48
49
|
PYFTPD_VER,
|
49
50
|
SQLITE_VER,
|
50
51
|
UNPLICATIONS,
|
52
|
+
Daemon,
|
51
53
|
align_tab,
|
52
54
|
ansi_re,
|
53
55
|
dedent,
|
@@ -464,6 +466,16 @@ def disable_quickedit() :
|
|
464
466
|
cmode(True, mode | 4)
|
465
467
|
|
466
468
|
|
469
|
+
def sfx_tpoke(top ):
|
470
|
+
files = [os.path.join(dp, p) for dp, dd, df in os.walk(top) for p in dd + df]
|
471
|
+
while True:
|
472
|
+
t = int(time.time())
|
473
|
+
for f in [top] + files:
|
474
|
+
os.utime(f, (t, t))
|
475
|
+
|
476
|
+
time.sleep(78123)
|
477
|
+
|
478
|
+
|
467
479
|
def showlic() :
|
468
480
|
p = os.path.join(E.mod, "res", "COPYING.txt")
|
469
481
|
if not os.path.exists(p):
|
@@ -814,7 +826,7 @@ def build_flags_desc():
|
|
814
826
|
v = v.replace("\n", "\n ")
|
815
827
|
ret += "\n \033[36m{}\033[35m {}".format(k, v)
|
816
828
|
|
817
|
-
return ret
|
829
|
+
return ret
|
818
830
|
|
819
831
|
|
820
832
|
# fmt: off
|
@@ -832,6 +844,8 @@ def add_general(ap, nc, srvname):
|
|
832
844
|
ap2.add_argument("--urlform", metavar="MODE", type=u, default="print,get", help="how to handle url-form POSTs; see \033[33m--help-urlform\033[0m")
|
833
845
|
ap2.add_argument("--wintitle", metavar="TXT", type=u, default="cpp @ $pub", help="server terminal title, for example [\033[32m$ip-10.1.2.\033[0m] or [\033[32m$ip-]")
|
834
846
|
ap2.add_argument("--name", metavar="TXT", type=u, default=srvname, help="server name (displayed topleft in browser and in mDNS)")
|
847
|
+
ap2.add_argument("--mime", metavar="EXT=MIME", type=u, action="append", help="map file \033[33mEXT\033[0mension to \033[33mMIME\033[0mtype, for example [\033[32mjpg=image/jpeg\033[0m]")
|
848
|
+
ap2.add_argument("--mimes", action="store_true", help="list default mimetype mapping and exit")
|
835
849
|
ap2.add_argument("--license", action="store_true", help="show licenses and exit")
|
836
850
|
ap2.add_argument("--version", action="store_true", help="show versions and exit")
|
837
851
|
|
@@ -1188,7 +1202,8 @@ def add_thumbnail(ap):
|
|
1188
1202
|
ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips")
|
1189
1203
|
ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
|
1190
1204
|
ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
|
1191
|
-
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,m4a,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,tak,tta,ulaw,wav,wma,wv,xm,xpk", help="audio formats to decode using ffmpeg")
|
1205
|
+
ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
|
1206
|
+
ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz", help="audio formats to decompress before passing to ffmpeg")
|
1192
1207
|
|
1193
1208
|
|
1194
1209
|
def add_transcoding(ap):
|
@@ -1399,7 +1414,7 @@ def run_argparse(
|
|
1399
1414
|
k2 = "help_" + k.replace("-", "_")
|
1400
1415
|
if vars(ret)[k2]:
|
1401
1416
|
lprint("# %s help page (%s)" % (k, h))
|
1402
|
-
lprint(t + "\033[0m")
|
1417
|
+
lprint(t.rstrip() + "\033[0m")
|
1403
1418
|
sys.exit(0)
|
1404
1419
|
|
1405
1420
|
return ret
|
@@ -1438,9 +1453,19 @@ def main(argv = None, rsrc = None) :
|
|
1438
1453
|
showlic()
|
1439
1454
|
sys.exit(0)
|
1440
1455
|
|
1456
|
+
if "--mimes" in argv:
|
1457
|
+
print("\n".join("%8s %s" % (k, v) for k, v in sorted(MIMES.items())))
|
1458
|
+
sys.exit(0)
|
1459
|
+
|
1441
1460
|
if EXE:
|
1442
1461
|
print("pybin: {}\n".format(pybin), end="")
|
1443
1462
|
|
1463
|
+
for n, zs in enumerate(argv):
|
1464
|
+
if zs.startswith("--sfx-tpoke="):
|
1465
|
+
Daemon(sfx_tpoke, "sfx-tpoke", (zs.split("=", 1)[1],))
|
1466
|
+
argv.pop(n)
|
1467
|
+
break
|
1468
|
+
|
1444
1469
|
ensure_locale()
|
1445
1470
|
|
1446
1471
|
ensure_webdeps()
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -17,7 +17,9 @@ from .bos import bos
|
|
17
17
|
from .cfg import flagdescs, permdescs, vf_bmap, vf_cmap, vf_vmap
|
18
18
|
from .pwhash import PWHash
|
19
19
|
from .util import (
|
20
|
+
EXTS,
|
20
21
|
IMPLICATIONS,
|
22
|
+
MIMES,
|
21
23
|
SQLITE_VER,
|
22
24
|
UNPLICATIONS,
|
23
25
|
UTC,
|
@@ -2058,6 +2060,13 @@ class AuthSrv(object):
|
|
2058
2060
|
|
2059
2061
|
self.re_pwd = re.compile(zs)
|
2060
2062
|
|
2063
|
+
# to ensure it propagates into tcpsrv with mp on
|
2064
|
+
if self.args.mime:
|
2065
|
+
for zs in self.args.mime:
|
2066
|
+
ext, mime = zs.split("=", 1)
|
2067
|
+
MIMES[ext] = mime
|
2068
|
+
EXTS.update({v: k for k, v in MIMES.items()})
|
2069
|
+
|
2061
2070
|
def setup_pwhash(self, acct ) :
|
2062
2071
|
self.ah = PWHash(self.args)
|
2063
2072
|
if not self.ah.on:
|
copyparty/broker_mp.py
CHANGED
@@ -53,11 +53,8 @@ class BrokerMp(object):
|
|
53
53
|
def shutdown(self) :
|
54
54
|
self.log("broker", "shutting down")
|
55
55
|
for n, proc in enumerate(self.procs):
|
56
|
-
|
57
|
-
|
58
|
-
name="mp-shutdown-{}-{}".format(n, len(self.procs)),
|
59
|
-
)
|
60
|
-
thr.start()
|
56
|
+
name = "mp-shut-%d-%d" % (n, len(self.procs))
|
57
|
+
Daemon(proc.q_pend.put, name, ((0, "shutdown", []),))
|
61
58
|
|
62
59
|
with self.mutex:
|
63
60
|
procs = self.procs
|
copyparty/cfg.py
CHANGED
@@ -190,6 +190,7 @@ flagcats = {
|
|
190
190
|
"dvthumb": "disables video thumbnails",
|
191
191
|
"dathumb": "disables audio thumbnails (spectrograms)",
|
192
192
|
"dithumb": "disables image thumbnails",
|
193
|
+
"pngquant": "compress audio waveforms 33% better",
|
193
194
|
"thsize": "thumbnail res; WxH",
|
194
195
|
"crop": "center-cropping (y/n/fy/fn)",
|
195
196
|
"th3x": "3x resolution (y/n/fy/fn)",
|
copyparty/httpcli.py
CHANGED
@@ -3409,7 +3409,7 @@ class HttpCli(object):
|
|
3409
3409
|
# for f in fgen: print(repr({k: f[k] for k in ["vp", "ap"]}))
|
3410
3410
|
cfmt = ""
|
3411
3411
|
if self.thumbcli and not self.args.no_bacode:
|
3412
|
-
for zs in ("opus", "mp3", "w", "j"):
|
3412
|
+
for zs in ("opus", "mp3", "w", "j", "p"):
|
3413
3413
|
if zs in self.ouparam or uarg == zs:
|
3414
3414
|
cfmt = zs
|
3415
3415
|
|
@@ -4800,7 +4800,7 @@ class HttpCli(object):
|
|
4800
4800
|
query = "th=%s&cache" % (fmt,)
|
4801
4801
|
query = ub64enc(query.encode("utf-8")).decode("utf-8")
|
4802
4802
|
# discord looks at file extension, not content-type...
|
4803
|
-
query += "/
|
4803
|
+
query += "/th.jpg" if "j" in fmt else "/th.webp"
|
4804
4804
|
j2a["og_thumb"] = "%s/.uqe/%s" % (th_base, query)
|
4805
4805
|
|
4806
4806
|
j2a["og_fn"] = og_fn
|
@@ -4808,9 +4808,7 @@ class HttpCli(object):
|
|
4808
4808
|
if og_fn:
|
4809
4809
|
og_fn_q = quotep(og_fn)
|
4810
4810
|
query = ub64enc(b"raw").decode("utf-8")
|
4811
|
-
|
4812
|
-
query += "/a.%s" % (og_fn.split(".")[-1])
|
4813
|
-
|
4811
|
+
query += "/%s" % (og_fn_q,)
|
4814
4812
|
j2a["og_url"] = ujoin(url_base, og_fn_q)
|
4815
4813
|
j2a["og_raw"] = j2a["og_url"] + "/.uqe/" + query
|
4816
4814
|
else:
|
copyparty/httpsrv.py
CHANGED
@@ -262,10 +262,7 @@ class HttpSrv(object):
|
|
262
262
|
msg = "subscribed @ {}:{} f{} p{}".format(hip, port, fno, os.getpid())
|
263
263
|
self.log(self.name, msg)
|
264
264
|
|
265
|
-
|
266
|
-
self.broker.say("cb_httpsrv_up")
|
267
|
-
|
268
|
-
threading.Thread(target=fun, name="sig-hsrv-up1").start()
|
265
|
+
Daemon(self.broker.say, "sig-hsrv-up1", ("cb_httpsrv_up",))
|
269
266
|
|
270
267
|
while not self.stopping:
|
271
268
|
if self.args.log_conn:
|
copyparty/mtag.py
CHANGED
@@ -7,12 +7,15 @@ import os
|
|
7
7
|
import shutil
|
8
8
|
import subprocess as sp
|
9
9
|
import sys
|
10
|
+
import tempfile
|
10
11
|
|
11
12
|
from .__init__ import ANYWIN, EXE, PY2, WINDOWS, E, unicode
|
13
|
+
from .authsrv import VFS
|
12
14
|
from .bos import bos
|
13
15
|
from .util import (
|
14
16
|
FFMPEG_URL,
|
15
17
|
REKOBO_LKEY,
|
18
|
+
VF_CAREFUL,
|
16
19
|
fsenc,
|
17
20
|
min_ex,
|
18
21
|
pybin,
|
@@ -20,6 +23,7 @@ from .util import (
|
|
20
23
|
runcmd,
|
21
24
|
sfsenc,
|
22
25
|
uncyg,
|
26
|
+
wunlink,
|
23
27
|
)
|
24
28
|
|
25
29
|
def have_ff(scmd ) :
|
@@ -101,6 +105,51 @@ class MParser(object):
|
|
101
105
|
raise Exception()
|
102
106
|
|
103
107
|
|
108
|
+
def au_unpk(log , fmt_map , abspath , vn = None) :
|
109
|
+
ret = ""
|
110
|
+
try:
|
111
|
+
ext = abspath.split(".")[-1].lower()
|
112
|
+
au, pk = fmt_map[ext].split(".")
|
113
|
+
|
114
|
+
fd, ret = tempfile.mkstemp("." + au)
|
115
|
+
|
116
|
+
if pk == "gz":
|
117
|
+
import gzip
|
118
|
+
|
119
|
+
fi = gzip.GzipFile(abspath, mode="rb")
|
120
|
+
|
121
|
+
elif pk == "xz":
|
122
|
+
import lzma
|
123
|
+
|
124
|
+
fi = lzma.open(abspath, "rb")
|
125
|
+
|
126
|
+
elif pk == "zip":
|
127
|
+
import zipfile
|
128
|
+
|
129
|
+
zf = zipfile.ZipFile(abspath, "r")
|
130
|
+
zil = zf.infolist()
|
131
|
+
zil = [x for x in zil if x.filename.lower().split(".")[-1] == au]
|
132
|
+
fi = zf.open(zil[0])
|
133
|
+
|
134
|
+
with os.fdopen(fd, "wb") as fo:
|
135
|
+
while True:
|
136
|
+
buf = fi.read(32768)
|
137
|
+
if not buf:
|
138
|
+
break
|
139
|
+
|
140
|
+
fo.write(buf)
|
141
|
+
|
142
|
+
return ret
|
143
|
+
|
144
|
+
except Exception as ex:
|
145
|
+
if ret:
|
146
|
+
t = "failed to decompress audio file [%s]: %r"
|
147
|
+
log(t % (abspath, ex))
|
148
|
+
wunlink(log, ret, vn.flags if vn else VF_CAREFUL)
|
149
|
+
|
150
|
+
return abspath
|
151
|
+
|
152
|
+
|
104
153
|
def ffprobe(
|
105
154
|
abspath , timeout = 60
|
106
155
|
) :
|
@@ -275,7 +324,7 @@ class MTag(object):
|
|
275
324
|
or_ffprobe = " or FFprobe"
|
276
325
|
|
277
326
|
if self.backend == "mutagen":
|
278
|
-
self.
|
327
|
+
self._get = self.get_mutagen
|
279
328
|
try:
|
280
329
|
from mutagen import version # noqa: F401
|
281
330
|
except:
|
@@ -284,7 +333,7 @@ class MTag(object):
|
|
284
333
|
|
285
334
|
if self.backend == "ffprobe":
|
286
335
|
self.usable = self.can_ffprobe
|
287
|
-
self.
|
336
|
+
self._get = self.get_ffprobe
|
288
337
|
self.prefer_mt = True
|
289
338
|
|
290
339
|
if not HAVE_FFPROBE:
|
@@ -454,6 +503,17 @@ class MTag(object):
|
|
454
503
|
|
455
504
|
return r1
|
456
505
|
|
506
|
+
def get(self, abspath ) :
|
507
|
+
ext = abspath.split(".")[-1].lower()
|
508
|
+
if ext not in self.args.au_unpk:
|
509
|
+
return self._get(abspath)
|
510
|
+
|
511
|
+
ap = au_unpk(self.log, self.args.au_unpk, abspath)
|
512
|
+
ret = self._get(ap)
|
513
|
+
if ap != abspath:
|
514
|
+
wunlink(self.log, ap, VF_CAREFUL)
|
515
|
+
return ret
|
516
|
+
|
457
517
|
def get_mutagen(self, abspath ) :
|
458
518
|
ret = {}
|
459
519
|
|
@@ -547,10 +607,16 @@ class MTag(object):
|
|
547
607
|
except:
|
548
608
|
raise # might be expected outside cpython
|
549
609
|
|
610
|
+
ext = abspath.split(".")[-1].lower()
|
611
|
+
if ext in self.args.au_unpk:
|
612
|
+
ap = au_unpk(self.log, self.args.au_unpk, abspath)
|
613
|
+
else:
|
614
|
+
ap = abspath
|
615
|
+
|
550
616
|
ret = {}
|
551
617
|
for tagname, parser in sorted(parsers.items(), key=lambda x: (x[1].pri, x[0])):
|
552
618
|
try:
|
553
|
-
cmd = [parser.bin,
|
619
|
+
cmd = [parser.bin, ap]
|
554
620
|
if parser.bin.endswith(".py"):
|
555
621
|
cmd = [pybin] + cmd
|
556
622
|
|
@@ -587,4 +653,7 @@ class MTag(object):
|
|
587
653
|
t = "mtag error: tagname {}, parser {}, file {} => {}"
|
588
654
|
self.log(t.format(tagname, parser.bin, abspath, min_ex()))
|
589
655
|
|
656
|
+
if ap != abspath:
|
657
|
+
wunlink(self.log, ap, VF_CAREFUL)
|
658
|
+
|
590
659
|
return ret
|
copyparty/smbd.py
CHANGED
copyparty/svchub.py
CHANGED
@@ -234,6 +234,10 @@ class SvcHub(object):
|
|
234
234
|
if not HAVE_FFMPEG or not HAVE_FFPROBE:
|
235
235
|
decs.pop("ff", None)
|
236
236
|
|
237
|
+
# compressed formats; "s3z=s3m.zip, s3gz=s3m.gz, ..."
|
238
|
+
zlss = [x.strip().lower().split("=", 1) for x in args.au_unpk.split(",")]
|
239
|
+
args.au_unpk = {x[0]: x[1] for x in zlss}
|
240
|
+
|
237
241
|
self.args.th_dec = list(decs.keys())
|
238
242
|
self.thumbsrv = None
|
239
243
|
want_ff = False
|
@@ -274,6 +278,8 @@ class SvcHub(object):
|
|
274
278
|
if not re.match("^(0|[qv][0-9]|[0-9]{2,3}k)$", args.q_mp3.lower()):
|
275
279
|
t = "invalid mp3 transcoding quality [%s] specified; only supports [0] to disable, a CBR value such as [192k], or a CQ/CRF value such as [v2]"
|
276
280
|
raise Exception(t % (args.q_mp3,))
|
281
|
+
else:
|
282
|
+
args.au_unpk = {}
|
277
283
|
|
278
284
|
args.th_poke = min(args.th_poke, args.th_maxage, args.ac_maxage)
|
279
285
|
|
@@ -287,13 +293,14 @@ class SvcHub(object):
|
|
287
293
|
from .ftpd import Ftpd
|
288
294
|
|
289
295
|
self.ftpd = None
|
290
|
-
Daemon(self.start_ftpd, "start_ftpd")
|
291
296
|
zms += "f" if args.ftp else "F"
|
292
297
|
|
293
298
|
if args.tftp:
|
294
299
|
from .tftpd import Tftpd
|
295
300
|
|
296
301
|
self.tftpd = None
|
302
|
+
|
303
|
+
if args.ftp or args.ftps or args.tftp:
|
297
304
|
Daemon(self.start_ftpd, "start_tftpd")
|
298
305
|
|
299
306
|
if args.smb:
|
@@ -382,7 +389,7 @@ class SvcHub(object):
|
|
382
389
|
self.sigterm()
|
383
390
|
|
384
391
|
def sigterm(self) :
|
385
|
-
|
392
|
+
self.signal_handler(signal.SIGTERM, None)
|
386
393
|
|
387
394
|
def cb_httpsrv_up(self) :
|
388
395
|
self.httpsrv_up += 1
|
copyparty/th_cli.py
CHANGED
@@ -103,6 +103,11 @@ class ThumbCli(object):
|
|
103
103
|
sfmt += "3" if "3" in fmt else ""
|
104
104
|
|
105
105
|
fmt = sfmt
|
106
|
+
|
107
|
+
elif fmt[:1] == "p" and not is_au:
|
108
|
+
t = "cannot thumbnail [%s]: png only allowed for waveforms"
|
109
|
+
self.log(t % (rem), 6)
|
110
|
+
return None
|
106
111
|
|
107
112
|
histpath = self.asrv.vfs.histtab.get(ptop)
|
108
113
|
if not histpath:
|
copyparty/th_srv.py
CHANGED
@@ -15,7 +15,7 @@ from queue import Queue
|
|
15
15
|
from .__init__ import ANYWIN, TYPE_CHECKING
|
16
16
|
from .authsrv import VFS
|
17
17
|
from .bos import bos
|
18
|
-
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, ffprobe
|
18
|
+
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, au_unpk, ffprobe
|
19
19
|
from .util import BytesIO # type: ignore
|
20
20
|
from .util import (
|
21
21
|
FFMPEG_URL,
|
@@ -294,6 +294,12 @@ class ThumbSrv(object):
|
|
294
294
|
ext = abspath.split(".")[-1].lower()
|
295
295
|
png_ok = False
|
296
296
|
funs = []
|
297
|
+
|
298
|
+
if ext in self.args.au_unpk:
|
299
|
+
ap_unpk = au_unpk(self.log, self.args.au_unpk, abspath, vn)
|
300
|
+
else:
|
301
|
+
ap_unpk = abspath
|
302
|
+
|
297
303
|
if not bos.path.exists(tpath):
|
298
304
|
for lib in self.args.th_dec:
|
299
305
|
if lib == "pil" and ext in self.fmt_pil:
|
@@ -313,9 +319,6 @@ class ThumbSrv(object):
|
|
313
319
|
else:
|
314
320
|
funs.append(self.conv_spec)
|
315
321
|
|
316
|
-
if not png_ok and tpath.endswith(".png"):
|
317
|
-
raise Pebkac(400, "png only allowed for waveforms")
|
318
|
-
|
319
322
|
tdir, tfn = os.path.split(tpath)
|
320
323
|
ttpath = os.path.join(tdir, "w", tfn)
|
321
324
|
try:
|
@@ -325,7 +328,10 @@ class ThumbSrv(object):
|
|
325
328
|
|
326
329
|
for fun in funs:
|
327
330
|
try:
|
328
|
-
|
331
|
+
if not png_ok and tpath.endswith(".png"):
|
332
|
+
raise Exception("png only allowed for waveforms")
|
333
|
+
|
334
|
+
fun(ap_unpk, ttpath, fmt, vn)
|
329
335
|
break
|
330
336
|
except Exception as ex:
|
331
337
|
msg = "{} could not create thumbnail of {}\n{}"
|
@@ -343,6 +349,9 @@ class ThumbSrv(object):
|
|
343
349
|
except:
|
344
350
|
pass
|
345
351
|
|
352
|
+
if abspath != ap_unpk:
|
353
|
+
wunlink(self.log, ap_unpk, vn.flags)
|
354
|
+
|
346
355
|
try:
|
347
356
|
wrename(self.log, ttpath, tpath, vn.flags)
|
348
357
|
except:
|
@@ -581,6 +590,24 @@ class ThumbSrv(object):
|
|
581
590
|
cmd += [fsenc(tpath)]
|
582
591
|
self._run_ff(cmd, vn)
|
583
592
|
|
593
|
+
if "pngquant" in vn.flags:
|
594
|
+
wtpath = tpath + ".png"
|
595
|
+
cmd = [
|
596
|
+
b"pngquant",
|
597
|
+
b"--strip",
|
598
|
+
b"--nofs",
|
599
|
+
b"--output", fsenc(wtpath),
|
600
|
+
fsenc(tpath)
|
601
|
+
]
|
602
|
+
ret = runcmd(cmd, timeout=vn.flags["convt"], nice=True, oom=400)[0]
|
603
|
+
if ret:
|
604
|
+
try:
|
605
|
+
wunlink(self.log, wtpath, vn.flags)
|
606
|
+
except:
|
607
|
+
pass
|
608
|
+
else:
|
609
|
+
wrename(self.log, wtpath, tpath, vn.flags)
|
610
|
+
|
584
611
|
def conv_spec(self, abspath , tpath , fmt , vn ) :
|
585
612
|
ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
586
613
|
if "ac" not in ret:
|
copyparty/up2k.py
CHANGED
@@ -10,7 +10,6 @@ import math
|
|
10
10
|
import os
|
11
11
|
import re
|
12
12
|
import shutil
|
13
|
-
import signal
|
14
13
|
import stat
|
15
14
|
import subprocess as sp
|
16
15
|
import tempfile
|
@@ -29,6 +28,7 @@ from .fsutil import Fstab
|
|
29
28
|
from .mtag import MParser, MTag
|
30
29
|
from .util import (
|
31
30
|
HAVE_SQLITE3,
|
31
|
+
VF_CAREFUL,
|
32
32
|
SYMTIME,
|
33
33
|
Daemon,
|
34
34
|
MTHash,
|
@@ -88,9 +88,6 @@ CV_EXTS = set(zsg.split(","))
|
|
88
88
|
HINT_HISTPATH = "you could try moving the database to another location (preferably an SSD or NVME drive) using either the --hist argument (global option for all volumes), or the hist volflag (just for this volume)"
|
89
89
|
|
90
90
|
|
91
|
-
VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
|
92
|
-
|
93
|
-
|
94
91
|
class Dbw(object):
|
95
92
|
def __init__(self, c , n , t ) :
|
96
93
|
self.c = c
|
@@ -458,7 +455,13 @@ class Up2k(object):
|
|
458
455
|
# important; not deferred by db_act
|
459
456
|
timeout = self._check_lifetimes()
|
460
457
|
|
461
|
-
|
458
|
+
try:
|
459
|
+
timeout = min(timeout, now + self._check_xiu())
|
460
|
+
except Exception as ex:
|
461
|
+
if "closed cursor" in str(ex):
|
462
|
+
self.log("sched_rescan: lost db")
|
463
|
+
return
|
464
|
+
raise
|
462
465
|
|
463
466
|
with self.mutex:
|
464
467
|
for vp, vol in sorted(self.asrv.vfs.all_vols.items()):
|
@@ -1036,8 +1039,11 @@ class Up2k(object):
|
|
1036
1039
|
return None
|
1037
1040
|
|
1038
1041
|
def _verify_db_cache(self, cur , vpath ) :
|
1039
|
-
# check if
|
1040
|
-
|
1042
|
+
# check if list of intersecting volumes changed since last use; drop caches if so
|
1043
|
+
prefix = (vpath + "/").lstrip("/")
|
1044
|
+
zsl = [x for x in self.asrv.vfs.all_vols if x.startswith(prefix)]
|
1045
|
+
zsl = [x[len(prefix) :] for x in zsl]
|
1046
|
+
zsl.sort()
|
1041
1047
|
zb = hashlib.sha1("\n".join(zsl).encode("utf-8", "replace")).digest()
|
1042
1048
|
vcfg = base64.urlsafe_b64encode(zb[:18]).decode("ascii")
|
1043
1049
|
|
@@ -1647,7 +1653,7 @@ class Up2k(object):
|
|
1647
1653
|
|
1648
1654
|
if e2vp and rewark:
|
1649
1655
|
self.hub.retcode = 1
|
1650
|
-
|
1656
|
+
Daemon(self.hub.sigterm)
|
1651
1657
|
raise Exception("{} files have incorrect hashes".format(len(rewark)))
|
1652
1658
|
|
1653
1659
|
if not e2vu or not rewark:
|
copyparty/util.py
CHANGED
@@ -337,6 +337,9 @@ APPLESAN_TXT = r"/(__MACOS|Icon\r\r)|/\.(_|DS_Store|AppleDouble|LSOverride|Docum
|
|
337
337
|
APPLESAN_RE = re.compile(APPLESAN_TXT)
|
338
338
|
|
339
339
|
|
340
|
+
VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
|
341
|
+
|
342
|
+
|
340
343
|
pybin = sys.executable or ""
|
341
344
|
if EXE:
|
342
345
|
pybin = ""
|
@@ -442,13 +445,22 @@ class Daemon(threading.Thread):
|
|
442
445
|
r = True,
|
443
446
|
ka = None,
|
444
447
|
) :
|
445
|
-
threading.Thread.__init__(
|
446
|
-
|
447
|
-
|
448
|
+
threading.Thread.__init__(self, name=name)
|
449
|
+
self.a = a or ()
|
450
|
+
self.ka = ka or {}
|
451
|
+
self.fun = target
|
448
452
|
self.daemon = True
|
449
453
|
if r:
|
450
454
|
self.start()
|
451
455
|
|
456
|
+
def run(self):
|
457
|
+
if not ANYWIN and not PY2:
|
458
|
+
signal.pthread_sigmask(
|
459
|
+
signal.SIG_BLOCK, [signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]
|
460
|
+
)
|
461
|
+
|
462
|
+
self.fun(*self.a, **self.ka)
|
463
|
+
|
452
464
|
|
453
465
|
class Netdev(object):
|
454
466
|
def __init__(self, ip , idx , name , desc ):
|
@@ -843,6 +855,7 @@ class ProgressPrinter(threading.Thread):
|
|
843
855
|
self.start()
|
844
856
|
|
845
857
|
def run(self) :
|
858
|
+
sigblock()
|
846
859
|
tp = 0
|
847
860
|
msg = None
|
848
861
|
no_stdout = self.args.q
|
@@ -1287,6 +1300,15 @@ def log_thrs(log , ival , name ) :
|
|
1287
1300
|
log(name, "\033[0m \033[33m".join(tv), 3)
|
1288
1301
|
|
1289
1302
|
|
1303
|
+
def sigblock():
|
1304
|
+
if ANYWIN or PY2:
|
1305
|
+
return
|
1306
|
+
|
1307
|
+
signal.pthread_sigmask(
|
1308
|
+
signal.SIG_BLOCK, [signal.SIGINT, signal.SIGTERM, signal.SIGUSR1]
|
1309
|
+
)
|
1310
|
+
|
1311
|
+
|
1290
1312
|
def vol_san(vols , txt ) :
|
1291
1313
|
txt0 = txt
|
1292
1314
|
for vol in vols:
|
@@ -1308,10 +1330,11 @@ def vol_san(vols , txt ) :
|
|
1308
1330
|
|
1309
1331
|
def min_ex(max_lines = 8, reverse = False) :
|
1310
1332
|
et, ev, tb = sys.exc_info()
|
1311
|
-
stb = traceback.extract_tb(tb)
|
1333
|
+
stb = traceback.extract_tb(tb) if tb else traceback.extract_stack()[:-1]
|
1312
1334
|
fmt = "%s @ %d <%s>: %s"
|
1313
1335
|
ex = [fmt % (fp.split(os.sep)[-1], ln, fun, txt) for fp, ln, fun, txt in stb]
|
1314
|
-
|
1336
|
+
if et or ev or tb:
|
1337
|
+
ex.append("[%s] %s" % (et.__name__ if et else "(anonymous)", ev))
|
1315
1338
|
return "\n".join(ex[-max_lines:][:: -1 if reverse else 1])
|
1316
1339
|
|
1317
1340
|
|
@@ -2660,7 +2683,7 @@ def unescape_cookie(orig ) :
|
|
2660
2683
|
|
2661
2684
|
def guess_mime(url , fallback = "application/octet-stream") :
|
2662
2685
|
try:
|
2663
|
-
|
2686
|
+
ext = url.rsplit(".", 1)[1].lower()
|
2664
2687
|
except:
|
2665
2688
|
return fallback
|
2666
2689
|
|
copyparty/web/a/u2c.py
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
#!/usr/bin/env python3
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
S_VERSION = "1.
|
5
|
-
S_BUILD_DT = "2024-
|
4
|
+
S_VERSION = "1.17"
|
5
|
+
S_BUILD_DT = "2024-05-09"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -79,12 +79,21 @@ req_ses = requests.Session()
|
|
79
79
|
|
80
80
|
|
81
81
|
class Daemon(threading.Thread):
|
82
|
-
def __init__(self, target, name=None, a=None):
|
83
|
-
|
84
|
-
|
82
|
+
def __init__(self, target, name = None, a = None):
|
83
|
+
threading.Thread.__init__(self, name=name)
|
84
|
+
self.a = a or ()
|
85
|
+
self.fun = target
|
85
86
|
self.daemon = True
|
86
87
|
self.start()
|
87
88
|
|
89
|
+
def run(self):
|
90
|
+
try:
|
91
|
+
signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGINT, signal.SIGTERM])
|
92
|
+
except:
|
93
|
+
pass
|
94
|
+
|
95
|
+
self.fun(*self.a)
|
96
|
+
|
88
97
|
|
89
98
|
class File(object):
|
90
99
|
"""an up2k upload task; represents a single file"""
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/deps/marked.js.gz
CHANGED
Binary file
|
copyparty/web/splash.js.gz
CHANGED
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.13.
|
3
|
+
Version: 1.13.2
|
4
4
|
Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
|
5
5
|
Author-email: ed <copyparty@ocv.me>
|
6
6
|
License: MIT
|
@@ -284,6 +284,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
284
284
|
* ☑ ...of videos using FFmpeg
|
285
285
|
* ☑ ...of audio (spectrograms) using FFmpeg
|
286
286
|
* ☑ cache eviction (max-age; maybe max-size eventually)
|
287
|
+
* ☑ multilingual UI (english, norwegian, [add your own](./docs/rice/#translations)))
|
287
288
|
* ☑ SPA (browse while uploading)
|
288
289
|
* server indexing
|
289
290
|
* ☑ [locate files by contents](#file-search)
|
@@ -466,7 +467,7 @@ configuring accounts/volumes with arguments:
|
|
466
467
|
`-v .::r,usr1,usr2:rw,usr3,usr4` = usr1/2 read-only, 3/4 read-write
|
467
468
|
|
468
469
|
permissions:
|
469
|
-
* `r` (read): browse folder contents, download files, download as zip/tar
|
470
|
+
* `r` (read): browse folder contents, download files, download as zip/tar, see filekeys/dirkeys
|
470
471
|
* `w` (write): upload files, move files *into* this folder
|
471
472
|
* `m` (move): move files/folders *from* this folder
|
472
473
|
* `d` (delete): delete files/folders
|
@@ -668,7 +669,7 @@ you can also zip a selection of files or folders by clicking them in the browser
|
|
668
669
|
|
669
670
|
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
|
670
671
|
* 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
|
671
|
-
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images
|
672
|
+
* and url-params `&j` / `&w` produce jpeg/webm thumbnails/spectrograms instead of the original audio/video/images (`&p` for audio waveforms)
|
672
673
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
673
674
|
|
674
675
|
|
@@ -964,6 +965,8 @@ using arguments or config files, or a mix of both:
|
|
964
965
|
|
965
966
|
**NB:** as humongous as this readme is, there is also a lot of undocumented features. Run copyparty with `--help` to see all available global options; all of those can be used in the `[global]` section of config files, and everything listed in `--help-flags` can be used in volumes as volflags.
|
966
967
|
* if running in docker/podman, try this: `docker run --rm -it copyparty/ac --help`
|
968
|
+
* or see this (probably outdated): https://ocv.me/copyparty/helptext.html
|
969
|
+
* or if you prefer plaintext, https://ocv.me/copyparty/helptext.txt
|
967
970
|
|
968
971
|
|
969
972
|
## zeroconf
|
@@ -1140,7 +1143,7 @@ tweaking the ui
|
|
1140
1143
|
* to sort in music order (album, track, artist, title) with filename as fallback, you could `--sort tags/Cirle,tags/.tn,tags/Artist,tags/Title,href`
|
1141
1144
|
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
1142
1145
|
|
1143
|
-
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag
|
1146
|
+
see [./docs/rice](./docs/rice) for more, including how to add stuff (css/`<meta>`/...) to the html `<head>` tag, or to add your own translation
|
1144
1147
|
|
1145
1148
|
|
1146
1149
|
## opengraph
|
@@ -1,38 +1,38 @@
|
|
1
1
|
copyparty/__init__.py,sha256=fUINM1abqDGzCCH_JcXdOnLdKOV-SrTI2Xo2QgQW2P4,1703
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
5
|
-
copyparty/broker_mp.py,sha256=
|
2
|
+
copyparty/__main__.py,sha256=eHd9z3x3VWKFULKcb37iBuWCUbYDRokq1UFjGHI5njU,99846
|
3
|
+
copyparty/__version__.py,sha256=HXaSfRCwDZ1gm9Ow7Po9NDC2KxGntKPiZkjTR_ujvpM,255
|
4
|
+
copyparty/authsrv.py,sha256=4YPt9_VqqcDAdaur4JN809jKUlpAyamVe-1JaeMUkOQ,85177
|
5
|
+
copyparty/broker_mp.py,sha256=YFe1S6Zziht8Qc__dCLj_ff8z0DDny9lqk_Mi5ajsJk,3868
|
6
6
|
copyparty/broker_mpw.py,sha256=4ZI7bJYOwUibeAJVv9_FPGNmHrr9eOtkj_Kz0JEppTU,3197
|
7
7
|
copyparty/broker_thr.py,sha256=eKr--HJGig5zqvNGwH9UoBG9Nvi9mT2axrRmJwknd0s,1759
|
8
8
|
copyparty/broker_util.py,sha256=CnX_LAhQQqouONcDLtVkVlcBX3Z6pWuKDQDmmbHGEg4,1489
|
9
9
|
copyparty/cert.py,sha256=nCeDdzcCpvjPPUcxT4Oh7wvL_8zvddu4oXtbA-zOb8g,7607
|
10
|
-
copyparty/cfg.py,sha256=
|
10
|
+
copyparty/cfg.py,sha256=gdsFudDxliRNwYm1YdImO5miWzyDQ2i1vHRMkokxCm0,9643
|
11
11
|
copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
|
12
12
|
copyparty/fsutil.py,sha256=NEdhYYgQxDQ7MmgTbtjMKorikCjDls2AXVX16EH2JfQ,4613
|
13
13
|
copyparty/ftpd.py,sha256=OIExjfqOEw-Y_ygez6cIZUQec4SFOmoxEH_WOVvw-aE,15961
|
14
|
-
copyparty/httpcli.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=wif37Oa89iAer5sIMoZPWChyWif80AFH7lOaG00h2z0,164293
|
15
15
|
copyparty/httpconn.py,sha256=6MOQgBtOGrlVRr6ZiHBKYzkzcls-YWwaWEtqE6DweM0,6873
|
16
|
-
copyparty/httpsrv.py,sha256=
|
16
|
+
copyparty/httpsrv.py,sha256=RpROXBJPgTXmwFbLYrAT15ovGYkIMrksluuetKWAJTM,16356
|
17
17
|
copyparty/ico.py,sha256=AYHdK6NlYBfBgafVYXia3jHQ9XHZdUL1D8WftLMAzIU,3545
|
18
18
|
copyparty/mdns.py,sha256=CcraggbDxTT1ntYzD8Ebgqmw5Q4HkyZcfh5ymtCV_ak,17469
|
19
19
|
copyparty/metrics.py,sha256=O8qiPNDxNjub_PI8C8Qu9rBQ_z0J1mnKonqkcTeAtf4,8845
|
20
|
-
copyparty/mtag.py,sha256=
|
20
|
+
copyparty/mtag.py,sha256=MpRkwAj_OAhE9alRzYMyoyPUtedSIuBmVxhCkLaIpMA,18593
|
21
21
|
copyparty/multicast.py,sha256=Ha27l2oATEa-Qo2WOzkeRgjAm6G_YDCfbVJWR-ao2UE,12319
|
22
22
|
copyparty/pwhash.py,sha256=D82y8emnwpHDQq7Cr8lNuppHshbNA9ptcR2XsGOOk6E,3937
|
23
|
-
copyparty/smbd.py,sha256=
|
23
|
+
copyparty/smbd.py,sha256=CwsjLzwfIkqY9Fr_w7po_giO2tnXq9_7bdjIBNdiuTY,14062
|
24
24
|
copyparty/ssdp.py,sha256=H6ZftXttydcnBxcg2-Prm4P-XiybgT3xiJRUXU1pbrE,6343
|
25
25
|
copyparty/star.py,sha256=K4NuzyfT4956uoW6GJSQ2II-JsSV57apQZwRZ4mjFoo,3790
|
26
26
|
copyparty/sutil.py,sha256=_G4TM0YFa1vXzhRypHJ88QBdZWtYgDbom4CZjGvGIwc,3074
|
27
|
-
copyparty/svchub.py,sha256=
|
27
|
+
copyparty/svchub.py,sha256=v81cj-KQ3P7pLcV4sOWEjJSpGdjseZ2tpqL4VruPtmI,32661
|
28
28
|
copyparty/szip.py,sha256=631TsEwGKV22yAnusJtvE-9fGFWr61HPGBinu-jk1QA,8591
|
29
29
|
copyparty/tcpsrv.py,sha256=ym6rda7svl_M4DjNesHMI1_6wO7Csu01UV1zGzXEMxI,17637
|
30
30
|
copyparty/tftpd.py,sha256=7EHAZ9LnjAXupwRNIENJ2eA8Q0lFynnwwbziV3fyzns,13157
|
31
|
-
copyparty/th_cli.py,sha256=
|
32
|
-
copyparty/th_srv.py,sha256=
|
31
|
+
copyparty/th_cli.py,sha256=VO2Eo0SGwgSJaHowMLeX3_vxEdQcQh5RFDSf0OraTTw,4568
|
32
|
+
copyparty/th_srv.py,sha256=utK8kA1mlYI0BsAdLL-l0-51gXoIN0BS5zQkGAcERXg,28041
|
33
33
|
copyparty/u2idx.py,sha256=uEUcEbye1jzGlQfEJkLtD060XA6Rv_6lXLgeg6oAU5M,13033
|
34
|
-
copyparty/up2k.py,sha256=
|
35
|
-
copyparty/util.py,sha256=
|
34
|
+
copyparty/up2k.py,sha256=hhh7PrUzRgnlvsapwjG1-X6_bqI51r3Tf5zo4jLvveU,143330
|
35
|
+
copyparty/util.py,sha256=w22CaPQy0Otq8sJMt9hCPpRbKM2sRLTQtBYAE6DTaHQ,83744
|
36
36
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
37
37
|
copyparty/bos/bos.py,sha256=Wb7eWsXJgR5AFlBR9ZOyKrLTwy-Kct9RrGiOu4Jo37Y,1622
|
38
38
|
copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
|
@@ -57,7 +57,7 @@ copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8
|
|
57
57
|
copyparty/web/baguettebox.js.gz,sha256=HdRHC_4Lvepp1DrRwusdcxvAn8IKGMdrKdggGIshKek,7869
|
58
58
|
copyparty/web/browser.css.gz,sha256=GGyPK9BBOX63x9XWqO2jrXewHtfAeZ-Jo0BBxqTOGUM,11491
|
59
59
|
copyparty/web/browser.html,sha256=-tLasq2GKe9mUceqXG4PczQ7odBMrX0qlWuyaA9SjPI,4882
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=Lci32Xx_OxmC9bjEuiQSzfMrb8UGj9Qg5j2D7kOcFjY,68838
|
61
61
|
copyparty/web/browser2.html,sha256=ciQlgr9GWuIapdsRBFNRvRFvN5T_5n920LqDMbsj5-g,1605
|
62
62
|
copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
|
63
63
|
copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
|
@@ -73,7 +73,7 @@ copyparty/web/msg.css.gz,sha256=u90fXYAVrMD-jqwf5XFVC1ptSpSHZUe8Mez6PX101P8,300
|
|
73
73
|
copyparty/web/msg.html,sha256=HcBeXXpcF2JKwcj8KD3dGCvONMnTZ6lXYmm4SYgBMlA,905
|
74
74
|
copyparty/web/splash.css.gz,sha256=zgDs-SY3VrInsXeARRPcGHziVOUs-1hUtSObzybwD1g,1006
|
75
75
|
copyparty/web/splash.html,sha256=z5OrfZqA5RBxeY86BJiQ5NZNHIIDHDvPlTuht-Q0v64,3917
|
76
|
-
copyparty/web/splash.js.gz,sha256=
|
76
|
+
copyparty/web/splash.js.gz,sha256=P4BLL_SBqfqWniq_gzUD-opVAkblAPgKDwmfxyfDB7o,1469
|
77
77
|
copyparty/web/svcs.html,sha256=Lniv3ndzV1ALGOdvMNKg6za5rafrqltuwoknYbExRxM,11711
|
78
78
|
copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
|
79
79
|
copyparty/web/ui.css.gz,sha256=skuzZHqTU0ag5hButpQmKI9wM7ro-UJ2PnpTodTWYF4,2616
|
@@ -82,7 +82,7 @@ copyparty/web/util.js.gz,sha256=eNRKtW7fM9AvipRdJGQyy9mbQIqMda73o8Bo64UWr7s,1441
|
|
82
82
|
copyparty/web/w.hash.js.gz,sha256=__hBMd5oZWfTrb8ZCJNT21isoSqyrxKE6qdaKGQVAhc,1060
|
83
83
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
84
84
|
copyparty/web/a/partyfuse.py,sha256=MuRkaSuYsdfWfBFMOkbPwDXqSvNTw3sd7QhhlKCDZ8I,32311
|
85
|
-
copyparty/web/a/u2c.py,sha256=
|
85
|
+
copyparty/web/a/u2c.py,sha256=mCVYSJo6wSiPrT_p7QxlIoIGSclcC7qw4COcIaAKS-w,38791
|
86
86
|
copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
|
87
87
|
copyparty/web/dd/2.png,sha256=gJ14XFPzaw95L6z92fSq9eMPikSQyu-03P1lgiGe0_I,258
|
88
88
|
copyparty/web/dd/3.png,sha256=4lho8Koz5tV7jJ4ODo6GMTScZfkqsT05yp48EDFIlyg,252
|
@@ -93,7 +93,7 @@ copyparty/web/deps/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
|
|
93
93
|
copyparty/web/deps/busy.mp3.gz,sha256=EVphk1_HYyRKJmtpeK99vbAstF7ub1f9ndu020H8PQ8,106
|
94
94
|
copyparty/web/deps/easymde.css.gz,sha256=vWxfueI64rPikuqFj69wJBtGisqf93AheQtOZqgUI_c,3041
|
95
95
|
copyparty/web/deps/easymde.js.gz,sha256=1FykpDM7_FiL4EeZAg4Qcggjoo4PE_MBTgRcBWvjD90,77000
|
96
|
-
copyparty/web/deps/marked.js.gz,sha256=
|
96
|
+
copyparty/web/deps/marked.js.gz,sha256=elpt4-fI9Fs5zgMYxHuQn7XL4MXMBfINU4WQ0sBF5HY,22582
|
97
97
|
copyparty/web/deps/mini-fa.css.gz,sha256=CTPrNaH8OTVmxajrGP88E2MkjadY9_81TBVnd9sw9Y8,572
|
98
98
|
copyparty/web/deps/mini-fa.woff,sha256=L9DNncV2TIyvsrspMbJouvnnt7F068Hbn7YZYvN76AU,2784
|
99
99
|
copyparty/web/deps/prism.css.gz,sha256=Z_A6rJ3MN5KWnjvXaV787aTW_5DT-xjFd0YZ7_W-Krk,1468
|
@@ -102,9 +102,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
|
|
102
102
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
103
103
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
104
104
|
copyparty/web/deps/sha512.hw.js.gz,sha256=vqoXeracj-99Z5MfY3jK2N4WiSzYQdfjy0RnUlQDhSU,8110
|
105
|
-
copyparty-1.13.
|
106
|
-
copyparty-1.13.
|
107
|
-
copyparty-1.13.
|
108
|
-
copyparty-1.13.
|
109
|
-
copyparty-1.13.
|
110
|
-
copyparty-1.13.
|
105
|
+
copyparty-1.13.2.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
106
|
+
copyparty-1.13.2.dist-info/METADATA,sha256=mqJMKOtNHic9_FIsW46owpSjsmGYFLF7pUSwjzIQZyg,122479
|
107
|
+
copyparty-1.13.2.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
108
|
+
copyparty-1.13.2.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
109
|
+
copyparty-1.13.2.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
110
|
+
copyparty-1.13.2.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|