copyparty 1.13.2__py3-none-any.whl → 1.13.3__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 +24 -5
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +7 -4
- copyparty/httpcli.py +9 -3
- copyparty/mdns.py +23 -2
- copyparty/mtag.py +3 -1
- copyparty/ssdp.py +22 -2
- copyparty/star.py +4 -4
- copyparty/sutil.py +12 -6
- copyparty/szip.py +4 -4
- copyparty/th_cli.py +1 -1
- copyparty/th_srv.py +22 -11
- copyparty/up2k.py +2 -2
- copyparty/util.py +25 -8
- copyparty/web/a/u2c.py +14 -6
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/deps/marked.js.gz +0 -0
- copyparty/web/md2.js.gz +0 -0
- {copyparty-1.13.2.dist-info → copyparty-1.13.3.dist-info}/METADATA +1 -1
- {copyparty-1.13.2.dist-info → copyparty-1.13.3.dist-info}/RECORD +26 -26
- {copyparty-1.13.2.dist-info → copyparty-1.13.3.dist-info}/LICENSE +0 -0
- {copyparty-1.13.2.dist-info → copyparty-1.13.3.dist-info}/WHEEL +0 -0
- {copyparty-1.13.2.dist-info → copyparty-1.13.3.dist-info}/entry_points.txt +0 -0
- {copyparty-1.13.2.dist-info → copyparty-1.13.3.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -13,6 +13,7 @@ import base64
|
|
13
13
|
import locale
|
14
14
|
import os
|
15
15
|
import re
|
16
|
+
import select
|
16
17
|
import socket
|
17
18
|
import sys
|
18
19
|
import threading
|
@@ -167,8 +168,10 @@ def init_E(EE ) :
|
|
167
168
|
(os.environ.get, "TMP"),
|
168
169
|
(unicode, "/tmp"),
|
169
170
|
]
|
171
|
+
errs = []
|
170
172
|
for chk in [os.listdir, os.mkdir]:
|
171
|
-
for pf, pa in paths:
|
173
|
+
for npath, (pf, pa) in enumerate(paths):
|
174
|
+
p = ""
|
172
175
|
try:
|
173
176
|
p = pf(pa)
|
174
177
|
# print(chk.__name__, p, pa)
|
@@ -181,9 +184,20 @@ def init_E(EE ) :
|
|
181
184
|
if not os.path.isdir(p):
|
182
185
|
os.mkdir(p)
|
183
186
|
|
187
|
+
if npath > 1:
|
188
|
+
t = "Using [%s] for config; filekeys/dirkeys will change on every restart. Consider setting XDG_CONFIG_HOME or giving the unix-user a ~/.config/"
|
189
|
+
errs.append(t % (p,))
|
190
|
+
elif errs:
|
191
|
+
errs.append("Using [%s] instead" % (p,))
|
192
|
+
|
193
|
+
if errs:
|
194
|
+
print("WARNING: " + ". ".join(errs))
|
195
|
+
|
184
196
|
return p # type: ignore
|
185
|
-
except:
|
186
|
-
|
197
|
+
except Exception as ex:
|
198
|
+
if p and npath < 2:
|
199
|
+
t = "Unable to store config in [%s] due to %r"
|
200
|
+
errs.append(t % (p, ex))
|
187
201
|
|
188
202
|
raise Exception("could not find a writable path for config")
|
189
203
|
|
@@ -892,7 +906,7 @@ def add_upload(ap):
|
|
892
906
|
ap2.add_argument("--rand", action="store_true", help="force randomized filenames, \033[33m--nrand\033[0m chars long (volflag=rand)")
|
893
907
|
ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)")
|
894
908
|
ap2.add_argument("--magic", action="store_true", help="enable filetype detection on nameless uploads (volflag=magic)")
|
895
|
-
ap2.add_argument("--df", metavar="GiB", type=
|
909
|
+
ap2.add_argument("--df", metavar="GiB", type=u, default="0", help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests; assumes gigabytes unless a unit suffix is given: [\033[32m256m\033[0m], [\033[32m4\033[0m], [\033[32m2T\033[0m] (volflag=df)")
|
896
910
|
ap2.add_argument("--sparse", metavar="MiB", type=int, default=4, help="windows-only: minimum size of incoming uploads through up2k before they are made into sparse files")
|
897
911
|
ap2.add_argument("--turbo", metavar="LVL", type=int, default=0, help="configure turbo-mode in up2k client; [\033[32m-1\033[0m] = forbidden/always-off, [\033[32m0\033[0m] = default-off and warn if enabled, [\033[32m1\033[0m] = default-off, [\033[32m2\033[0m] = on, [\033[32m3\033[0m] = on and disable datecheck")
|
898
912
|
ap2.add_argument("--u2j", metavar="JOBS", type=int, default=2, help="web-client: number of file chunks to upload in parallel; 1 or 2 is good for low-latency (same-country) connections, 4-8 for android clients, 16 for cross-atlantic (max=64)")
|
@@ -1316,6 +1330,8 @@ def add_debug(ap):
|
|
1316
1330
|
ap2 = ap.add_argument_group('debug options')
|
1317
1331
|
ap2.add_argument("--vc", action="store_true", help="verbose config file parser (explain config)")
|
1318
1332
|
ap2.add_argument("--cgen", action="store_true", help="generate config file from current config (best-effort; probably buggy)")
|
1333
|
+
if hasattr(select, "poll"):
|
1334
|
+
ap2.add_argument("--no-poll", action="store_true", help="kernel-bug workaround: disable poll; use select instead (limits max num clients to ~700)")
|
1319
1335
|
ap2.add_argument("--no-sendfile", action="store_true", help="kernel-bug workaround: disable sendfile; do a safe and slow read-send-loop instead")
|
1320
1336
|
ap2.add_argument("--no-scandir", action="store_true", help="kernel-bug workaround: disable scandir; do a listdir + stat on each file instead")
|
1321
1337
|
ap2.add_argument("--no-fastboot", action="store_true", help="wait for initial filesystem indexing before accepting client requests")
|
@@ -1526,7 +1542,7 @@ def main(argv = None, rsrc = None) :
|
|
1526
1542
|
if hard > 0: # -1 == infinite
|
1527
1543
|
nc = min(nc, int(hard / 4))
|
1528
1544
|
except:
|
1529
|
-
nc = 512
|
1545
|
+
nc = 486 # mdns/ssdp restart headroom; select() maxfd is 512 on windows
|
1530
1546
|
|
1531
1547
|
retry = False
|
1532
1548
|
for fmtr in [RiceFormatter, RiceFormatter, Dodge11874, BasicDodge11874]:
|
@@ -1619,6 +1635,9 @@ def main(argv = None, rsrc = None) :
|
|
1619
1635
|
if not hasattr(os, "sendfile"):
|
1620
1636
|
al.no_sendfile = True
|
1621
1637
|
|
1638
|
+
if not hasattr(select, "poll"):
|
1639
|
+
al.no_poll = True
|
1640
|
+
|
1622
1641
|
# signal.signal(signal.SIGINT, sighandler)
|
1623
1642
|
|
1624
1643
|
SvcHub(al, dal, argv, "".join(printed)).run()
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -1610,11 +1610,14 @@ class AuthSrv(object):
|
|
1610
1610
|
use = True
|
1611
1611
|
lim.nosub = True
|
1612
1612
|
|
1613
|
-
zs = vol.flags.get("df") or
|
1614
|
-
|
1615
|
-
)
|
1616
|
-
if zs:
|
1613
|
+
zs = vol.flags.get("df") or self.args.df or ""
|
1614
|
+
if zs not in ("", "0"):
|
1617
1615
|
use = True
|
1616
|
+
try:
|
1617
|
+
_ = float(zs)
|
1618
|
+
zs = "%sg" % (zs)
|
1619
|
+
except:
|
1620
|
+
pass
|
1618
1621
|
lim.dfl = unhumanize(zs)
|
1619
1622
|
|
1620
1623
|
zs = vol.flags.get("sz")
|
copyparty/httpcli.py
CHANGED
@@ -755,7 +755,6 @@ class HttpCli(object):
|
|
755
755
|
is_jinja = True
|
756
756
|
|
757
757
|
if is_jinja:
|
758
|
-
print("applying jinja")
|
759
758
|
with self.conn.hsrv.mutex:
|
760
759
|
if html not in self.conn.hsrv.j2:
|
761
760
|
j2env = jinja2.Environment()
|
@@ -3190,7 +3189,14 @@ class HttpCli(object):
|
|
3190
3189
|
|
3191
3190
|
sendfun = sendfile_kern if use_sendfile else sendfile_py
|
3192
3191
|
remains = sendfun(
|
3193
|
-
self.log,
|
3192
|
+
self.log,
|
3193
|
+
lower,
|
3194
|
+
upper,
|
3195
|
+
f,
|
3196
|
+
self.s,
|
3197
|
+
self.args.s_wr_sz,
|
3198
|
+
self.args.s_wr_slp,
|
3199
|
+
not self.args.no_poll,
|
3194
3200
|
)
|
3195
3201
|
|
3196
3202
|
if remains > 0:
|
@@ -3419,7 +3425,7 @@ class HttpCli(object):
|
|
3419
3425
|
|
3420
3426
|
bgen = packer(
|
3421
3427
|
self.log,
|
3422
|
-
self.
|
3428
|
+
self.asrv,
|
3423
3429
|
fgen,
|
3424
3430
|
utf8="utf" in uarg,
|
3425
3431
|
pre_crc="crc" in uarg,
|
copyparty/mdns.py
CHANGED
@@ -288,6 +288,22 @@ class MDNS(MCast):
|
|
288
288
|
def run2(self) :
|
289
289
|
last_hop = time.time()
|
290
290
|
ihop = self.args.mc_hop
|
291
|
+
|
292
|
+
try:
|
293
|
+
if self.args.no_poll:
|
294
|
+
raise Exception()
|
295
|
+
fd2sck = {}
|
296
|
+
srvpoll = select.poll()
|
297
|
+
for sck in self.srv:
|
298
|
+
fd = sck.fileno()
|
299
|
+
fd2sck[fd] = sck
|
300
|
+
srvpoll.register(fd, select.POLLIN)
|
301
|
+
except Exception as ex:
|
302
|
+
srvpoll = None
|
303
|
+
if not self.args.no_poll:
|
304
|
+
t = "WARNING: failed to poll(), will use select() instead: %r"
|
305
|
+
self.log(t % (ex,), 3)
|
306
|
+
|
291
307
|
while self.running:
|
292
308
|
timeout = (
|
293
309
|
0.02 + random.random() * 0.07
|
@@ -296,8 +312,13 @@ class MDNS(MCast):
|
|
296
312
|
if self.unsolicited
|
297
313
|
else (last_hop + ihop if ihop else 180)
|
298
314
|
)
|
299
|
-
|
300
|
-
|
315
|
+
if srvpoll:
|
316
|
+
pr = srvpoll.poll(timeout * 1000)
|
317
|
+
rx = [fd2sck[x[0]] for x in pr if x[1] & select.POLLIN]
|
318
|
+
else:
|
319
|
+
rdy = select.select(self.srv, [], [], timeout)
|
320
|
+
rx = rdy[0] # type: ignore
|
321
|
+
|
301
322
|
self.rx4.cln()
|
302
323
|
self.rx6.cln()
|
303
324
|
buf = b""
|
copyparty/mtag.py
CHANGED
copyparty/ssdp.py
CHANGED
@@ -137,9 +137,29 @@ class SSDPd(MCast):
|
|
137
137
|
self.log("stopped", 2)
|
138
138
|
|
139
139
|
def run2(self) :
|
140
|
+
try:
|
141
|
+
if self.args.no_poll:
|
142
|
+
raise Exception()
|
143
|
+
fd2sck = {}
|
144
|
+
srvpoll = select.poll()
|
145
|
+
for sck in self.srv:
|
146
|
+
fd = sck.fileno()
|
147
|
+
fd2sck[fd] = sck
|
148
|
+
srvpoll.register(fd, select.POLLIN)
|
149
|
+
except Exception as ex:
|
150
|
+
srvpoll = None
|
151
|
+
if not self.args.no_poll:
|
152
|
+
t = "WARNING: failed to poll(), will use select() instead: %r"
|
153
|
+
self.log(t % (ex,), 3)
|
154
|
+
|
140
155
|
while self.running:
|
141
|
-
|
142
|
-
|
156
|
+
if srvpoll:
|
157
|
+
pr = srvpoll.poll((self.args.z_chk or 180) * 1000)
|
158
|
+
rx = [fd2sck[x[0]] for x in pr if x[1] & select.POLLIN]
|
159
|
+
else:
|
160
|
+
rdy = select.select(self.srv, [], [], self.args.z_chk or 180)
|
161
|
+
rx = rdy[0] # type: ignore
|
162
|
+
|
143
163
|
self.rxc.cln()
|
144
164
|
buf = b""
|
145
165
|
addr = ("0", 0)
|
copyparty/star.py
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
import argparse
|
5
4
|
import re
|
6
5
|
import stat
|
7
6
|
import tarfile
|
8
7
|
|
9
8
|
from queue import Queue
|
10
9
|
|
10
|
+
from .authsrv import AuthSrv
|
11
11
|
from .bos import bos
|
12
12
|
from .sutil import StreamArc, errdesc
|
13
13
|
from .util import Daemon, fsenc, min_ex
|
@@ -39,12 +39,12 @@ class StreamTar(StreamArc):
|
|
39
39
|
def __init__(
|
40
40
|
self,
|
41
41
|
log ,
|
42
|
-
|
42
|
+
asrv ,
|
43
43
|
fgen ,
|
44
44
|
cmp = "",
|
45
45
|
**kwargs
|
46
46
|
):
|
47
|
-
super(StreamTar, self).__init__(log,
|
47
|
+
super(StreamTar, self).__init__(log, asrv, fgen)
|
48
48
|
|
49
49
|
self.ci = 0
|
50
50
|
self.co = 0
|
@@ -142,7 +142,7 @@ class StreamTar(StreamArc):
|
|
142
142
|
errors.append((f["vp"], ex))
|
143
143
|
|
144
144
|
if errors:
|
145
|
-
self.errf, txt = errdesc(errors)
|
145
|
+
self.errf, txt = errdesc(self.asrv.vfs, errors)
|
146
146
|
self.log("\n".join(([repr(self.errf)] + txt[1:])))
|
147
147
|
self.ser(self.errf)
|
148
148
|
|
copyparty/sutil.py
CHANGED
@@ -1,26 +1,27 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
import argparse
|
5
4
|
import os
|
6
5
|
import tempfile
|
7
6
|
from datetime import datetime
|
8
7
|
|
9
8
|
from .__init__ import CORES
|
9
|
+
from .authsrv import AuthSrv, VFS
|
10
10
|
from .bos import bos
|
11
11
|
from .th_cli import ThumbCli
|
12
|
-
from .util import UTC, vjoin
|
12
|
+
from .util import UTC, vjoin, vol_san
|
13
13
|
|
14
14
|
class StreamArc(object):
|
15
15
|
def __init__(
|
16
16
|
self,
|
17
17
|
log ,
|
18
|
-
|
18
|
+
asrv ,
|
19
19
|
fgen ,
|
20
20
|
**kwargs
|
21
21
|
):
|
22
22
|
self.log = log
|
23
|
-
self.
|
23
|
+
self.asrv = asrv
|
24
|
+
self.args = asrv.args
|
24
25
|
self.fgen = fgen
|
25
26
|
self.stopped = False
|
26
27
|
|
@@ -97,15 +98,20 @@ def enthumb(
|
|
97
98
|
return f
|
98
99
|
|
99
100
|
|
100
|
-
def errdesc(
|
101
|
+
def errdesc(
|
102
|
+
vfs , errors
|
103
|
+
) :
|
101
104
|
report = ["copyparty failed to add the following files to the archive:", ""]
|
102
105
|
|
103
106
|
for fn, err in errors:
|
104
107
|
report.extend([" file: {}".format(fn), "error: {}".format(err), ""])
|
105
108
|
|
109
|
+
btxt = "\r\n".join(report).encode("utf-8", "replace")
|
110
|
+
btxt = vol_san(list(vfs.all_vols.values()), btxt)
|
111
|
+
|
106
112
|
with tempfile.NamedTemporaryFile(prefix="copyparty-", delete=False) as tf:
|
107
113
|
tf_path = tf.name
|
108
|
-
tf.write(
|
114
|
+
tf.write(btxt)
|
109
115
|
|
110
116
|
dt = datetime.now(UTC).strftime("%Y-%m%d-%H%M%S")
|
111
117
|
|
copyparty/szip.py
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
from __future__ import print_function, unicode_literals
|
3
3
|
|
4
|
-
import argparse
|
5
4
|
import calendar
|
6
5
|
import stat
|
7
6
|
import time
|
8
7
|
import zlib
|
9
8
|
|
9
|
+
from .authsrv import AuthSrv
|
10
10
|
from .bos import bos
|
11
11
|
from .sutil import StreamArc, errdesc
|
12
12
|
from .util import min_ex, sanitize_fn, spack, sunpack, yieldfile
|
@@ -213,13 +213,13 @@ class StreamZip(StreamArc):
|
|
213
213
|
def __init__(
|
214
214
|
self,
|
215
215
|
log ,
|
216
|
-
|
216
|
+
asrv ,
|
217
217
|
fgen ,
|
218
218
|
utf8 = False,
|
219
219
|
pre_crc = False,
|
220
220
|
**kwargs
|
221
221
|
) :
|
222
|
-
super(StreamZip, self).__init__(log,
|
222
|
+
super(StreamZip, self).__init__(log, asrv, fgen)
|
223
223
|
|
224
224
|
self.utf8 = utf8
|
225
225
|
self.pre_crc = pre_crc
|
@@ -296,7 +296,7 @@ class StreamZip(StreamArc):
|
|
296
296
|
mbuf = b""
|
297
297
|
|
298
298
|
if errors:
|
299
|
-
errf, txt = errdesc(errors)
|
299
|
+
errf, txt = errdesc(self.asrv.vfs, errors)
|
300
300
|
self.log("\n".join(([repr(errf)] + txt[1:])))
|
301
301
|
for x in self.ser(errf):
|
302
302
|
yield x
|
copyparty/th_cli.py
CHANGED
copyparty/th_srv.py
CHANGED
@@ -596,13 +596,14 @@ class ThumbSrv(object):
|
|
596
596
|
b"pngquant",
|
597
597
|
b"--strip",
|
598
598
|
b"--nofs",
|
599
|
-
b"--output",
|
600
|
-
fsenc(
|
599
|
+
b"--output",
|
600
|
+
fsenc(wtpath),
|
601
|
+
fsenc(tpath),
|
601
602
|
]
|
602
603
|
ret = runcmd(cmd, timeout=vn.flags["convt"], nice=True, oom=400)[0]
|
603
604
|
if ret:
|
604
605
|
try:
|
605
|
-
wunlink(self.log, wtpath,
|
606
|
+
wunlink(self.log, wtpath, vn.flags)
|
606
607
|
except:
|
607
608
|
pass
|
608
609
|
else:
|
@@ -670,8 +671,8 @@ class ThumbSrv(object):
|
|
670
671
|
raise Exception("disabled in server config")
|
671
672
|
|
672
673
|
self.wait4ram(0.2, tpath)
|
673
|
-
|
674
|
-
if "ac" not in
|
674
|
+
tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
675
|
+
if "ac" not in tags:
|
675
676
|
raise Exception("not audio")
|
676
677
|
|
677
678
|
if quality.endswith("k"):
|
@@ -692,7 +693,7 @@ class ThumbSrv(object):
|
|
692
693
|
b"-v", b"error",
|
693
694
|
b"-hide_banner",
|
694
695
|
b"-i", fsenc(abspath),
|
695
|
-
|
696
|
+
] + self.big_tags(rawtags) + [
|
696
697
|
b"-map", b"0:a:0",
|
697
698
|
b"-ar", b"44100",
|
698
699
|
b"-ac", b"2",
|
@@ -708,16 +709,16 @@ class ThumbSrv(object):
|
|
708
709
|
raise Exception("disabled in server config")
|
709
710
|
|
710
711
|
self.wait4ram(0.2, tpath)
|
711
|
-
|
712
|
-
if "ac" not in
|
712
|
+
tags, rawtags = ffprobe(abspath, int(vn.flags["convt"] / 2))
|
713
|
+
if "ac" not in tags:
|
713
714
|
raise Exception("not audio")
|
714
715
|
|
715
716
|
try:
|
716
|
-
dur =
|
717
|
+
dur = tags[".dur"][1]
|
717
718
|
except:
|
718
719
|
dur = 0
|
719
720
|
|
720
|
-
src_opus = abspath.lower().endswith(".opus") or
|
721
|
+
src_opus = abspath.lower().endswith(".opus") or tags["ac"][1] == "opus"
|
721
722
|
want_caf = tpath.endswith(".caf")
|
722
723
|
tmp_opus = tpath
|
723
724
|
if want_caf:
|
@@ -738,7 +739,7 @@ class ThumbSrv(object):
|
|
738
739
|
b"-v", b"error",
|
739
740
|
b"-hide_banner",
|
740
741
|
b"-i", fsenc(abspath),
|
741
|
-
|
742
|
+
] + self.big_tags(rawtags) + [
|
742
743
|
b"-map", b"0:a:0",
|
743
744
|
b"-c:a", b"libopus",
|
744
745
|
b"-b:a", bq,
|
@@ -795,6 +796,16 @@ class ThumbSrv(object):
|
|
795
796
|
except:
|
796
797
|
pass
|
797
798
|
|
799
|
+
def big_tags(self, raw_tags ) :
|
800
|
+
ret = []
|
801
|
+
for k, vs in raw_tags.items():
|
802
|
+
for v in vs:
|
803
|
+
if len(str(v)) >= 1024:
|
804
|
+
bv = k.encode("utf-8", "replace")
|
805
|
+
ret += [b"-metadata", bv + b"="]
|
806
|
+
break
|
807
|
+
return ret
|
808
|
+
|
798
809
|
def poke(self, tdir ) :
|
799
810
|
if not self.poke_cd.poke(tdir):
|
800
811
|
return
|
copyparty/up2k.py
CHANGED
@@ -706,9 +706,9 @@ class Up2k(object):
|
|
706
706
|
try:
|
707
707
|
bos.makedirs(vol.realpath) # gonna happen at snap anyways
|
708
708
|
dir_is_empty(self.log_func, not self.args.no_scandir, vol.realpath)
|
709
|
-
except:
|
709
|
+
except Exception as ex:
|
710
710
|
self.volstate[vol.vpath] = "OFFLINE (cannot access folder)"
|
711
|
-
self.log("cannot access "
|
711
|
+
self.log("cannot access %s: %r" % (vol.realpath, ex), c=1)
|
712
712
|
continue
|
713
713
|
|
714
714
|
if scan_vols and vol.vpath not in scan_vols:
|
copyparty/util.py
CHANGED
@@ -337,6 +337,18 @@ 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
|
+
HUMANSIZE_UNITS = ("B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB")
|
341
|
+
|
342
|
+
UNHUMANIZE_UNITS = {
|
343
|
+
"b": 1,
|
344
|
+
"k": 1024,
|
345
|
+
"m": 1024 * 1024,
|
346
|
+
"g": 1024 * 1024 * 1024,
|
347
|
+
"t": 1024 * 1024 * 1024 * 1024,
|
348
|
+
"p": 1024 * 1024 * 1024 * 1024 * 1024,
|
349
|
+
"e": 1024 * 1024 * 1024 * 1024 * 1024 * 1024,
|
350
|
+
}
|
351
|
+
|
340
352
|
VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
|
341
353
|
|
342
354
|
|
@@ -1787,7 +1799,7 @@ def gencookie(k , v , r , tls , dur = 0, txt = "") :
|
|
1787
1799
|
|
1788
1800
|
|
1789
1801
|
def humansize(sz , terse = False) :
|
1790
|
-
for unit in
|
1802
|
+
for unit in HUMANSIZE_UNITS:
|
1791
1803
|
if sz < 1024:
|
1792
1804
|
break
|
1793
1805
|
|
@@ -1808,12 +1820,7 @@ def unhumanize(sz ) :
|
|
1808
1820
|
pass
|
1809
1821
|
|
1810
1822
|
mc = sz[-1:].lower()
|
1811
|
-
mi =
|
1812
|
-
"k": 1024,
|
1813
|
-
"m": 1024 * 1024,
|
1814
|
-
"g": 1024 * 1024 * 1024,
|
1815
|
-
"t": 1024 * 1024 * 1024 * 1024,
|
1816
|
-
}.get(mc, 1)
|
1823
|
+
mi = UNHUMANIZE_UNITS.get(mc, 1)
|
1817
1824
|
return int(float(sz[:-1]) * mi)
|
1818
1825
|
|
1819
1826
|
|
@@ -2496,6 +2503,7 @@ def sendfile_py(
|
|
2496
2503
|
s ,
|
2497
2504
|
bufsz ,
|
2498
2505
|
slp ,
|
2506
|
+
use_poll ,
|
2499
2507
|
) :
|
2500
2508
|
remains = upper - lower
|
2501
2509
|
f.seek(lower)
|
@@ -2524,22 +2532,31 @@ def sendfile_kern(
|
|
2524
2532
|
s ,
|
2525
2533
|
bufsz ,
|
2526
2534
|
slp ,
|
2535
|
+
use_poll ,
|
2527
2536
|
) :
|
2528
2537
|
out_fd = s.fileno()
|
2529
2538
|
in_fd = f.fileno()
|
2530
2539
|
ofs = lower
|
2531
2540
|
stuck = 0.0
|
2541
|
+
if use_poll:
|
2542
|
+
poll = select.poll()
|
2543
|
+
poll.register(out_fd, select.POLLOUT)
|
2544
|
+
|
2532
2545
|
while ofs < upper:
|
2533
2546
|
stuck = stuck or time.time()
|
2534
2547
|
try:
|
2535
2548
|
req = min(2 ** 30, upper - ofs)
|
2536
|
-
|
2549
|
+
if use_poll:
|
2550
|
+
poll.poll(10000)
|
2551
|
+
else:
|
2552
|
+
select.select([], [out_fd], [], 10)
|
2537
2553
|
n = os.sendfile(out_fd, in_fd, ofs, req)
|
2538
2554
|
stuck = 0
|
2539
2555
|
except OSError as ex:
|
2540
2556
|
# client stopped reading; do another select
|
2541
2557
|
d = time.time() - stuck
|
2542
2558
|
if d < 3600 and ex.errno == errno.EWOULDBLOCK:
|
2559
|
+
time.sleep(0.02)
|
2543
2560
|
continue
|
2544
2561
|
|
2545
2562
|
n = 0
|
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.18"
|
5
|
+
S_BUILD_DT = "2024-06-01"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -1144,7 +1144,7 @@ source file/folder selection uses rsync syntax, meaning that:
|
|
1144
1144
|
ap.add_argument("url", type=unicode, help="server url, including destination folder")
|
1145
1145
|
ap.add_argument("files", type=unicode, nargs="+", help="files and/or folders to process")
|
1146
1146
|
ap.add_argument("-v", action="store_true", help="verbose")
|
1147
|
-
ap.add_argument("-a", metavar="
|
1147
|
+
ap.add_argument("-a", metavar="PASSWD", help="password or $filepath")
|
1148
1148
|
ap.add_argument("-s", action="store_true", help="file-search (disables upload)")
|
1149
1149
|
ap.add_argument("-x", type=unicode, metavar="REGEX", default="", help="skip file if filesystem-abspath matches REGEX, example: '.*/\\.hist/.*'")
|
1150
1150
|
ap.add_argument("--ok", action="store_true", help="continue even if some local files are inaccessible")
|
@@ -1162,8 +1162,8 @@ source file/folder selection uses rsync syntax, meaning that:
|
|
1162
1162
|
ap.add_argument("--drd", action="store_true", help="delete remote files during upload instead of afterwards; reduces peak disk space usage, but will reupload instead of detecting renames")
|
1163
1163
|
|
1164
1164
|
ap = app.add_argument_group("performance tweaks")
|
1165
|
-
ap.add_argument("-j", type=int, metavar="
|
1166
|
-
ap.add_argument("-J", type=int, metavar="
|
1165
|
+
ap.add_argument("-j", type=int, metavar="CONNS", default=2, help="parallel connections")
|
1166
|
+
ap.add_argument("-J", type=int, metavar="CORES", default=hcores, help="num cpu-cores to use for hashing; set 0 or 1 for single-core hashing")
|
1167
1167
|
ap.add_argument("-nh", action="store_true", help="disable hashing while uploading")
|
1168
1168
|
ap.add_argument("-ns", action="store_true", help="no status panel (for slow consoles and macos)")
|
1169
1169
|
ap.add_argument("--cd", type=float, metavar="SEC", default=5, help="delay before reattempting a failed handshake/upload")
|
@@ -1171,7 +1171,7 @@ source file/folder selection uses rsync syntax, meaning that:
|
|
1171
1171
|
ap.add_argument("-z", action="store_true", help="ZOOMIN' (skip uploading files if they exist at the destination with the ~same last-modified timestamp, so same as yolo / turbo with date-chk but even faster)")
|
1172
1172
|
|
1173
1173
|
ap = app.add_argument_group("tls")
|
1174
|
-
ap.add_argument("-te", metavar="
|
1174
|
+
ap.add_argument("-te", metavar="PATH", help="path to ca.pem or cert.pem to expect/verify")
|
1175
1175
|
ap.add_argument("-td", action="store_true", help="disable certificate check")
|
1176
1176
|
# fmt: on
|
1177
1177
|
|
@@ -1208,6 +1208,14 @@ source file/folder selection uses rsync syntax, meaning that:
|
|
1208
1208
|
ar.url = ar.url.rstrip("/") + "/"
|
1209
1209
|
if "://" not in ar.url:
|
1210
1210
|
ar.url = "http://" + ar.url
|
1211
|
+
|
1212
|
+
if "https://" in ar.url.lower():
|
1213
|
+
try:
|
1214
|
+
import ssl, zipfile
|
1215
|
+
except:
|
1216
|
+
t = "ERROR: https is not available for some reason; please use http"
|
1217
|
+
print("\n\n %s\n\n" % (t,))
|
1218
|
+
raise
|
1211
1219
|
|
1212
1220
|
if ar.a and ar.a.startswith("$"):
|
1213
1221
|
fn = ar.a[1:]
|
copyparty/web/baguettebox.js.gz
CHANGED
Binary file
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/deps/marked.js.gz
CHANGED
Binary file
|
copyparty/web/md2.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.3
|
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
|
@@ -1,7 +1,7 @@
|
|
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=
|
2
|
+
copyparty/__main__.py,sha256=0z21tPU_24uD5Ule4pT5PhFKSmi774Q-pxi9lXt10Vw,100949
|
3
|
+
copyparty/__version__.py,sha256=x893bLkpUdr1zLkE3NI7Yqq_loU2TKQ_HgyT9bWygDY,254
|
4
|
+
copyparty/authsrv.py,sha256=kTf6iBchUDqb62oLypsQdTIsDY2NTn1D1YoZd8t1d1k,85272
|
5
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
|
@@ -11,28 +11,28 @@ 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=2lc__-IIOQsS_Lmsz6miwOobl0lLiyGHbXtOJYtag_4,164393
|
15
15
|
copyparty/httpconn.py,sha256=6MOQgBtOGrlVRr6ZiHBKYzkzcls-YWwaWEtqE6DweM0,6873
|
16
16
|
copyparty/httpsrv.py,sha256=RpROXBJPgTXmwFbLYrAT15ovGYkIMrksluuetKWAJTM,16356
|
17
17
|
copyparty/ico.py,sha256=AYHdK6NlYBfBgafVYXia3jHQ9XHZdUL1D8WftLMAzIU,3545
|
18
|
-
copyparty/mdns.py,sha256
|
18
|
+
copyparty/mdns.py,sha256=--Up4OLu8BMV3JQvl2xuqSx7nc5LcV6IadqD5Drrbj0,18152
|
19
19
|
copyparty/metrics.py,sha256=O8qiPNDxNjub_PI8C8Qu9rBQ_z0J1mnKonqkcTeAtf4,8845
|
20
|
-
copyparty/mtag.py,sha256=
|
20
|
+
copyparty/mtag.py,sha256=Eg7ioGzys25pf-f6GEL0j_rRL5nGe4jZzTMZMD0wxCU,18599
|
21
21
|
copyparty/multicast.py,sha256=Ha27l2oATEa-Qo2WOzkeRgjAm6G_YDCfbVJWR-ao2UE,12319
|
22
22
|
copyparty/pwhash.py,sha256=D82y8emnwpHDQq7Cr8lNuppHshbNA9ptcR2XsGOOk6E,3937
|
23
23
|
copyparty/smbd.py,sha256=CwsjLzwfIkqY9Fr_w7po_giO2tnXq9_7bdjIBNdiuTY,14062
|
24
|
-
copyparty/ssdp.py,sha256=
|
25
|
-
copyparty/star.py,sha256=
|
26
|
-
copyparty/sutil.py,sha256=
|
24
|
+
copyparty/ssdp.py,sha256=XVanfBewbriKJvHgP5QpDjJn-l8Jb7AoOQ2u53LYwUY,7042
|
25
|
+
copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
|
26
|
+
copyparty/sutil.py,sha256=xTw2jTrF3m3EXeh6E5Th810Axx5xVeMBNElkSwGb-Bo,3214
|
27
27
|
copyparty/svchub.py,sha256=v81cj-KQ3P7pLcV4sOWEjJSpGdjseZ2tpqL4VruPtmI,32661
|
28
|
-
copyparty/szip.py,sha256=
|
28
|
+
copyparty/szip.py,sha256=5xbfbnTKt97c59pZD_nAzWEYpMel7xFDuGUjj60VjOs,8619
|
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=JBazIKlw8oQXW2FLzqjokjqTk33c9V4Ke7Nx5ovoN-M,4560
|
32
|
+
copyparty/th_srv.py,sha256=tbRoaIb9WtUdVwjysxMYDbbEpRNvVwTh2Kj-_vCRbg8,28391
|
33
33
|
copyparty/u2idx.py,sha256=uEUcEbye1jzGlQfEJkLtD060XA6Rv_6lXLgeg6oAU5M,13033
|
34
|
-
copyparty/up2k.py,sha256=
|
35
|
-
copyparty/util.py,sha256=
|
34
|
+
copyparty/up2k.py,sha256=LuJS-DyxkVMq9AOJtiGjGr-9RaPxcrquFDO8LzfamYY,143358
|
35
|
+
copyparty/util.py,sha256=kRm2zAoHaihFBnA856iR8hfz8sXNNmYh7GsfnxuCVlw,84151
|
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
|
@@ -54,10 +54,10 @@ copyparty/stolen/ifaddr/__init__.py,sha256=_BUN7eM5oD2Jgib6B22tEFSb20fD9urNPPaAl
|
|
54
54
|
copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUuTOrU,2626
|
55
55
|
copyparty/stolen/ifaddr/_shared.py,sha256=cJACl8cOxQ-HSYphZTzKMAjAx_TAFyJwUPjfD102Xqw,6111
|
56
56
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
57
|
-
copyparty/web/baguettebox.js.gz,sha256=
|
58
|
-
copyparty/web/browser.css.gz,sha256=
|
57
|
+
copyparty/web/baguettebox.js.gz,sha256=hIlIpULK0O1MFPs2LNuyoRXMgRVYSvA5Db8eeVB8CSU,7909
|
58
|
+
copyparty/web/browser.css.gz,sha256=8AZ53KZ-fWInji7m-eGNrwdZbWEeLmyjwg1V23ON6Mc,11539
|
59
59
|
copyparty/web/browser.html,sha256=-tLasq2GKe9mUceqXG4PczQ7odBMrX0qlWuyaA9SjPI,4882
|
60
|
-
copyparty/web/browser.js.gz,sha256=
|
60
|
+
copyparty/web/browser.js.gz,sha256=kggLwqztclrse8G6I4GqlzmZ04wmPpMu06Qw0H6pm3U,68833
|
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
|
@@ -65,7 +65,7 @@ copyparty/web/md.css.gz,sha256=UZpN0J7ubVM05CZkbZYkQRJeGgJt_GNDEzKTGSQd8h4,2032
|
|
65
65
|
copyparty/web/md.html,sha256=35oLUnDYsAdiW7Zg-iKFEXzEl_bGbnoAxUrNgJL46_o,4119
|
66
66
|
copyparty/web/md.js.gz,sha256=AHRQ3a-PZq_UiGh4CjNwXRllJCvA0IqqYmeHhFWhCig,4179
|
67
67
|
copyparty/web/md2.css.gz,sha256=uIVHKScThdbcfhXNSHgKZnALYpxbnXC-WuEzOJ20Lpc,699
|
68
|
-
copyparty/web/md2.js.gz,sha256=
|
68
|
+
copyparty/web/md2.js.gz,sha256=0fTA3lahQ1iDvJR4Q3W9v8dX5hc5VP8nunTtoDwFySs,8363
|
69
69
|
copyparty/web/mde.css.gz,sha256=2SkAEDKIRPqywNJ8t_heQaeBQ_R73Rf-pQI_bDoKF6o,942
|
70
70
|
copyparty/web/mde.html,sha256=v0MsEinom5LmZzUM-Ht26IEUkrFzMX57XpCyIQXctAg,1687
|
71
71
|
copyparty/web/mde.js.gz,sha256=kN2eUSvr4mFuksfK4-4LimJmWdwsao39Sea2lWtu8L0,2224
|
@@ -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=Oj80BztQ9bNKP5invrLq99q7Wxw8PTiKAuUvn7lU2Rw,39040
|
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=0KvEM32CEJgafd23OBa4L27GyfCEQ6oRI-OoWhIkIcQ,22538
|
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.3.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
|
106
|
+
copyparty-1.13.3.dist-info/METADATA,sha256=HAszIqsIs6owRR8n9YyeA8h49mSnEqiKZ1QVgDNMCqg,122479
|
107
|
+
copyparty-1.13.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
108
|
+
copyparty-1.13.3.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
109
|
+
copyparty-1.13.3.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
110
|
+
copyparty-1.13.3.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|