copyparty 1.13.0__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 +55 -5
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +23 -2
- copyparty/broker_mp.py +2 -5
- copyparty/cfg.py +16 -2
- copyparty/fsutil.py +25 -5
- copyparty/httpcli.py +262 -20
- copyparty/httpsrv.py +1 -4
- copyparty/metrics.py +1 -1
- copyparty/mtag.py +72 -3
- copyparty/smbd.py +1 -1
- copyparty/svchub.py +14 -3
- copyparty/tcpsrv.py +6 -0
- copyparty/th_cli.py +5 -0
- copyparty/th_srv.py +32 -5
- copyparty/u2idx.py +18 -3
- copyparty/up2k.py +27 -9
- copyparty/util.py +41 -6
- copyparty/web/a/u2c.py +14 -5
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.html +1 -1
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/deps/marked.js.gz +0 -0
- copyparty/web/md.html +1 -1
- copyparty/web/mde.html +1 -1
- copyparty/web/msg.html +1 -1
- copyparty/web/splash.html +2 -1
- copyparty/web/splash.js.gz +0 -0
- copyparty/web/svcs.html +1 -1
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.13.0.dist-info → copyparty-1.13.2.dist-info}/METADATA +55 -8
- {copyparty-1.13.0.dist-info → copyparty-1.13.2.dist-info}/RECORD +37 -37
- {copyparty-1.13.0.dist-info → copyparty-1.13.2.dist-info}/LICENSE +0 -0
- {copyparty-1.13.0.dist-info → copyparty-1.13.2.dist-info}/WHEEL +0 -0
- {copyparty-1.13.0.dist-info → copyparty-1.13.2.dist-info}/entry_points.txt +0 -0
- {copyparty-1.13.0.dist-info → copyparty-1.13.2.dist-info}/top_level.txt +0 -0
copyparty/tcpsrv.py
CHANGED
@@ -460,6 +460,12 @@ class TcpSrv(object):
|
|
460
460
|
sys.stderr.flush()
|
461
461
|
|
462
462
|
def _qr(self, t1 , t2 ) :
|
463
|
+
t2c = {zs: zli for zs, zli in t2.items() if zs in ("127.0.0.1", "::1")}
|
464
|
+
t2b = {zs: zli for zs, zli in t2.items() if ":" in zs and zs not in t2c}
|
465
|
+
t2 = {zs: zli for zs, zli in t2.items() if zs not in t2b and zs not in t2c}
|
466
|
+
t2.update(t2b) # first ipv4, then ipv6...
|
467
|
+
t2.update(t2c) # ...and finally localhost
|
468
|
+
|
463
469
|
ip = None
|
464
470
|
ips = list(t1) + list(t2)
|
465
471
|
qri = self.args.qri
|
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/u2idx.py
CHANGED
@@ -59,6 +59,17 @@ class U2idx(object):
|
|
59
59
|
def log(self, msg , c = 0) :
|
60
60
|
self.log_func("u2idx", msg, c)
|
61
61
|
|
62
|
+
def shutdown(self) :
|
63
|
+
for cur in self.cur.values():
|
64
|
+
db = cur.connection
|
65
|
+
try:
|
66
|
+
db.interrupt()
|
67
|
+
except:
|
68
|
+
pass
|
69
|
+
|
70
|
+
cur.close()
|
71
|
+
db.close()
|
72
|
+
|
62
73
|
def fsearch(
|
63
74
|
self, uname , vols , body
|
64
75
|
) :
|
@@ -78,14 +89,18 @@ class U2idx(object):
|
|
78
89
|
except:
|
79
90
|
raise Pebkac(500, min_ex())
|
80
91
|
|
81
|
-
def get_cur(self,
|
92
|
+
def get_cur(self, vn ) :
|
82
93
|
if not HAVE_SQLITE3:
|
83
94
|
return None
|
84
95
|
|
85
|
-
cur = self.cur.get(
|
96
|
+
cur = self.cur.get(vn.realpath)
|
86
97
|
if cur:
|
87
98
|
return cur
|
88
99
|
|
100
|
+
if "e2d" not in vn.flags:
|
101
|
+
return None
|
102
|
+
|
103
|
+
ptop = vn.realpath
|
89
104
|
histpath = self.asrv.vfs.histtab.get(ptop)
|
90
105
|
if not histpath:
|
91
106
|
self.log("no histpath for [{}]".format(ptop))
|
@@ -314,7 +329,7 @@ class U2idx(object):
|
|
314
329
|
ptop = vol.realpath
|
315
330
|
flags = vol.flags
|
316
331
|
|
317
|
-
cur = self.get_cur(
|
332
|
+
cur = self.get_cur(vol)
|
318
333
|
if not cur:
|
319
334
|
continue
|
320
335
|
|
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
|
@@ -183,7 +180,7 @@ class Up2k(object):
|
|
183
180
|
t = "could not initialize sqlite3, will use in-memory registry only"
|
184
181
|
self.log(t, 3)
|
185
182
|
|
186
|
-
self.fstab = Fstab(self.log_func)
|
183
|
+
self.fstab = Fstab(self.log_func, self.args)
|
187
184
|
self.gen_fk = self._gen_fk if self.args.log_fk else gen_filekey
|
188
185
|
|
189
186
|
if self.args.hash_mt < 2:
|
@@ -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:
|
@@ -4376,6 +4382,18 @@ class Up2k(object):
|
|
4376
4382
|
for x in list(self.spools):
|
4377
4383
|
self._unspool(x)
|
4378
4384
|
|
4385
|
+
for cur in self.cur.values():
|
4386
|
+
db = cur.connection
|
4387
|
+
try:
|
4388
|
+
db.interrupt()
|
4389
|
+
except:
|
4390
|
+
pass
|
4391
|
+
|
4392
|
+
cur.close()
|
4393
|
+
db.close()
|
4394
|
+
|
4395
|
+
self.registry = {}
|
4396
|
+
|
4379
4397
|
|
4380
4398
|
def up2k_chunksize(filesize ) :
|
4381
4399
|
chunksize = 1024 * 1024
|
copyparty/util.py
CHANGED
@@ -35,6 +35,9 @@ from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, VT100, WINDOWS
|
|
35
35
|
from .__version__ import S_BUILD_DT, S_VERSION
|
36
36
|
from .stolen import surrogateescape
|
37
37
|
|
38
|
+
ub64dec = base64.urlsafe_b64decode
|
39
|
+
ub64enc = base64.urlsafe_b64encode
|
40
|
+
|
38
41
|
try:
|
39
42
|
from datetime import datetime, timezone
|
40
43
|
|
@@ -334,6 +337,9 @@ APPLESAN_TXT = r"/(__MACOS|Icon\r\r)|/\.(_|DS_Store|AppleDouble|LSOverride|Docum
|
|
334
337
|
APPLESAN_RE = re.compile(APPLESAN_TXT)
|
335
338
|
|
336
339
|
|
340
|
+
VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
|
341
|
+
|
342
|
+
|
337
343
|
pybin = sys.executable or ""
|
338
344
|
if EXE:
|
339
345
|
pybin = ""
|
@@ -439,13 +445,22 @@ class Daemon(threading.Thread):
|
|
439
445
|
r = True,
|
440
446
|
ka = None,
|
441
447
|
) :
|
442
|
-
threading.Thread.__init__(
|
443
|
-
|
444
|
-
|
448
|
+
threading.Thread.__init__(self, name=name)
|
449
|
+
self.a = a or ()
|
450
|
+
self.ka = ka or {}
|
451
|
+
self.fun = target
|
445
452
|
self.daemon = True
|
446
453
|
if r:
|
447
454
|
self.start()
|
448
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
|
+
|
449
464
|
|
450
465
|
class Netdev(object):
|
451
466
|
def __init__(self, ip , idx , name , desc ):
|
@@ -840,6 +855,7 @@ class ProgressPrinter(threading.Thread):
|
|
840
855
|
self.start()
|
841
856
|
|
842
857
|
def run(self) :
|
858
|
+
sigblock()
|
843
859
|
tp = 0
|
844
860
|
msg = None
|
845
861
|
no_stdout = self.args.q
|
@@ -1284,6 +1300,15 @@ def log_thrs(log , ival , name ) :
|
|
1284
1300
|
log(name, "\033[0m \033[33m".join(tv), 3)
|
1285
1301
|
|
1286
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
|
+
|
1287
1312
|
def vol_san(vols , txt ) :
|
1288
1313
|
txt0 = txt
|
1289
1314
|
for vol in vols:
|
@@ -1305,10 +1330,11 @@ def vol_san(vols , txt ) :
|
|
1305
1330
|
|
1306
1331
|
def min_ex(max_lines = 8, reverse = False) :
|
1307
1332
|
et, ev, tb = sys.exc_info()
|
1308
|
-
stb = traceback.extract_tb(tb)
|
1333
|
+
stb = traceback.extract_tb(tb) if tb else traceback.extract_stack()[:-1]
|
1309
1334
|
fmt = "%s @ %d <%s>: %s"
|
1310
1335
|
ex = [fmt % (fp.split(os.sep)[-1], ln, fun, txt) for fp, ln, fun, txt in stb]
|
1311
|
-
|
1336
|
+
if et or ev or tb:
|
1337
|
+
ex.append("[%s] %s" % (et.__name__ if et else "(anonymous)", ev))
|
1312
1338
|
return "\n".join(ex[-max_lines:][:: -1 if reverse else 1])
|
1313
1339
|
|
1314
1340
|
|
@@ -2010,6 +2036,7 @@ def vsplit(vpath ) :
|
|
2010
2036
|
return vpath.rsplit("/", 1) # type: ignore
|
2011
2037
|
|
2012
2038
|
|
2039
|
+
# vpath-join
|
2013
2040
|
def vjoin(rd , fn ) :
|
2014
2041
|
if rd and fn:
|
2015
2042
|
return rd + "/" + fn
|
@@ -2017,6 +2044,14 @@ def vjoin(rd , fn ) :
|
|
2017
2044
|
return rd or fn
|
2018
2045
|
|
2019
2046
|
|
2047
|
+
# url-join
|
2048
|
+
def ujoin(rd , fn ) :
|
2049
|
+
if rd and fn:
|
2050
|
+
return rd.rstrip("/") + "/" + fn.lstrip("/")
|
2051
|
+
else:
|
2052
|
+
return rd or fn
|
2053
|
+
|
2054
|
+
|
2020
2055
|
def _w8dec2(txt ) :
|
2021
2056
|
"""decodes filesystem-bytes to wtf8"""
|
2022
2057
|
return surrogateescape.decodefilename(txt)
|
@@ -2648,7 +2683,7 @@ def unescape_cookie(orig ) :
|
|
2648
2683
|
|
2649
2684
|
def guess_mime(url , fallback = "application/octet-stream") :
|
2650
2685
|
try:
|
2651
|
-
|
2686
|
+
ext = url.rsplit(".", 1)[1].lower()
|
2652
2687
|
except:
|
2653
2688
|
return fallback
|
2654
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/baguettebox.js.gz
CHANGED
Binary file
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>{{ title }}</title>
|
7
7
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=0.8, minimum-scale=0.6">
|
9
|
-
<meta name="theme-color" content="#
|
9
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
10
10
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
11
11
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/browser.css?_={{ ts }}">
|
12
12
|
{{ html_head }}
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/deps/marked.js.gz
CHANGED
Binary file
|
copyparty/web/md.html
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<title>📝 {{ title }}</title>
|
4
4
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=0.7">
|
6
|
-
<meta name="theme-color" content="#
|
6
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
7
7
|
<link rel="stylesheet" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
8
8
|
<link rel="stylesheet" href="{{ r }}/.cpr/md.css?_={{ ts }}">
|
9
9
|
{%- if edit %}
|
copyparty/web/mde.html
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<title>📝 {{ title }}</title>
|
4
4
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=0.7">
|
6
|
-
<meta name="theme-color" content="#
|
6
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
7
7
|
<link rel="stylesheet" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
8
8
|
<link rel="stylesheet" href="{{ r }}/.cpr/mde.css?_={{ ts }}">
|
9
9
|
<link rel="stylesheet" href="{{ r }}/.cpr/deps/mini-fa.css?_={{ ts }}">
|
copyparty/web/msg.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>{{ s_doctitle }}</title>
|
7
7
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
9
|
-
<meta name="theme-color" content="#
|
9
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
10
10
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/msg.css?_={{ ts }}">
|
11
11
|
{{ html_head }}
|
12
12
|
</head>
|
copyparty/web/splash.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>{{ s_doctitle }}</title>
|
7
7
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
9
|
-
<meta name="theme-color" content="#
|
9
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
10
10
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
|
11
11
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
12
12
|
{{ html_head }}
|
@@ -95,6 +95,7 @@
|
|
95
95
|
<form method="post" enctype="multipart/form-data" action="{{ r }}/{{ qvpath }}">
|
96
96
|
<input type="hidden" name="act" value="login" />
|
97
97
|
<input type="password" name="cppwd" placeholder=" password" />
|
98
|
+
<input type="hidden" name="uhash" id="uhash" value="x" />
|
98
99
|
<input type="submit" value="Login" />
|
99
100
|
{% if ahttps %}
|
100
101
|
<a id="w" href="{{ ahttps }}">switch to https</a>
|
copyparty/web/splash.js.gz
CHANGED
Binary file
|
copyparty/web/svcs.html
CHANGED
@@ -6,7 +6,7 @@
|
|
6
6
|
<title>{{ s_doctitle }}</title>
|
7
7
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
8
8
|
<meta name="viewport" content="width=device-width, initial-scale=0.8">
|
9
|
-
<meta name="theme-color" content="#
|
9
|
+
<meta name="theme-color" content="#{{ tcolor }}">
|
10
10
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
|
11
11
|
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
|
12
12
|
<style>ul{padding-left:1.3em}li{margin:.4em 0}</style>
|
copyparty/web/util.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
|
@@ -101,6 +101,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
101
101
|
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
102
102
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
103
103
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
104
|
+
* [markdown vars](#markdown-vars) - dynamic docs with serverside variable expansion
|
104
105
|
* [other tricks](#other-tricks)
|
105
106
|
* [searching](#searching) - search by size, date, path/name, mp3-tags, ...
|
106
107
|
* [server config](#server-config) - using arguments or config files, or a mix of both
|
@@ -114,6 +115,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
114
115
|
* [tftp server](#tftp-server) - a TFTP server (read/write) can be started using `--tftp 3969`
|
115
116
|
* [smb server](#smb-server) - unsafe, slow, not recommended for wan
|
116
117
|
* [browser ux](#browser-ux) - tweaking the ui
|
118
|
+
* [opengraph](#opengraph) - discord and social-media embeds
|
117
119
|
* [file indexing](#file-indexing) - enables dedup and music search ++
|
118
120
|
* [exclude-patterns](#exclude-patterns) - to save some time
|
119
121
|
* [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
|
@@ -162,8 +164,9 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
162
164
|
* [dependencies](#dependencies) - mandatory deps
|
163
165
|
* [optional dependencies](#optional-dependencies) - install these to enable bonus features
|
164
166
|
* [optional gpl stuff](#optional-gpl-stuff)
|
165
|
-
* [sfx](#sfx) - the self-contained "binary"
|
167
|
+
* [sfx](#sfx) - the self-contained "binary" (recommended!)
|
166
168
|
* [copyparty.exe](#copypartyexe) - download [copyparty.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty.exe) (win8+) or [copyparty32.exe](https://github.com/9001/copyparty/releases/latest/download/copyparty32.exe) (win7+)
|
169
|
+
* [zipapp](#zipapp) - another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz)
|
167
170
|
* [install on android](#install-on-android)
|
168
171
|
* [reporting bugs](#reporting-bugs) - ideas for context to include, and where to submit them
|
169
172
|
* [devnotes](#devnotes) - for build instructions etc, see [./docs/devnotes.md](./docs/devnotes.md)
|
@@ -177,6 +180,7 @@ just run **[copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/
|
|
177
180
|
* or if you cannot install python, you can use [copyparty.exe](#copypartyexe) instead
|
178
181
|
* or install [on arch](#arch-package) ╱ [on NixOS](#nixos-module) ╱ [through nix](#nix-package)
|
179
182
|
* or if you are on android, [install copyparty in termux](#install-on-android)
|
183
|
+
* or if your computer is messed up and nothing else works, [try the pyz](#zipapp)
|
180
184
|
* or if you prefer to [use docker](./scripts/docker/) 🐋 you can do that too
|
181
185
|
* docker has all deps built-in, so skip this step:
|
182
186
|
|
@@ -280,6 +284,7 @@ also see [comparison to similar software](./docs/versus.md)
|
|
280
284
|
* ☑ ...of videos using FFmpeg
|
281
285
|
* ☑ ...of audio (spectrograms) using FFmpeg
|
282
286
|
* ☑ cache eviction (max-age; maybe max-size eventually)
|
287
|
+
* ☑ multilingual UI (english, norwegian, [add your own](./docs/rice/#translations)))
|
283
288
|
* ☑ SPA (browse while uploading)
|
284
289
|
* server indexing
|
285
290
|
* ☑ [locate files by contents](#file-search)
|
@@ -288,9 +293,11 @@ also see [comparison to similar software](./docs/versus.md)
|
|
288
293
|
* client support
|
289
294
|
* ☑ [folder sync](#folder-sync)
|
290
295
|
* ☑ [curl-friendly](https://user-images.githubusercontent.com/241032/215322619-ea5fd606-3654-40ad-94ee-2bc058647bb2.png)
|
296
|
+
* ☑ [opengraph](#opengraph) (discord embeds)
|
291
297
|
* markdown
|
292
298
|
* ☑ [viewer](#markdown-viewer)
|
293
299
|
* ☑ editor (sure why not)
|
300
|
+
* ☑ [variables](#markdown-vars)
|
294
301
|
|
295
302
|
PS: something missing? post any crazy ideas you've got as a [feature request](https://github.com/9001/copyparty/issues/new?assignees=9001&labels=enhancement&template=feature_request.md) or [discussion](https://github.com/9001/copyparty/discussions/new?category=ideas) 🤙
|
296
303
|
|
@@ -460,7 +467,7 @@ configuring accounts/volumes with arguments:
|
|
460
467
|
`-v .::r,usr1,usr2:rw,usr3,usr4` = usr1/2 read-only, 3/4 read-write
|
461
468
|
|
462
469
|
permissions:
|
463
|
-
* `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
|
464
471
|
* `w` (write): upload files, move files *into* this folder
|
465
472
|
* `m` (move): move files/folders *from* this folder
|
466
473
|
* `d` (delete): delete files/folders
|
@@ -662,15 +669,21 @@ you can also zip a selection of files or folders by clicking them in the browser
|
|
662
669
|
|
663
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
|
664
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
|
665
|
-
* 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)
|
666
673
|
* can also be used to pregenerate thumbnails; combine with `--th-maxage=9999999` or `--th-clean=0`
|
667
674
|
|
668
675
|
|
669
676
|
## uploading
|
670
677
|
|
671
|
-
drag files/folders into the web-browser to upload
|
678
|
+
drag files/folders into the web-browser to upload
|
672
679
|
|
673
|
-
|
680
|
+
dragdrop is the recommended way, but you may also:
|
681
|
+
|
682
|
+
* select some files (not folders) in your file explorer and press CTRL-V inside the browser window
|
683
|
+
* use the [command-line uploader](https://github.com/9001/copyparty/tree/hovudstraum/bin#u2cpy)
|
684
|
+
* upload using [curl or sharex](#client-examples)
|
685
|
+
|
686
|
+
when uploading files through dragdrop or CTRL-V, this initiates an upload using `up2k`; there are two browser-based uploaders available:
|
674
687
|
* `[🎈] bup`, the basic uploader, supports almost every browser since netscape 4.0
|
675
688
|
* `[🚀] up2k`, the good / fancy one
|
676
689
|
|
@@ -897,6 +910,13 @@ other notes,
|
|
897
910
|
* the document preview has a max-width which is the same as an A4 paper when printed
|
898
911
|
|
899
912
|
|
913
|
+
### markdown vars
|
914
|
+
|
915
|
+
dynamic docs with serverside variable expansion to replace stuff like `{{self.ip}}` with the client's IP, or `{{srv.htime}}` with the current time on the server
|
916
|
+
|
917
|
+
see [./srv/expand/](./srv/expand/) for usage and examples
|
918
|
+
|
919
|
+
|
900
920
|
## other tricks
|
901
921
|
|
902
922
|
* you can link a particular timestamp in an audio file by adding it to the URL, such as `&20` / `&20s` / `&1m20` / `&t=1:20` after the `.../#af-c8960dab`
|
@@ -945,6 +965,8 @@ using arguments or config files, or a mix of both:
|
|
945
965
|
|
946
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.
|
947
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
|
948
970
|
|
949
971
|
|
950
972
|
## zeroconf
|
@@ -1121,7 +1143,22 @@ tweaking the ui
|
|
1121
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`
|
1122
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`
|
1123
1145
|
|
1124
|
-
see [./docs/rice](./docs/rice) for more
|
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
|
1147
|
+
|
1148
|
+
|
1149
|
+
## opengraph
|
1150
|
+
|
1151
|
+
discord and social-media embeds
|
1152
|
+
|
1153
|
+
can be enabled globally with `--og` or per-volume with volflag `og`
|
1154
|
+
|
1155
|
+
note that this disables hotlinking because the opengraph spec demands it; to sneak past this intentional limitation, you can enable opengraph selectively by user-agent, for example `--og-ua '(Discord|Twitter|Slack)bot'` (or volflag `og_ua`)
|
1156
|
+
|
1157
|
+
you can also hotlink files regardless by appending `?raw` to the url
|
1158
|
+
|
1159
|
+
NOTE: because discord (and maybe others) strip query args such as `?raw` in opengraph tags, any links which require a filekey or dirkey will not work
|
1160
|
+
|
1161
|
+
if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object)
|
1125
1162
|
|
1126
1163
|
|
1127
1164
|
## file indexing
|
@@ -2035,7 +2072,7 @@ these are standalone programs and will never be imported / evaluated by copypart
|
|
2035
2072
|
|
2036
2073
|
# sfx
|
2037
2074
|
|
2038
|
-
the self-contained "binary" [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
|
2075
|
+
the self-contained "binary" (recommended!) [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/download/copyparty-sfx.py) will unpack itself and run copyparty, assuming you have python installed of course
|
2039
2076
|
|
2040
2077
|
you can reduce the sfx size by repacking it; see [./docs/devnotes.md#sfx-repack](./docs/devnotes.md#sfx-repack)
|
2041
2078
|
|
@@ -2062,6 +2099,16 @@ meanwhile [copyparty-sfx.py](https://github.com/9001/copyparty/releases/latest/d
|
|
2062
2099
|
then again, if you are already into downloading shady binaries from the internet, you may also want my [minimal builds](./scripts/pyinstaller#ffmpeg) of [ffmpeg](https://ocv.me/stuff/bin/ffmpeg.exe) and [ffprobe](https://ocv.me/stuff/bin/ffprobe.exe) which enables copyparty to extract multimedia-info, do audio-transcoding, and thumbnails/spectrograms/waveforms, however it's much better to instead grab a [recent official build](https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z) every once ina while if you can afford the size
|
2063
2100
|
|
2064
2101
|
|
2102
|
+
## zipapp
|
2103
|
+
|
2104
|
+
another emergency alternative, [copyparty.pyz](https://github.com/9001/copyparty/releases/latest/download/copyparty.pyz) has less features, requires python 3.7 or newer, worse compression, and more importantly is unable to benefit from more recent versions of jinja2 and such (which makes it less secure)... lots of drawbacks with this one really -- but it *may* just work if the regular sfx fails to start because the computer is messed up in certain funky ways, so it's worth a shot if all else fails
|
2105
|
+
|
2106
|
+
run it by doubleclicking it, or try typing `python copyparty.pyz` in your terminal/console/commandline/telex if that fails
|
2107
|
+
|
2108
|
+
it is a python [zipapp](https://docs.python.org/3/library/zipapp.html) meaning it doesn't have to unpack its own python code anywhere to run, so if the filesystem is busted it has a better chance of getting somewhere
|
2109
|
+
* but note that it currently still needs to extract the web-resources somewhere (they'll land in the default TEMP-folder of your OS)
|
2110
|
+
|
2111
|
+
|
2065
2112
|
# install on android
|
2066
2113
|
|
2067
2114
|
install [Termux](https://termux.com/) + its companion app `Termux:API` (see [ocv.me/termux](https://ocv.me/termux/)) and then copy-paste this into Termux (long-tap) all at once:
|