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 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
- pass
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=float, default=0, help="ensure \033[33mGiB\033[0m free disk space by rejecting upload requests")
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
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 13, 2)
3
+ VERSION = (1, 13, 3)
4
4
  CODENAME = "race the beam"
5
- BUILD_DT = (2024, 5, 10)
5
+ BUILD_DT = (2024, 6, 1)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
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
- "{}g".format(self.args.df) if self.args.df else ""
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, lower, upper, f, self.s, self.args.s_wr_sz, self.args.s_wr_slp
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.args,
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
- rdy = select.select(self.srv, [], [], timeout)
300
- rx = rdy[0] # type: ignore
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
@@ -105,7 +105,9 @@ class MParser(object):
105
105
  raise Exception()
106
106
 
107
107
 
108
- def au_unpk(log , fmt_map , abspath , vn = None) :
108
+ def au_unpk(
109
+ log , fmt_map , abspath , vn = None
110
+ ) :
109
111
  ret = ""
110
112
  try:
111
113
  ext = abspath.split(".")[-1].lower()
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
- rdy = select.select(self.srv, [], [], self.args.z_chk or 180)
142
- rx = rdy[0] # type: ignore
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
- args ,
42
+ asrv ,
43
43
  fgen ,
44
44
  cmp = "",
45
45
  **kwargs
46
46
  ):
47
- super(StreamTar, self).__init__(log, args, fgen)
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
- args ,
18
+ asrv ,
19
19
  fgen ,
20
20
  **kwargs
21
21
  ):
22
22
  self.log = log
23
- self.args = args
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(errors ) :
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("\r\n".join(report).encode("utf-8", "replace"))
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
- args ,
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, args, fgen)
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
@@ -103,7 +103,7 @@ class ThumbCli(object):
103
103
  sfmt += "3" if "3" in fmt else ""
104
104
 
105
105
  fmt = sfmt
106
-
106
+
107
107
  elif fmt[:1] == "p" and not is_au:
108
108
  t = "cannot thumbnail [%s]: png only allowed for waveforms"
109
109
  self.log(t % (rem), 6)
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", fsenc(wtpath),
600
- fsenc(tpath)
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, vn.flags)
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
- ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
674
- if "ac" not in ret:
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
- b"-map_metadata", b"-1",
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
- ret, _ = ffprobe(abspath, int(vn.flags["convt"] / 2))
712
- if "ac" not in ret:
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 = ret[".dur"][1]
717
+ dur = tags[".dur"][1]
717
718
  except:
718
719
  dur = 0
719
720
 
720
- src_opus = abspath.lower().endswith(".opus") or ret["ac"][1] == "opus"
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
- b"-map_metadata", b"-1",
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 " + vol.realpath, c=1)
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 ["B", "KiB", "MiB", "GiB", "TiB"]:
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
- select.select([], [out_fd], [], 10)
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.17"
5
- S_BUILD_DT = "2024-05-09"
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="PASSWORD", help="password or $filepath")
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="THREADS", default=4, help="parallel connections")
1166
- ap.add_argument("-J", type=int, metavar="THREADS", default=hcores, help="num cpu-cores to use for hashing; set 0 or 1 for single-core hashing")
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="PEM_FILE", help="certificate to expect/verify")
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:]
Binary file
Binary file
Binary file
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.2
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=eHd9z3x3VWKFULKcb37iBuWCUbYDRokq1UFjGHI5njU,99846
3
- copyparty/__version__.py,sha256=HXaSfRCwDZ1gm9Ow7Po9NDC2KxGntKPiZkjTR_ujvpM,255
4
- copyparty/authsrv.py,sha256=4YPt9_VqqcDAdaur4JN809jKUlpAyamVe-1JaeMUkOQ,85177
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=wif37Oa89iAer5sIMoZPWChyWif80AFH7lOaG00h2z0,164293
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=CcraggbDxTT1ntYzD8Ebgqmw5Q4HkyZcfh5ymtCV_ak,17469
18
+ copyparty/mdns.py,sha256=--Up4OLu8BMV3JQvl2xuqSx7nc5LcV6IadqD5Drrbj0,18152
19
19
  copyparty/metrics.py,sha256=O8qiPNDxNjub_PI8C8Qu9rBQ_z0J1mnKonqkcTeAtf4,8845
20
- copyparty/mtag.py,sha256=MpRkwAj_OAhE9alRzYMyoyPUtedSIuBmVxhCkLaIpMA,18593
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=H6ZftXttydcnBxcg2-Prm4P-XiybgT3xiJRUXU1pbrE,6343
25
- copyparty/star.py,sha256=K4NuzyfT4956uoW6GJSQ2II-JsSV57apQZwRZ4mjFoo,3790
26
- copyparty/sutil.py,sha256=_G4TM0YFa1vXzhRypHJ88QBdZWtYgDbom4CZjGvGIwc,3074
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=631TsEwGKV22yAnusJtvE-9fGFWr61HPGBinu-jk1QA,8591
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=VO2Eo0SGwgSJaHowMLeX3_vxEdQcQh5RFDSf0OraTTw,4568
32
- copyparty/th_srv.py,sha256=utK8kA1mlYI0BsAdLL-l0-51gXoIN0BS5zQkGAcERXg,28041
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=hhh7PrUzRgnlvsapwjG1-X6_bqI51r3Tf5zo4jLvveU,143330
35
- copyparty/util.py,sha256=w22CaPQy0Otq8sJMt9hCPpRbKM2sRLTQtBYAE6DTaHQ,83744
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=HdRHC_4Lvepp1DrRwusdcxvAn8IKGMdrKdggGIshKek,7869
58
- copyparty/web/browser.css.gz,sha256=GGyPK9BBOX63x9XWqO2jrXewHtfAeZ-Jo0BBxqTOGUM,11491
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=Lci32Xx_OxmC9bjEuiQSzfMrb8UGj9Qg5j2D7kOcFjY,68838
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=8xLixaTfTXC808538OOSLhp9AqKowYaunjDeBsbiBEw,8350
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=mCVYSJo6wSiPrT_p7QxlIoIGSclcC7qw4COcIaAKS-w,38791
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=elpt4-fI9Fs5zgMYxHuQn7XL4MXMBfINU4WQ0sBF5HY,22582
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.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,,
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,,