copyparty 1.16.0__py3-none-any.whl → 1.16.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 CHANGED
@@ -870,8 +870,9 @@ def get_sects():
870
870
  use argon2id with timecost 3, 256 MiB, 4 threads, version 19 (0x13/v1.3)
871
871
 
872
872
  \033[36m--ah-alg scrypt\033[0m # which is the same as:
873
- \033[36m--ah-alg scrypt,13,2,8,4\033[0m
874
- use scrypt with cost 2**13, 2 iterations, blocksize 8, 4 threads
873
+ \033[36m--ah-alg scrypt,13,2,8,4,32\033[0m
874
+ use scrypt with cost 2**13, 2 iterations, blocksize 8, 4 threads,
875
+ and allow using up to 32 MiB RAM (ram=cost*blksz roughly)
875
876
 
876
877
  \033[36m--ah-alg sha2\033[0m # which is the same as:
877
878
  \033[36m--ah-alg sha2,424242\033[0m
@@ -1343,12 +1344,12 @@ def add_thumbnail(ap):
1343
1344
  # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html
1344
1345
  # https://github.com/libvips/libvips
1345
1346
  # ffmpeg -hide_banner -demuxers | awk '/^ D /{print$2}' | while IFS= read -r x; do ffmpeg -hide_banner -h demuxer=$x; done | grep -E '^Demuxer |extensions:'
1346
- ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="avif,avifs,blp,bmp,dcx,dds,dib,emf,eps,fits,flc,fli,fpx,gif,heic,heics,heif,heifs,icns,ico,im,j2p,j2k,jp2,jpeg,jpg,jpx,pbm,pcx,pgm,png,pnm,ppm,psd,qoi,sgi,spi,tga,tif,tiff,webp,wmf,xbm,xpm", help="image formats to decode using pillow")
1347
+ ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="avif,avifs,blp,bmp,cbz,dcx,dds,dib,emf,eps,fits,flc,fli,fpx,gif,heic,heics,heif,heifs,icns,ico,im,j2p,j2k,jp2,jpeg,jpg,jpx,pbm,pcx,pgm,png,pnm,ppm,psd,qoi,sgi,spi,tga,tif,tiff,webp,wmf,xbm,xpm", help="image formats to decode using pillow")
1347
1348
  ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips")
1348
- ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
1349
+ ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg")
1349
1350
  ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg")
1350
1351
  ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg")
1351
- ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz", help="audio formats to decompress before passing to ffmpeg")
1352
+ ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz", help="audio/image formats to decompress before passing to ffmpeg")
1352
1353
 
1353
1354
 
1354
1355
  def add_transcoding(ap):
@@ -1448,6 +1449,7 @@ def add_ui(ap, retry):
1448
1449
  ap2.add_argument("--themes", metavar="NUM", type=int, default=8, help="number of themes installed")
1449
1450
  ap2.add_argument("--au-vol", metavar="0-100", type=int, default=50, choices=range(0, 101), help="default audio/video volume percent")
1450
1451
  ap2.add_argument("--sort", metavar="C,C,C", type=u, default="href", help="default sort order, comma-separated column IDs (see header tooltips), prefix with '-' for descending. Examples: \033[32mhref -href ext sz ts tags/Album tags/.tn\033[0m (volflag=sort)")
1452
+ ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
1451
1453
  ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
1452
1454
  ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
1453
1455
  ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])")
copyparty/__version__.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 16, 0)
3
+ VERSION = (1, 16, 2)
4
4
  CODENAME = "COPYparty"
5
- BUILD_DT = (2024, 11, 10)
5
+ BUILD_DT = (2024, 11, 23)
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
@@ -360,18 +360,21 @@ class VFS(object):
360
360
  self.ahtml = {}
361
361
  self.aadmin = {}
362
362
  self.adot = {}
363
- self.all_vols = {}
363
+ self.js_ls = {}
364
+ self.js_htm = ""
364
365
 
365
366
  if realpath:
366
367
  rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
367
368
  vp = vpath + ("/" if vpath else "")
368
369
  self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
369
370
  self.all_vols = {vpath: self} # flattened recursive
371
+ self.all_nodes = {vpath: self} # also jumpvols
370
372
  self.all_aps = [(rp, self)]
371
373
  self.all_vps = [(vp, self)]
372
374
  else:
373
375
  self.histpath = ""
374
376
  self.all_vols = {}
377
+ self.all_nodes = {}
375
378
  self.all_aps = []
376
379
  self.all_vps = []
377
380
 
@@ -389,9 +392,11 @@ class VFS(object):
389
392
  def get_all_vols(
390
393
  self,
391
394
  vols ,
395
+ nodes ,
392
396
  aps ,
393
397
  vps ,
394
398
  ) :
399
+ nodes[self.vpath] = self
395
400
  if self.realpath:
396
401
  vols[self.vpath] = self
397
402
  rp = self.realpath
@@ -401,7 +406,7 @@ class VFS(object):
401
406
  vps.append((vp, self))
402
407
 
403
408
  for v in self.nodes.values():
404
- v.get_all_vols(vols, aps, vps)
409
+ v.get_all_vols(vols, nodes, aps, vps)
405
410
 
406
411
  def add(self, src , dst ) :
407
412
  """get existing, or add new path to the vfs"""
@@ -1528,10 +1533,11 @@ class AuthSrv(object):
1528
1533
 
1529
1534
  assert vfs # type: ignore
1530
1535
  vfs.all_vols = {}
1536
+ vfs.all_nodes = {}
1531
1537
  vfs.all_aps = []
1532
1538
  vfs.all_vps = []
1533
- vfs.get_all_vols(vfs.all_vols, vfs.all_aps, vfs.all_vps)
1534
- for vol in vfs.all_vols.values():
1539
+ vfs.get_all_vols(vfs.all_vols, vfs.all_nodes, vfs.all_aps, vfs.all_vps)
1540
+ for vol in vfs.all_nodes.values():
1535
1541
  vol.all_aps.sort(key=lambda x: len(x[0]), reverse=True)
1536
1542
  vol.all_vps.sort(key=lambda x: len(x[0]), reverse=True)
1537
1543
  vol.root = vfs
@@ -1582,7 +1588,7 @@ class AuthSrv(object):
1582
1588
 
1583
1589
  vfs.nodes[shr] = vfs.all_vols[shr] = shv
1584
1590
  for vol in shv.nodes.values():
1585
- vfs.all_vols[vol.vpath] = vol
1591
+ vfs.all_vols[vol.vpath] = vfs.all_nodes[vol.vpath] = vol
1586
1592
  vol.get_dbv = vol._get_share_src
1587
1593
  vol.ls = vol._ls_nope
1588
1594
 
@@ -1725,7 +1731,19 @@ class AuthSrv(object):
1725
1731
 
1726
1732
  self.log("\n\n".join(ta) + "\n", c=3)
1727
1733
 
1728
- vfs.histtab = {zv.realpath: zv.histpath for zv in vfs.all_vols.values()}
1734
+ rhisttab = {}
1735
+ vfs.histtab = {}
1736
+ for zv in vfs.all_vols.values():
1737
+ histp = zv.histpath
1738
+ is_shr = shr and zv.vpath.split("/")[0] == shr
1739
+ if histp and not is_shr and histp in rhisttab:
1740
+ zv2 = rhisttab[histp]
1741
+ t = "invalid config; multiple volumes share the same histpath (database location):\n histpath: %s\n volume 1: /%s [%s]\n volume 2: %s [%s]"
1742
+ t = t % (histp, zv2.vpath, zv2.realpath, zv.vpath, zv.realpath)
1743
+ self.log(t, 1)
1744
+ raise Exception(t)
1745
+ rhisttab[histp] = zv
1746
+ vfs.histtab[zv.realpath] = histp
1729
1747
 
1730
1748
  for vol in vfs.all_vols.values():
1731
1749
  lim = Lim(self.log_func)
@@ -1784,12 +1802,12 @@ class AuthSrv(object):
1784
1802
  vol.lim = lim
1785
1803
 
1786
1804
  if self.args.no_robots:
1787
- for vol in vfs.all_vols.values():
1805
+ for vol in vfs.all_nodes.values():
1788
1806
  # volflag "robots" overrides global "norobots", allowing indexing by search engines for this vol
1789
1807
  if not vol.flags.get("robots"):
1790
1808
  vol.flags["norobots"] = True
1791
1809
 
1792
- for vol in vfs.all_vols.values():
1810
+ for vol in vfs.all_nodes.values():
1793
1811
  if self.args.no_vthumb:
1794
1812
  vol.flags["dvthumb"] = True
1795
1813
  if self.args.no_athumb:
@@ -1801,7 +1819,7 @@ class AuthSrv(object):
1801
1819
  vol.flags["dithumb"] = True
1802
1820
 
1803
1821
  have_fk = False
1804
- for vol in vfs.all_vols.values():
1822
+ for vol in vfs.all_nodes.values():
1805
1823
  fk = vol.flags.get("fk")
1806
1824
  fka = vol.flags.get("fka")
1807
1825
  if fka and not fk:
@@ -1833,7 +1851,7 @@ class AuthSrv(object):
1833
1851
  zs = os.path.join(E.cfg, "fk-salt.txt")
1834
1852
  self.log(t % (fk_len, 16, zs), 3)
1835
1853
 
1836
- for vol in vfs.all_vols.values():
1854
+ for vol in vfs.all_nodes.values():
1837
1855
  if "pk" in vol.flags and "gz" not in vol.flags and "xz" not in vol.flags:
1838
1856
  vol.flags["gz"] = False # def.pk
1839
1857
 
@@ -1844,7 +1862,7 @@ class AuthSrv(object):
1844
1862
 
1845
1863
  all_mte = {}
1846
1864
  errors = False
1847
- for vol in vfs.all_vols.values():
1865
+ for vol in vfs.all_nodes.values():
1848
1866
  if (self.args.e2ds and vol.axs.uwrite) or self.args.e2dsa:
1849
1867
  vol.flags["e2ds"] = True
1850
1868
 
@@ -2062,7 +2080,7 @@ class AuthSrv(object):
2062
2080
  errors = True
2063
2081
 
2064
2082
  have_daw = False
2065
- for vol in vfs.all_vols.values():
2083
+ for vol in vfs.all_nodes.values():
2066
2084
  daw = vol.flags.get("daw") or self.args.daw
2067
2085
  if daw:
2068
2086
  vol.flags["daw"] = True
@@ -2077,13 +2095,12 @@ class AuthSrv(object):
2077
2095
  self.log("--smb can only be used when --ah-alg is none", 1)
2078
2096
  errors = True
2079
2097
 
2080
- for vol in vfs.all_vols.values():
2098
+ for vol in vfs.all_nodes.values():
2081
2099
  for k in list(vol.flags.keys()):
2082
2100
  if re.match("^-[^-]+$", k):
2083
2101
  vol.flags.pop(k[1:], None)
2084
2102
  vol.flags.pop(k)
2085
2103
 
2086
- for vol in vfs.all_vols.values():
2087
2104
  if vol.flags.get("dots"):
2088
2105
  for name in vol.axs.uread:
2089
2106
  vol.axs.udot.add(name)
@@ -2225,6 +2242,11 @@ class AuthSrv(object):
2225
2242
  for x, y in vfs.all_vols.items()
2226
2243
  if x != shr and not x.startswith(shrs)
2227
2244
  }
2245
+ vfs.all_nodes = {
2246
+ x: y
2247
+ for x, y in vfs.all_nodes.items()
2248
+ if x != shr and not x.startswith(shrs)
2249
+ }
2228
2250
 
2229
2251
  assert db and cur and cur2 and shv # type: ignore
2230
2252
  for row in cur.execute("select * from sh"):
@@ -2277,6 +2299,68 @@ class AuthSrv(object):
2277
2299
  cur.close()
2278
2300
  db.close()
2279
2301
 
2302
+ self.js_ls = {}
2303
+ self.js_htm = {}
2304
+ for vn in self.vfs.all_nodes.values():
2305
+ vf = vn.flags
2306
+ vn.js_ls = {
2307
+ "idx": "e2d" in vf,
2308
+ "itag": "e2t" in vf,
2309
+ "dnsort": "nsort" in vf,
2310
+ "dsort": vf["sort"],
2311
+ "dcrop": vf["crop"],
2312
+ "dth3x": vf["th3x"],
2313
+ "u2ts": vf["u2ts"],
2314
+ "frand": bool(vf.get("rand")),
2315
+ "lifetime": vf.get("lifetime") or 0,
2316
+ "unlist": vf.get("unlist") or "",
2317
+ }
2318
+ js_htm = {
2319
+ "s_name": self.args.bname,
2320
+ "have_up2k_idx": "e2d" in vf,
2321
+ "have_acode": not self.args.no_acode,
2322
+ "have_shr": self.args.shr,
2323
+ "have_zip": not self.args.no_zip,
2324
+ "have_mv": not self.args.no_mv,
2325
+ "have_del": not self.args.no_del,
2326
+ "have_unpost": int(self.args.unpost),
2327
+ "have_emp": self.args.emp,
2328
+ "sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
2329
+ "txt_ext": self.args.textfiles.replace(",", " "),
2330
+ "def_hcols": list(vf.get("mth") or []),
2331
+ "unlist0": vf.get("unlist") or "",
2332
+ "dgrid": "grid" in vf,
2333
+ "dgsel": "gsel" in vf,
2334
+ "dnsort": "nsort" in vf,
2335
+ "dsort": vf["sort"],
2336
+ "dcrop": vf["crop"],
2337
+ "dth3x": vf["th3x"],
2338
+ "dvol": self.args.au_vol,
2339
+ "idxh": int(self.args.ih),
2340
+ "themes": self.args.themes,
2341
+ "turbolvl": self.args.turbo,
2342
+ "u2j": self.args.u2j,
2343
+ "u2sz": self.args.u2sz,
2344
+ "u2ts": vf["u2ts"],
2345
+ "frand": bool(vf.get("rand")),
2346
+ "lifetime": vn.js_ls["lifetime"],
2347
+ "u2sort": self.args.u2sort,
2348
+ }
2349
+ vn.js_htm = json.dumps(js_htm)
2350
+
2351
+ vols = list(vfs.all_nodes.values())
2352
+ if enshare:
2353
+ vols.append(shv)
2354
+ vols.extend(list(shv.nodes.values()))
2355
+
2356
+ for vol in vols:
2357
+ dbv = vol.get_dbv("")[0]
2358
+ vol.js_ls = vol.js_ls or dbv.js_ls or {}
2359
+ vol.js_htm = vol.js_htm or dbv.js_htm or "{}"
2360
+
2361
+ zs = str(vol.flags.get("tcolor") or self.args.tcolor)
2362
+ vol.flags["tcolor"] = zs.lstrip("#")
2363
+
2280
2364
  def load_sessions(self, quiet=False) :
2281
2365
  # mutex me
2282
2366
  if self.args.no_ses:
copyparty/cfg.py CHANGED
@@ -42,6 +42,7 @@ def vf_bmap() :
42
42
  "magic",
43
43
  "no_sb_md",
44
44
  "no_sb_lg",
45
+ "nsort",
45
46
  "og",
46
47
  "og_no_head",
47
48
  "og_s_title",
copyparty/httpcli.py CHANGED
@@ -243,7 +243,6 @@ class HttpCli(object):
243
243
  ka["ts"] = self.conn.hsrv.cachebuster()
244
244
  ka["lang"] = self.args.lang
245
245
  ka["favico"] = self.args.favico
246
- ka["s_name"] = self.args.bname
247
246
  ka["s_doctitle"] = self.args.doctitle
248
247
  ka["tcolor"] = self.vn.flags["tcolor"]
249
248
 
@@ -700,7 +699,7 @@ class HttpCli(object):
700
699
 
701
700
  if pex.code != 404 or self.do_log:
702
701
  self.log(
703
- "%s\033[0m, %s" % (msg, self.vpath),
702
+ "http%d: %s\033[0m, %s" % (pex.code, msg, self.vpath),
704
703
  6 if em.startswith("client d/c ") else 3,
705
704
  )
706
705
 
@@ -1409,12 +1408,13 @@ class HttpCli(object):
1409
1408
  vst = os.stat_result((16877, -1, -1, 1, 1000, 1000, 8, zi, zi, zi))
1410
1409
 
1411
1410
  try:
1412
- topdir = {"vp": "", "st": bos.stat(tap)}
1411
+ st = bos.stat(tap)
1413
1412
  except OSError as ex:
1414
1413
  if ex.errno not in (errno.ENOENT, errno.ENOTDIR):
1415
1414
  raise
1416
1415
  raise Pebkac(404)
1417
1416
 
1417
+ topdir = {"vp": "", "st": st}
1418
1418
  fgen = []
1419
1419
 
1420
1420
  depth = self.headers.get("depth", "infinity").lower()
@@ -1450,6 +1450,12 @@ class HttpCli(object):
1450
1450
  wrap=False,
1451
1451
  )
1452
1452
 
1453
+ elif depth == "0" or not stat.S_ISDIR(st.st_mode):
1454
+ # propfind on a file; return as topdir
1455
+ if not self.can_read and not self.can_get:
1456
+ self.log("inaccessible: [%s]" % (self.vpath,))
1457
+ raise Pebkac(401, "authenticate")
1458
+
1453
1459
  elif depth == "1":
1454
1460
  _, vfs_ls, vfs_virt = vn.ls(
1455
1461
  rem,
@@ -1468,9 +1474,6 @@ class HttpCli(object):
1468
1474
  fgen = [{"vp": vp, "st": st} for vp, st in vfs_ls]
1469
1475
  fgen += [{"vp": v, "st": vst} for v in vfs_virt]
1470
1476
 
1471
- elif depth == "0":
1472
- pass
1473
-
1474
1477
  else:
1475
1478
  t = "invalid depth value '{}' (must be either '0' or '1'{})"
1476
1479
  t2 = " or 'infinity'" if self.args.dav_inf else ""
@@ -5474,61 +5477,28 @@ class HttpCli(object):
5474
5477
  is_js = False
5475
5478
 
5476
5479
  vf = vn.flags
5477
- unlist = vf.get("unlist", "")
5478
5480
  ls_ret = {
5479
5481
  "dirs": [],
5480
5482
  "files": [],
5481
5483
  "taglist": [],
5482
5484
  "srvinf": srv_infot,
5483
5485
  "acct": self.uname,
5484
- "idx": e2d,
5485
- "itag": e2t,
5486
- "dsort": vf["sort"],
5487
- "dcrop": vf["crop"],
5488
- "dth3x": vf["th3x"],
5489
- "u2ts": vf["u2ts"],
5490
- "lifetime": vn.flags.get("lifetime") or 0,
5491
- "frand": bool(vn.flags.get("rand")),
5492
- "unlist": unlist,
5493
5486
  "perms": perms,
5487
+ "cfg": vn.js_ls,
5494
5488
  }
5495
5489
  cgv = {
5496
5490
  "ls0": None,
5497
5491
  "acct": self.uname,
5498
5492
  "perms": perms,
5499
- "u2ts": vf["u2ts"],
5500
- "lifetime": ls_ret["lifetime"],
5501
- "frand": bool(vn.flags.get("rand")),
5502
- "def_hcols": [],
5503
- "have_emp": self.args.emp,
5504
- "have_up2k_idx": e2d,
5505
- "have_acode": (not self.args.no_acode),
5506
- "have_mv": (not self.args.no_mv),
5507
- "have_del": (not self.args.no_del),
5508
- "have_zip": (not self.args.no_zip),
5509
- "have_shr": self.args.shr,
5510
- "have_unpost": int(self.args.unpost),
5511
- "sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
5512
- "dgrid": "grid" in vf,
5513
- "dgsel": "gsel" in vf,
5514
- "dsort": vf["sort"],
5515
- "dcrop": vf["crop"],
5516
- "dth3x": vf["th3x"],
5517
- "dvol": self.args.au_vol,
5518
- "themes": self.args.themes,
5519
- "turbolvl": self.args.turbo,
5520
- "u2j": self.args.u2j,
5521
- "u2sz": self.args.u2sz,
5522
- "idxh": int(self.args.ih),
5523
- "u2sort": self.args.u2sort,
5524
5493
  }
5525
5494
  j2a = {
5495
+ "cgv1": vn.js_htm,
5526
5496
  "cgv": cgv,
5527
5497
  "vpnodes": vpnodes,
5528
5498
  "files": [],
5529
5499
  "ls0": None,
5530
5500
  "taglist": [],
5531
- "have_tags_idx": e2t,
5501
+ "have_tags_idx": int(e2t),
5532
5502
  "have_b_u": (self.can_write and self.uparam.get("b") == "u"),
5533
5503
  "sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"),
5534
5504
  "url_suf": url_suf,
@@ -5899,17 +5869,12 @@ class HttpCli(object):
5899
5869
  "dirs": dirs,
5900
5870
  "files": files,
5901
5871
  "taglist": taglist,
5902
- "unlist": unlist,
5903
5872
  }
5904
5873
  j2a["files"] = []
5905
5874
  else:
5906
5875
  j2a["files"] = dirs + files
5907
5876
 
5908
5877
  j2a["taglist"] = taglist
5909
- j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
5910
-
5911
- if "mth" in vn.flags:
5912
- j2a["def_hcols"] = list(vn.flags["mth"])
5913
5878
 
5914
5879
  if add_og and "raw" not in self.uparam:
5915
5880
  j2a["this"] = self
copyparty/httpsrv.py CHANGED
@@ -132,7 +132,7 @@ class HttpSrv(object):
132
132
  dls = {} # state
133
133
  self.dli = self.tdli = dli
134
134
  self.dls = self.tdls = dls
135
- self.iiam = '<img src="%s.cpr/iiam.gif" />' % (self.args.SRS,)
135
+ self.iiam = '<img src="%s.cpr/iiam.gif?cache=i" />' % (self.args.SRS,)
136
136
 
137
137
  self.bound = set()
138
138
  self.name = "hsrv" + nsuf
@@ -607,7 +607,7 @@ class HttpSrv(object):
607
607
  """
608
608
  dli = {}
609
609
  for k, (a, b, c, d, e) in sdli.items():
610
- vn = self.asrv.vfs.all_vols[c]
610
+ vn = self.asrv.vfs.all_nodes[c]
611
611
  dli[k] = (a, b, vn, d, e)
612
612
 
613
613
  self.tdli = dli
copyparty/mtag.py CHANGED
@@ -4,6 +4,7 @@ from __future__ import print_function, unicode_literals
4
4
  import argparse
5
5
  import json
6
6
  import os
7
+ import re
7
8
  import shutil
8
9
  import subprocess as sp
9
10
  import sys
@@ -56,6 +57,9 @@ def have_ff(scmd ) :
56
57
  HAVE_FFMPEG = not os.environ.get("PRTY_NO_FFMPEG") and have_ff("ffmpeg")
57
58
  HAVE_FFPROBE = not os.environ.get("PRTY_NO_FFPROBE") and have_ff("ffprobe")
58
59
 
60
+ CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif".split())
61
+ CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b")
62
+
59
63
 
60
64
  class MParser(object):
61
65
  def __init__(self, cmdline ) :
@@ -120,6 +124,7 @@ def au_unpk(
120
124
  log , fmt_map , abspath , vn = None
121
125
  ) :
122
126
  ret = ""
127
+ maxsz = 1024 * 1024 * 64
123
128
  try:
124
129
  ext = abspath.split(".")[-1].lower()
125
130
  au, pk = fmt_map[ext].split(".")
@@ -142,17 +147,41 @@ def au_unpk(
142
147
  zf = zipfile.ZipFile(abspath, "r")
143
148
  zil = zf.infolist()
144
149
  zil = [x for x in zil if x.filename.lower().split(".")[-1] == au]
150
+ if not zil:
151
+ raise Exception("no audio inside zip")
145
152
  fi = zf.open(zil[0])
146
153
 
154
+ elif pk == "cbz":
155
+ import zipfile
156
+
157
+ zf = zipfile.ZipFile(abspath, "r")
158
+ znil = [(x.filename.lower(), x) for x in zf.infolist()]
159
+ nf = len(znil)
160
+ znil = [x for x in znil if x[0].split(".")[-1] in CBZ_PICS]
161
+ znil = [x for x in znil if "cover" in x[0]] or znil
162
+ znil = [x for x in znil if CBZ_01.search(x[0])] or znil
163
+ t = "cbz: %d files, %d hits" % (nf, len(znil))
164
+ if znil:
165
+ t += ", using " + znil[0][1].filename
166
+ log(t)
167
+ if not znil:
168
+ raise Exception("no images inside cbz")
169
+ fi = zf.open(znil[0][1])
170
+
147
171
  else:
148
172
  raise Exception("unknown compression %s" % (pk,))
149
173
 
174
+ fsz = 0
150
175
  with os.fdopen(fd, "wb") as fo:
151
176
  while True:
152
177
  buf = fi.read(32768)
153
178
  if not buf:
154
179
  break
155
180
 
181
+ fsz += len(buf)
182
+ if fsz > maxsz:
183
+ raise Exception("zipbomb defused")
184
+
156
185
  fo.write(buf)
157
186
 
158
187
  return ret
copyparty/pwhash.py CHANGED
@@ -24,17 +24,13 @@ class PWHash(object):
24
24
  def __init__(self, args ):
25
25
  self.args = args
26
26
 
27
- try:
28
- alg, ac = args.ah_alg.split(",")
29
- except:
30
- alg = args.ah_alg
31
- ac = {}
32
-
27
+ zsl = args.ah_alg.split(",")
28
+ alg = zsl[0]
33
29
  if alg == "none":
34
30
  alg = ""
35
31
 
36
32
  self.alg = alg
37
- self.ac = ac
33
+ self.ac = zsl[1:]
38
34
  if not alg:
39
35
  self.on = False
40
36
  self.hash = unicode
@@ -90,17 +86,23 @@ class PWHash(object):
90
86
  its = 2
91
87
  blksz = 8
92
88
  para = 4
89
+ ramcap = 0 # openssl 1.1 = 32 MiB
93
90
  try:
94
91
  cost = 2 << int(self.ac[0])
95
92
  its = int(self.ac[1])
96
93
  blksz = int(self.ac[2])
97
94
  para = int(self.ac[3])
95
+ ramcap = int(self.ac[4]) * 1024 * 1024
98
96
  except:
99
97
  pass
100
98
 
99
+ cfg = {"salt": self.salt, "n": cost, "r": blksz, "p": para, "dklen": 24}
100
+ if ramcap:
101
+ cfg["maxmem"] = ramcap
102
+
101
103
  ret = plain.encode("utf-8")
102
104
  for _ in range(its):
103
- ret = hashlib.scrypt(ret, salt=self.salt, n=cost, r=blksz, p=para, dklen=24)
105
+ ret = hashlib.scrypt(ret, **cfg)
104
106
 
105
107
  return "+" + base64.urlsafe_b64encode(ret).decode("utf-8")
106
108
 
copyparty/res/COPYING.txt CHANGED
@@ -77,83 +77,19 @@ License: SIL OFL 1.1
77
77
 
78
78
  --- MIT License ---
79
79
 
80
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
81
-
82
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
83
-
84
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
85
80
 
86
81
 
87
82
  --- ISC License ---
88
83
 
89
- Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.
90
-
91
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
92
84
 
93
85
 
94
86
  --- BSD 2-Clause License ---
95
87
 
96
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
97
-
98
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
99
-
100
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
101
-
102
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
103
88
 
104
89
 
105
90
  --- BSD 3-Clause License ---
106
91
 
107
- Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
108
-
109
- 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
110
-
111
- 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
112
-
113
- 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
114
-
115
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
116
92
 
117
93
 
118
94
  --- SIL Open Font License v1.1 ---
119
95
 
120
- PREAMBLE
121
-
122
- The goals of the Open Font License (OFL) are to stimulate worldwide development of collaborative font projects, to support the font creation efforts of academic and linguistic communities, and to provide a free and open framework in which fonts may be shared and improved in partnership with others.
123
-
124
- The OFL allows the licensed fonts to be used, studied, modified and redistributed freely as long as they are not sold by themselves. The fonts, including any derivative works, can be bundled, embedded, redistributed and/or sold with any software provided that any reserved names are not used by derivative works. The fonts and derivatives, however, cannot be released under any other type of license. The requirement for fonts to remain under this license does not apply to any document created using the fonts or their derivatives.
125
-
126
- DEFINITIONS
127
-
128
- "Font Software" refers to the set of files released by the Copyright Holder(s) under this license and clearly marked as such. This may include source files, build scripts and documentation.
129
-
130
- "Reserved Font Name" refers to any names specified as such after the copyright statement(s).
131
-
132
- "Original Version" refers to the collection of Font Software components as distributed by the Copyright Holder(s).
133
-
134
- "Modified Version" refers to any derivative made by adding to, deleting, or substituting - in part or in whole - any of the components of the Original Version, by changing formats or by porting the Font Software to a new environment.
135
-
136
- "Author" refers to any designer, engineer, programmer, technical writer or other person who contributed to the Font Software.
137
-
138
- PERMISSION & CONDITIONS
139
-
140
- Permission is hereby granted, free of charge, to any person obtaining a copy of the Font Software, to use, study, copy, merge, embed, modify, redistribute, and sell modified and unmodified copies of the Font Software, subject to the following conditions:
141
-
142
- 1) Neither the Font Software nor any of its individual components, in Original or Modified Versions, may be sold by itself.
143
-
144
- 2) Original or Modified Versions of the Font Software may be bundled, redistributed and/or sold with any software, provided that each copy contains the above copyright notice and this license. These can be included either as stand-alone text files, human-readable headers or in the appropriate machine-readable metadata fields within text or binary files as long as those fields can be easily viewed by the user.
145
-
146
- 3) No Modified Version of the Font Software may use the Reserved Font Name(s) unless explicit written permission is granted by the corresponding Copyright Holder. This restriction only applies to the primary font name as presented to the users.
147
-
148
- 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font Software shall not be used to promote, endorse or advertise any Modified Version, except to acknowledge the contribution(s) of the Copyright Holder(s) and the Author(s) or with their explicit written permission.
149
-
150
- 5) The Font Software, modified or unmodified, in part or in whole, must be distributed entirely under this license, and must not be distributed under any other license. The requirement for fonts to remain under this license does not apply to any document created using the Font Software.
151
-
152
- TERMINATION
153
-
154
- This license becomes null and void if any of the above conditions are not met.
155
-
156
- DISCLAIMER
157
-
158
- THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
159
-
copyparty/u2idx.py CHANGED
@@ -66,6 +66,9 @@ class U2idx(object):
66
66
  self.log_func("u2idx", msg, c)
67
67
 
68
68
  def shutdown(self) :
69
+ if not HAVE_SQLITE3:
70
+ return
71
+
69
72
  for cur in self.cur.values():
70
73
  db = cur.connection
71
74
  try:
@@ -76,6 +79,12 @@ class U2idx(object):
76
79
  cur.close()
77
80
  db.close()
78
81
 
82
+ for cur in (self.mem_cur, self.sh_cur):
83
+ if cur:
84
+ db = cur.connection
85
+ cur.close()
86
+ db.close()
87
+
79
88
  def fsearch(
80
89
  self, uname , vols , body
81
90
  ) :
copyparty/up2k.py CHANGED
@@ -5273,6 +5273,11 @@ class Up2k(object):
5273
5273
  cur.close()
5274
5274
  db.close()
5275
5275
 
5276
+ if self.mem_cur:
5277
+ db = self.mem_cur.connection
5278
+ self.mem_cur.close()
5279
+ db.close()
5280
+
5276
5281
  self.registry = {}
5277
5282
 
5278
5283
 
copyparty/util.py CHANGED
@@ -2622,12 +2622,29 @@ def build_netmap(csv , defer_mutex = False):
2622
2622
  if csv in ("any", "all", "no", ",", ""):
2623
2623
  return None
2624
2624
 
2625
- if csv in ("lan", "local", "private", "prvt"):
2626
- csv = "10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fd00::/8" # lan
2627
- csv += ", 169.254.0.0/16, fe80::/10" # link-local
2628
- csv += ", 127.0.0.0/8, ::1/128" # loopback
2629
-
2630
2625
  srcs = [x.strip() for x in csv.split(",") if x.strip()]
2626
+
2627
+ expanded_shorthands = False
2628
+ for shorthand in ("lan", "local", "private", "prvt"):
2629
+ if shorthand in srcs:
2630
+ if not expanded_shorthands:
2631
+ srcs += [
2632
+ # lan:
2633
+ "10.0.0.0/8",
2634
+ "172.16.0.0/12",
2635
+ "192.168.0.0/16",
2636
+ "fd00::/8",
2637
+ # link-local:
2638
+ "169.254.0.0/16",
2639
+ "fe80::/10",
2640
+ # loopback:
2641
+ "127.0.0.0/8",
2642
+ "::1/128",
2643
+ ]
2644
+ expanded_shorthands = True
2645
+
2646
+ srcs.remove(shorthand)
2647
+
2631
2648
  if not HAVE_IPV6:
2632
2649
  srcs = [x for x in srcs if ":" not in x]
2633
2650
 
copyparty/web/a/u2c.py CHANGED
@@ -1088,6 +1088,8 @@ class Ctl(object):
1088
1088
 
1089
1089
  spd = humansize(spd)
1090
1090
  self.eta = str(datetime.timedelta(seconds=int(eta)))
1091
+ if eta > 2591999:
1092
+ self.eta = self.eta.split(",")[0] # truncate HH:MM:SS
1091
1093
  sleft = humansize(self.nbytes - self.up_b)
1092
1094
  nleft = self.nfiles - self.up_f
1093
1095
  tail = "\033[K\033[u" if VT100 and not self.ar.ns else "\r"
Binary file
Binary file
@@ -132,16 +132,15 @@
132
132
 
133
133
  <script>
134
134
  var SR = {{ r|tojson }},
135
+ CGV1 = {{ cgv1 }},
135
136
  CGV = {{ cgv|tojson }},
136
137
  TS = "{{ ts }}",
137
138
  dtheme = "{{ dtheme }}",
138
139
  srvinf = "{{ srv_info }}",
139
- s_name = "{{ s_name }}",
140
140
  lang = "{{ lang }}",
141
141
  dfavico = "{{ favico }}",
142
- have_tags_idx = {{ have_tags_idx|tojson }},
142
+ have_tags_idx = {{ have_tags_idx }},
143
143
  sb_lg = "{{ sb_lg }}",
144
- txt_ext = "{{ txt_ext }}",
145
144
  logues = {{ logues|tojson if sb_lg else "[]" }},
146
145
  ls0 = {{ ls0|tojson }};
147
146
 
Binary file
Binary file
Binary file
copyparty/web/ui.css.gz CHANGED
Binary file
copyparty/web/up2k.js.gz CHANGED
Binary file
copyparty/web/util.js.gz CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.16.0
4
- Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
3
+ Version: 1.16.2
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
7
7
  Project-URL: Source Code, https://github.com/9001/copyparty
@@ -37,6 +37,10 @@ Requires-Python: >=3.3
37
37
  Description-Content-Type: text/markdown
38
38
  License-File: LICENSE
39
39
  Requires-Dist: Jinja2
40
+ Provides-Extra: thumbnails
41
+ Requires-Dist: Pillow; extra == "thumbnails"
42
+ Provides-Extra: thumbnails2
43
+ Requires-Dist: pyvips; extra == "thumbnails2"
40
44
  Provides-Extra: audiotags
41
45
  Requires-Dist: mutagen; extra == "audiotags"
42
46
  Provides-Extra: ftpd
@@ -44,14 +48,10 @@ Requires-Dist: pyftpdlib; extra == "ftpd"
44
48
  Provides-Extra: ftps
45
49
  Requires-Dist: pyftpdlib; extra == "ftps"
46
50
  Requires-Dist: pyopenssl; extra == "ftps"
47
- Provides-Extra: pwhash
48
- Requires-Dist: argon2-cffi; extra == "pwhash"
49
51
  Provides-Extra: tftpd
50
52
  Requires-Dist: partftpy>=0.4.0; extra == "tftpd"
51
- Provides-Extra: thumbnails
52
- Requires-Dist: Pillow; extra == "thumbnails"
53
- Provides-Extra: thumbnails2
54
- Requires-Dist: pyvips; extra == "thumbnails2"
53
+ Provides-Extra: pwhash
54
+ Requires-Dist: argon2-cffi; extra == "pwhash"
55
55
 
56
56
  <img src="https://github.com/9001/copyparty/raw/hovudstraum/docs/logo.svg" width="250" align="right"/>
57
57
 
@@ -1,25 +1,25 @@
1
1
  copyparty/__init__.py,sha256=iRCNvMPg6k9WG_O2uCtlkD4vWogH8EgP9elp9XwSIJs,2610
2
- copyparty/__main__.py,sha256=NpKXKPp6rAuWYw-fMWs-iS0dAjyOMl9WBtwBTYsH9zY,112286
3
- copyparty/__version__.py,sha256=snuFV6IoeKYLPgiZHLcMTRengBZI8NN2la43bff1e3E,252
4
- copyparty/authsrv.py,sha256=7ypOOehMN-NiC10y46lO-sDU8uGGnXrJz2rt9njKEZg,99237
2
+ copyparty/__main__.py,sha256=fbbMVr-sxhrn2fb9l44OnQ3XStmOoZJbq8FLrwZeel4,112528
3
+ copyparty/__version__.py,sha256=qkSYWTcO84wN8R56ATzvkttx7joci-cjVx1QjrUWw-8,252
4
+ copyparty/authsrv.py,sha256=QQGbliw2jOI86sNPUcx7rYeG39-LLSsfbJ1yWszFx5Y,102621
5
5
  copyparty/broker_mp.py,sha256=QdOXXvV2Xn6J0CysEqyY3GZbqxQMyWnTpnba-a5lMc0,4987
6
6
  copyparty/broker_mpw.py,sha256=PpSS4SK3pItlpfD8OwVr3QmJEPKlUgaf2nuMOozixgU,3347
7
7
  copyparty/broker_thr.py,sha256=fjoYtpSscUA7-nMl4r1n2R7UK3J9lrvLS3rUZ-iJzKQ,1721
8
8
  copyparty/broker_util.py,sha256=76mfnFOpX1gUUvtjm8UQI7jpTIaVINX10QonM-B7ggc,1680
9
9
  copyparty/cert.py,sha256=0ZAPeXeMR164vWn9GQU3JDKooYXEq_NOQkDeg543ivg,8009
10
- copyparty/cfg.py,sha256=4-Tk1Yb3eGcA8pO3jNRzd9HfCci6vRu3BNWarry0ia8,10263
10
+ copyparty/cfg.py,sha256=0v_ZK3NCfzqBVLW7cheJr53IwIOIbHpgd-uYAeseyUc,10280
11
11
  copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
12
12
  copyparty/fsutil.py,sha256=5CshJWO7CflfaRRNOb3JxghUH7W5rmS_HWNmKfx42MM,4538
13
13
  copyparty/ftpd.py,sha256=T97SFS7JFtvRLbJX8C4fJSYwe13vhN3-E6emtlVmqLA,17608
14
- copyparty/httpcli.py,sha256=tu5abG7JpDZYTDlPNv9p5SYGd0ZgAdoWf8HNYAr45V4,206103
14
+ copyparty/httpcli.py,sha256=s0W2R7l-ZWAJi2A6pQhtF7E7iNKXeVuyk--ybNJhPhE,204841
15
15
  copyparty/httpconn.py,sha256=mQSgljh0Q-jyWjF4tQLrHbRKRe9WKl19kGqsGMsJpWo,6880
16
- copyparty/httpsrv.py,sha256=WMQ-0sk6wk4Gbg7FB1ZYvnb74EsZQ5b7WJT0zAwZXjA,18226
16
+ copyparty/httpsrv.py,sha256=PXLZlT6iuJZYG9ajNsAaNgRK3UtS4CrOGFGXOpkRtOk,18235
17
17
  copyparty/ico.py,sha256=eWSxEae4wOCfheHl-m-wchYvFRAR_97kJDb4NGaB-Z8,3561
18
18
  copyparty/mdns.py,sha256=vC078llnL1v0pvL3mnwacuStFHPJUQuxo9Opj-IbHL4,18155
19
19
  copyparty/metrics.py,sha256=EOIiPOItEQmdK9YgNb75l0kCzanWb6RtJGwMI7ufifY,8966
20
- copyparty/mtag.py,sha256=8WGjEn0T0Ri9ww1yBpLUnFHZiTQMye1BMXL6SkK3MRo,18893
20
+ copyparty/mtag.py,sha256=o-rxu4LajWF4H3HFmfCbXnKfs0GCQh1FQ0XywuW6wOc,19934
21
21
  copyparty/multicast.py,sha256=Ha27l2oATEa-Qo2WOzkeRgjAm6G_YDCfbVJWR-ao2UE,12319
22
- copyparty/pwhash.py,sha256=AdLMLyIi2IDhGtbKIQOswKUxWvO7ARYYRF_ThsryOoc,4124
22
+ copyparty/pwhash.py,sha256=X87RWeay8IhzGVZLDKE5LctF9YVUcYxPAJ1BX6r_9CU,4248
23
23
  copyparty/smbd.py,sha256=Or7RF13cl1r3ncnpVh8BqyAGqH2Oa04O9iPZWCoB0Bo,14609
24
24
  copyparty/ssdp.py,sha256=R1Z61GZOxBMF2Sk4RTxKWMOemogmcjEWG-CvLihd45k,7023
25
25
  copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
@@ -30,13 +30,13 @@ copyparty/tcpsrv.py,sha256=VuW_aVDcyXIhIMZ8I-wpIouX8MI9TGp7KKSRohrMTtk,19897
30
30
  copyparty/tftpd.py,sha256=FRCALO3PigoBlwUrqxoKHM_xk7wT2O0GPG1TvNRtjOY,13606
31
31
  copyparty/th_cli.py,sha256=o6FMkerYvAXS455z3DUossVztu_nzFlYSQhs6qN6Jt8,4636
32
32
  copyparty/th_srv.py,sha256=LBcB4LpsF-H7L52Z0Dhn9LogRjJVPp1GKa8MeIMIBnw,29596
33
- copyparty/u2idx.py,sha256=HLO49L1zmpJtBcJiXgD12a6pAlQdnf2pFelHMA7habw,13462
34
- copyparty/up2k.py,sha256=m7sWNWmRR1-VoFzlXlAOYxwhOlbeOyFBO5a8Rcl6mnE,173608
35
- copyparty/util.py,sha256=jk4Z32KuIvqPQK8aveYhUfGZT9k0LR8viGGfcX4iab4,94422
33
+ copyparty/u2idx.py,sha256=_2nJlJb6a77Dt5KwK-TY5EnpIxWRVoiXTvk2sCGe6JI,13671
34
+ copyparty/up2k.py,sha256=LWq_VqZdrBDHNLX2pyK221hZfoQFDabWD5vOEBbP-xs,173731
35
+ copyparty/util.py,sha256=fUfkSBZwOjL4RbZ9UxP5Hi0TvRqy8GbL2oGEny_ikvw,94840
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
39
- copyparty/res/COPYING.txt,sha256=c1ZODkz9gwQsQ1nDHGHs0i4Nq0zBx_pRGITzPNtCYSY,10555
39
+ copyparty/res/COPYING.txt,sha256=rrIzm8MDinQXNkaBZ_ipr3mAQNzRgTff9tPJNdjaPtY,2193
40
40
  copyparty/res/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
41
41
  copyparty/res/insecure.pem,sha256=FEt7jgrn6ZHTlFopq_LFAN027YIoaHi0HQFBbzYnEwc,2876
42
42
  copyparty/stolen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -54,10 +54,10 @@ copyparty/stolen/ifaddr/__init__.py,sha256=vpREjAyPubr5s1NJi91icXV3q1o4DrKAvHABw
54
54
  copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUuTOrU,2626
55
55
  copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
56
56
  copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
57
- copyparty/web/baguettebox.js.gz,sha256=YIaxFDsubJfGIdzzxA-cL6GwJVmpWZyaPhW9hHcOIIw,7964
58
- copyparty/web/browser.css.gz,sha256=N5T5U-iWzls21E2SYkQvDUaaZf11gjj3KwUP0lm1mMA,11672
59
- copyparty/web/browser.html,sha256=ISpfvWEawufJCYZIqvuXiyUgiXgjmOTtScz4zrEaypI,4870
60
- copyparty/web/browser.js.gz,sha256=uGALYaMsyyXuCSKbvdMZpB-YrIvCIV3JWo611xRlHd8,88488
57
+ copyparty/web/baguettebox.js.gz,sha256=_amC3ipOrXKEFz8DsVP-JEl49VjMQYiKyF78eWfG-uk,7965
58
+ copyparty/web/browser.css.gz,sha256=1BN6qfX6Zai3osSbW0Y5WFcqD4D7wiWYOVEb8zXYu9w,11643
59
+ copyparty/web/browser.html,sha256=KCkZ_LwzQnj9xhXKYptAxp6W3nVGiDoSJ4ioZDo7rQ0,4827
60
+ copyparty/web/browser.js.gz,sha256=YNp0XMA-fvOiEBymBv3Iti33cdrp3hP9WMqj_wL7g_U,88603
61
61
  copyparty/web/browser2.html,sha256=NRUZ08GH-e2YcGXcoz0UjYg6JIVF42u4IMX4HHwWTmg,1587
62
62
  copyparty/web/cf.html,sha256=lJThtNFNAQT1ClCHHlivAkDGE0LutedwopXD62Z8Nys,589
63
63
  copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
@@ -73,19 +73,19 @@ copyparty/web/msg.css.gz,sha256=u90fXYAVrMD-jqwf5XFVC1ptSpSHZUe8Mez6PX101P8,300
73
73
  copyparty/web/msg.html,sha256=w9CM3hkLLGJX9fWEaG4gSbTOPe2GcPqW8BpSCDiFzOI,977
74
74
  copyparty/web/shares.css.gz,sha256=T2fSezuluDVIiNIERAuUREByhHFlIwwNyx7EBOAVVyQ,499
75
75
  copyparty/web/shares.html,sha256=ZNHtLBM-Y4BX2qa9AGTrZzZp_IP5PLM3QvFMYKolFfM,2494
76
- copyparty/web/shares.js.gz,sha256=_8_1MkmERDcrPeLFpNGzJA4vticRzNRehGKeDV24fNs,926
77
- copyparty/web/splash.css.gz,sha256=zgF2kvrp7z8LlhkaXNvFkP3RLlA4dHFZCkwQpG5RcYI,1081
76
+ copyparty/web/shares.js.gz,sha256=emeY2-wjkh8x1JgaW6ny5fcC7XpZzZzfE1f-sEyntQ4,940
77
+ copyparty/web/splash.css.gz,sha256=VxFqPvNdZtWb0u1C_GW2yYwrHq0lqPMitft9GYcv56k,1087
78
78
  copyparty/web/splash.html,sha256=wc8El8_5BR3EMuVik8WYAkkEQ4S6-VepR1B1F8qAYgI,6190
79
79
  copyparty/web/splash.js.gz,sha256=EEfsi9YGtPTYRB6MPX8Dfg4YyfqncI9ldJS7_MGVOhs,2710
80
80
  copyparty/web/svcs.html,sha256=P5YZimYLeQMT0uz6u3clQSNZRc5Zs0Ok-ffcbcGSYuc,11762
81
81
  copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
82
- copyparty/web/ui.css.gz,sha256=DCWgsJLb4exJ3_tUPHRcI0PuLLNlJJ1krF3WiSN9I7w,2785
83
- copyparty/web/up2k.js.gz,sha256=lGR1Xb0RkIZ1eHmncsSwWRuFc6FC2rZalvjo3oNTV1s,23291
84
- copyparty/web/util.js.gz,sha256=AMr49EVNOJiJjgSJyYyXKf_tHFLk3ODkCPQu26zbMZI,14815
82
+ copyparty/web/ui.css.gz,sha256=v8U-1tetZzuzTpITjq8NWj1gg3jEiYDIIE8aE0dx63k,2800
83
+ copyparty/web/up2k.js.gz,sha256=J8QY7CZH5Df3DN0ouDRDAM5derRgO_gRNzy5R5NilwM,23291
84
+ copyparty/web/util.js.gz,sha256=cciG6bEOr0bC4uQ0O5xTrcgjqolu6lKX-la81VfS_B8,14855
85
85
  copyparty/web/w.hash.js.gz,sha256=l3GpSJD6mcU-1CRWkIj7PybgbjlfSr8oeO3vortIrQk,1105
86
86
  copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
87
  copyparty/web/a/partyfuse.py,sha256=9p5Hpg_IBiSimv7j9kmPhCGpy-FLXSRUOYnLjJ5JifU,28049
88
- copyparty/web/a/u2c.py,sha256=4_YvRoWEAYrUVQHRts-1rPdWLBd6axfzG0fF5mc2Uj8,50196
88
+ copyparty/web/a/u2c.py,sha256=n5CxOhwZ2C_GhiDMhUcbwuc6v-f4tS2xfoAF-djjIQU,50297
89
89
  copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
90
90
  copyparty/web/dd/2.png,sha256=gJ14XFPzaw95L6z92fSq9eMPikSQyu-03P1lgiGe0_I,258
91
91
  copyparty/web/dd/3.png,sha256=4lho8Koz5tV7jJ4ODo6GMTScZfkqsT05yp48EDFIlyg,252
@@ -106,9 +106,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
106
106
  copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
107
107
  copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
108
108
  copyparty/web/deps/sha512.hw.js.gz,sha256=vqoXeracj-99Z5MfY3jK2N4WiSzYQdfjy0RnUlQDhSU,8110
109
- copyparty-1.16.0.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
110
- copyparty-1.16.0.dist-info/METADATA,sha256=tLqMYoMnPCLqhLEvCe8twQHQoRnXfIGwu8neJ1MucdQ,140282
111
- copyparty-1.16.0.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
112
- copyparty-1.16.0.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
113
- copyparty-1.16.0.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
114
- copyparty-1.16.0.dist-info/RECORD,,
109
+ copyparty-1.16.2.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
110
+ copyparty-1.16.2.dist-info/METADATA,sha256=55fGnCZfk0w7XNKhojXjou_rx5RSGFnOLkF-nUeqp_8,140284
111
+ copyparty-1.16.2.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
112
+ copyparty-1.16.2.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
113
+ copyparty-1.16.2.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
114
+ copyparty-1.16.2.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (75.3.0)
2
+ Generator: setuptools (75.6.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5