copyparty 1.14.4__py3-none-any.whl → 1.15.1__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/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.23"
5
- S_BUILD_DT = "2024-08-22"
4
+ S_VERSION = "1.24"
5
+ S_BUILD_DT = "2024-09-05"
6
6
 
7
7
  """
8
8
  u2c.py: upload to copyparty
@@ -41,19 +41,25 @@ except:
41
41
 
42
42
  try:
43
43
  import requests
44
+
45
+ req_ses = requests.Session()
44
46
  except ImportError as ex:
45
- if EXE:
47
+ if "-" in sys.argv or "-h" in sys.argv:
48
+ m = ""
49
+ elif EXE:
46
50
  raise
47
51
  elif sys.version_info > (2, 7):
48
- m = "\nERROR: need 'requests'; please run this command:\n {0} -m pip install --user requests\n"
52
+ m = "\nERROR: need 'requests'{0}; please run this command:\n {1} -m pip install --user requests\n"
49
53
  else:
50
54
  m = "requests/2.18.4 urllib3/1.23 chardet/3.0.4 certifi/2020.4.5.1 idna/2.7"
51
55
  m = [" https://pypi.org/project/" + x + "/#files" for x in m.split()]
52
- m = "\n ERROR: need these:\n" + "\n".join(m) + "\n"
56
+ m = "\n ERROR: need these{0}:\n" + "\n".join(m) + "\n"
53
57
  m += "\n for f in *.whl; do unzip $f; done; rm -r *.dist-info\n"
54
58
 
55
- print(m.format(sys.executable), "\nspecifically,", ex)
56
- sys.exit(1)
59
+ if m:
60
+ t = " when not running with '-h' or url '-'"
61
+ print(m.format(t, sys.executable), "\nspecifically,", ex)
62
+ sys.exit(1)
57
63
 
58
64
 
59
65
  # from copyparty/__init__.py
@@ -76,7 +82,22 @@ else:
76
82
  VT100 = platform.system() != "Windows"
77
83
 
78
84
 
79
- req_ses = requests.Session()
85
+ try:
86
+ UTC = datetime.timezone.utc
87
+ except:
88
+ TD_ZERO = datetime.timedelta(0)
89
+
90
+ class _UTC(datetime.tzinfo):
91
+ def utcoffset(self, dt):
92
+ return TD_ZERO
93
+
94
+ def tzname(self, dt):
95
+ return "UTC"
96
+
97
+ def dst(self, dt):
98
+ return TD_ZERO
99
+
100
+ UTC = _UTC()
80
101
 
81
102
 
82
103
  class Daemon(threading.Thread):
@@ -271,6 +292,12 @@ class MTHash(object):
271
292
  _print = print
272
293
 
273
294
 
295
+ def safe_print(*a, **ka):
296
+ ka["end"] = ""
297
+ zs = " ".join([unicode(x) for x in a])
298
+ _print(zs + "\n", **ka)
299
+
300
+
274
301
  def eprint(*a, **ka):
275
302
  ka["file"] = sys.stderr
276
303
  ka["end"] = ""
@@ -284,18 +311,17 @@ def eprint(*a, **ka):
284
311
 
285
312
  def flushing_print(*a, **ka):
286
313
  try:
287
- _print(*a, **ka)
314
+ safe_print(*a, **ka)
288
315
  except:
289
316
  v = " ".join(str(x) for x in a)
290
317
  v = v.encode("ascii", "replace").decode("ascii")
291
- _print(v, **ka)
318
+ safe_print(v, **ka)
292
319
 
293
320
  if "flush" not in ka:
294
321
  sys.stdout.flush()
295
322
 
296
323
 
297
- if not VT100:
298
- print = flushing_print
324
+ print = safe_print if VT100 else flushing_print
299
325
 
300
326
 
301
327
  def termsize():
@@ -770,8 +796,6 @@ class Ctl(object):
770
796
  self.up_c = 0
771
797
  self.up_b = 0
772
798
  self.up_br = 0
773
- self.hasher_busy = 1
774
- self.handshaker_busy = 0
775
799
  self.uploader_busy = 0
776
800
  self.serialized = False
777
801
 
@@ -781,6 +805,9 @@ class Ctl(object):
781
805
  self.eta = "99:99:99"
782
806
 
783
807
  self.mutex = threading.Lock()
808
+ self.exit_cond = threading.Condition()
809
+ self.uploader_alive = ar.j
810
+ self.handshaker_alive = ar.j
784
811
  self.q_handshake = Queue() # type: Queue[File]
785
812
  self.q_upload = Queue() # type: Queue[FileSlice]
786
813
 
@@ -851,27 +878,21 @@ class Ctl(object):
851
878
  Daemon(self.handshaker)
852
879
  Daemon(self.uploader)
853
880
 
854
- idles = 0
855
- while idles < 3:
856
- time.sleep(0.07)
881
+ while True:
882
+ with self.exit_cond:
883
+ self.exit_cond.wait(0.07)
857
884
  with self.mutex:
858
- if (
859
- self.q_handshake.empty()
860
- and self.q_upload.empty()
861
- and not self.hasher_busy
862
- and not self.handshaker_busy
863
- and not self.uploader_busy
864
- ):
865
- idles += 1
866
- else:
867
- idles = 0
885
+ if not self.handshaker_alive and not self.uploader_alive:
886
+ break
887
+ st_hash = self.st_hash[:]
888
+ st_up = self.st_up[:]
868
889
 
869
890
  if VT100 and not self.ar.ns:
870
891
  maxlen = ss.w - len(str(self.nfiles)) - 14
871
892
  txt = "\033[s\033[{0}H".format(ss.g)
872
893
  for y, k, st, f in [
873
- [0, "hash", self.st_hash, self.hash_f],
874
- [1, "send", self.st_up, self.up_f],
894
+ [0, "hash", st_hash, self.hash_f],
895
+ [1, "send", st_up, self.up_f],
875
896
  ]:
876
897
  txt += "\033[{0}H{1}:".format(ss.g + y, k)
877
898
  file, arg = st
@@ -1027,11 +1048,42 @@ class Ctl(object):
1027
1048
  self.hash_f += 1
1028
1049
  self.hash_c += len(file.cids)
1029
1050
  self.hash_b += file.size
1051
+ if self.ar.wlist:
1052
+ self.up_f = self.hash_f
1053
+ self.up_c = self.hash_c
1054
+ self.up_b = self.hash_b
1055
+
1056
+ if self.ar.wlist:
1057
+ zsl = [self.ar.wsalt, str(file.size)] + [x[0] for x in file.kchunks]
1058
+ zb = hashlib.sha512("\n".join(zsl).encode("utf-8")).digest()[:33]
1059
+ wark = base64.urlsafe_b64encode(zb).decode("utf-8")
1060
+ vp = file.rel.decode("utf-8")
1061
+ if self.ar.jw:
1062
+ print("%s %s" % (wark, vp))
1063
+ else:
1064
+ zd = datetime.datetime.fromtimestamp(file.lmod, UTC)
1065
+ dt = "%04d-%02d-%02d %02d:%02d:%02d" % (
1066
+ zd.year,
1067
+ zd.month,
1068
+ zd.day,
1069
+ zd.hour,
1070
+ zd.minute,
1071
+ zd.second,
1072
+ )
1073
+ print("%s %12d %s %s" % (dt, file.size, wark, vp))
1074
+ continue
1030
1075
 
1031
1076
  self.q_handshake.put(file)
1032
1077
 
1033
- self.hasher_busy = 0
1034
1078
  self.st_hash = [None, "(finished)"]
1079
+ self._check_if_done()
1080
+
1081
+ def _check_if_done(self):
1082
+ with self.mutex:
1083
+ if self.nfiles - self.up_f:
1084
+ return
1085
+ for _ in range(self.ar.j):
1086
+ self.q_handshake.put(None)
1035
1087
 
1036
1088
  def handshaker(self):
1037
1089
  search = self.ar.s
@@ -1039,8 +1091,10 @@ class Ctl(object):
1039
1091
  while True:
1040
1092
  file = self.q_handshake.get()
1041
1093
  if not file:
1094
+ with self.mutex:
1095
+ self.handshaker_alive -= 1
1042
1096
  self.q_upload.put(None)
1043
- break
1097
+ return
1044
1098
 
1045
1099
  upath = file.abs.decode("utf-8", "replace")
1046
1100
  if not VT100:
@@ -1052,9 +1106,6 @@ class Ctl(object):
1052
1106
  self.errs += 1
1053
1107
  continue
1054
1108
 
1055
- with self.mutex:
1056
- self.handshaker_busy += 1
1057
-
1058
1109
  while time.time() < file.cd:
1059
1110
  time.sleep(0.1)
1060
1111
 
@@ -1062,17 +1113,17 @@ class Ctl(object):
1062
1113
  if search:
1063
1114
  if hs:
1064
1115
  for hit in hs:
1065
- t = "found: {0}\n {1}{2}\n"
1066
- print(t.format(upath, burl, hit["rp"]), end="")
1116
+ t = "found: {0}\n {1}{2}"
1117
+ print(t.format(upath, burl, hit["rp"]))
1067
1118
  else:
1068
- print("NOT found: {0}\n".format(upath), end="")
1119
+ print("NOT found: {0}".format(upath))
1069
1120
 
1070
1121
  with self.mutex:
1071
1122
  self.up_f += 1
1072
1123
  self.up_c += len(file.cids)
1073
1124
  self.up_b += file.size
1074
- self.handshaker_busy -= 1
1075
1125
 
1126
+ self._check_if_done()
1076
1127
  continue
1077
1128
 
1078
1129
  if file.recheck:
@@ -1104,7 +1155,6 @@ class Ctl(object):
1104
1155
  file.up_b -= sz
1105
1156
 
1106
1157
  file.ucids = hs
1107
- self.handshaker_busy -= 1
1108
1158
 
1109
1159
  if not hs:
1110
1160
  self.at_hash += file.t_hash
@@ -1130,6 +1180,9 @@ class Ctl(object):
1130
1180
  kw = "uploaded" if file.up_b else " found"
1131
1181
  print("{0} {1}".format(kw, upath))
1132
1182
 
1183
+ self._check_if_done()
1184
+ continue
1185
+
1133
1186
  chunksz = up2k_chunksize(file.size)
1134
1187
  njoin = (self.ar.sz * 1024 * 1024) // chunksz
1135
1188
  cs = hs[:]
@@ -1149,8 +1202,16 @@ class Ctl(object):
1149
1202
  while True:
1150
1203
  fsl = self.q_upload.get()
1151
1204
  if not fsl:
1152
- self.st_up = [None, "(finished)"]
1153
- break
1205
+ done = False
1206
+ with self.mutex:
1207
+ self.uploader_alive -= 1
1208
+ if not self.uploader_alive:
1209
+ done = not self.handshaker_alive
1210
+ self.st_up = [None, "(finished)"]
1211
+ if done:
1212
+ with self.exit_cond:
1213
+ self.exit_cond.notify_all()
1214
+ return
1154
1215
 
1155
1216
  file = fsl.file
1156
1217
  cids = fsl.cids
@@ -1252,6 +1313,10 @@ source file/folder selection uses rsync syntax, meaning that:
1252
1313
  ap.add_argument("--dr", action="store_true", help="delete remote files which don't exist locally (implies --ow)")
1253
1314
  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")
1254
1315
 
1316
+ ap = app.add_argument_group("file-ID calculator; enable with url '-' to list warks (file identifiers) instead of upload/search")
1317
+ ap.add_argument("--wsalt", type=unicode, metavar="S", default="hunter2", help="salt to use when creating warks; must match server config")
1318
+ ap.add_argument("--jw", action="store_true", help="just identifier+filepath, not mtime/size too")
1319
+
1255
1320
  ap = app.add_argument_group("performance tweaks")
1256
1321
  ap.add_argument("-j", type=int, metavar="CONNS", default=2, help="parallel connections")
1257
1322
  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")
@@ -1285,7 +1350,9 @@ source file/folder selection uses rsync syntax, meaning that:
1285
1350
 
1286
1351
  ar.x = "|".join(ar.x or [])
1287
1352
 
1288
- for k in "dl dr drd".split():
1353
+ setattr(ar, "wlist", ar.url == "-")
1354
+
1355
+ for k in "dl dr drd wlist".split():
1289
1356
  errs = []
1290
1357
  if ar.safe and getattr(ar, k):
1291
1358
  errs.append(k)
Binary file
Binary file
copyparty/web/up2k.js.gz CHANGED
Binary file
copyparty/web/util.js.gz CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.14.4
3
+ Version: 1.15.1
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
@@ -119,7 +119,8 @@ turn almost any device into a file server with resumable uploads/downloads using
119
119
  * [smb server](#smb-server) - unsafe, slow, not recommended for wan
120
120
  * [browser ux](#browser-ux) - tweaking the ui
121
121
  * [opengraph](#opengraph) - discord and social-media embeds
122
- * [file indexing](#file-indexing) - enables dedup and music search ++
122
+ * [file deduplication](#file-deduplication) - enable symlink-based upload deduplication
123
+ * [file indexing](#file-indexing) - enable music search, upload-undo, and better dedup
123
124
  * [exclude-patterns](#exclude-patterns) - to save some time
124
125
  * [filesystem guards](#filesystem-guards) - avoid traversing into other filesystems
125
126
  * [periodic rescan](#periodic-rescan) - filesystem monitoring
@@ -1209,9 +1210,41 @@ NOTE: because discord (and maybe others) strip query args such as `?raw` in open
1209
1210
  if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object)
1210
1211
 
1211
1212
 
1213
+ ## file deduplication
1214
+
1215
+ enable symlink-based upload deduplication globally with `--dedup` or per-volume with volflag `dedup`
1216
+
1217
+ when someone tries to upload a file that already exists on the server, the upload will be politely declined and a symlink is created instead, pointing to the nearest copy on disk, thus reducinc disk space usage
1218
+
1219
+ **warning:** when enabling dedup, you should also:
1220
+ * enable indexing with `-e2dsa` or volflag `e2dsa` (see [file indexing](#file-indexing) section below); strongly recommended
1221
+ * ...and/or `--hardlink-only` to use hardlink-based deduplication instead of symlinks; see explanation below
1222
+
1223
+ it will not be safe to rename/delete files if you only enable dedup and none of the above; if you enable indexing then it is not *necessary* to also do hardlinks (but you may still want to)
1224
+
1225
+ by default, deduplication is done based on symlinks (symbolic links); these are tiny files which are pointers to the nearest full copy of the file
1226
+
1227
+ you can choose to use hardlinks instead of softlinks, globally with `--hardlink-only` or volflag `hardlinkonly`;
1228
+
1229
+ advantages of using hardlinks:
1230
+ * hardlinks are more compatible with other software; they behave entirely like regular files
1231
+ * you can safely move and rename files using other file managers
1232
+ * symlinks need to be managed by copyparty to ensure the destinations remain correct
1233
+
1234
+ advantages of using symlinks (default):
1235
+ * each symlink can have its own last-modified timestamp, but a single timestamp is shared by all hardlinks
1236
+ * symlinks make it more obvious to other software that the file is not a regular file, so this can be less dangerous
1237
+ * hardlinks look like regular files, so other software may assume they are safe to edit without affecting the other copies
1238
+
1239
+ **warning:** if you edit the contents of a deduplicated file, then you will also edit all other copies of that file! This is especially surprising with hardlinks, because they look like regular files, but that same file exists in multiple locations
1240
+
1241
+ global-option `--xlink` / volflag `xlink` additionally enables deduplication across volumes, but this is probably buggy and not recommended
1242
+
1243
+
1244
+
1212
1245
  ## file indexing
1213
1246
 
1214
- enables dedup and music search ++
1247
+ enable music search, upload-undo, and better dedup
1215
1248
 
1216
1249
  file indexing relies on two database tables, the up2k filetree (`-e2d`) and the metadata tags (`-e2t`), stored in `.hist/up2k.db`. Configuration can be done through arguments, volflags, or a mix of both.
1217
1250
 
@@ -1225,7 +1258,6 @@ through arguments:
1225
1258
  * `-e2v` verfies file integrity at startup, comparing hashes from the db
1226
1259
  * `-e2vu` patches the database with the new hashes from the filesystem
1227
1260
  * `-e2vp` panics and kills copyparty instead
1228
- * `--xlink` enables deduplication across volumes
1229
1261
 
1230
1262
  the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`, `d2ts`, `d2v` for disabling:
1231
1263
  * `-v ~/music::r:c,e2ds,e2tsr` does a full reindex of everything on startup
@@ -1238,7 +1270,6 @@ note:
1238
1270
  * upload-times can be displayed in the file listing by enabling the `.up_at` metadata key, either globally with `-e2d -mte +.up_at` or per-volume with volflags `e2d,mte=+.up_at` (will have a ~17% performance impact on directory listings)
1239
1271
  * `e2tsr` is probably always overkill, since `e2ds`/`e2dsa` would pick up any file modifications and `e2ts` would then reindex those, unless there is a new copyparty version with new parsers and the release note says otherwise
1240
1272
  * the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
1241
- * deduplication is possible on windows if you run copyparty as administrator (not saying you should!)
1242
1273
 
1243
1274
  ### exclude-patterns
1244
1275
 
@@ -1978,6 +2009,8 @@ below are some tweaks roughly ordered by usefulness:
1978
2009
  * `-q` disables logging and can help a bunch, even when combined with `-lo` to redirect logs to file
1979
2010
  * `--hist` pointing to a fast location (ssd) will make directory listings and searches faster when `-e2d` or `-e2t` is set
1980
2011
  * and also makes thumbnails load faster, regardless of e2d/e2t
2012
+ * `--dedup` enables deduplication and thus avoids writing to the HDD if someone uploads a dupe
2013
+ * `--safe-dedup 1` makes deduplication much faster during upload by skipping verification of file contents; safe if there is no other software editing/moving the files in the volumes
1981
2014
  * `--no-hash .` when indexing a network-disk if you don't care about the actual filehashes and only want the names/tags searchable
1982
2015
  * if your volumes are on a network-disk such as NFS / SMB / s3, specifying larger values for `--iobuf` and/or `--s-rd-sz` and/or `--s-wr-sz` may help; try setting all of them to `524288` or `1048576` or `4194304`
1983
2016
  * `--no-htp --hash-mt=0 --mtag-mt=1 --th-mt=1` minimizes the number of threads; can help in some eccentric environments (like the vscode debugger)
@@ -2032,7 +2065,7 @@ safety profiles:
2032
2065
  * `--hardlink` creates hardlinks instead of symlinks when deduplicating uploads, which is less maintenance
2033
2066
  * however note if you edit one file it will also affect the other copies
2034
2067
  * `--vague-403` returns a "404 not found" instead of "401 unauthorized" which is a common enterprise meme
2035
- * `--nih` removes the server hostname from directory listings
2068
+ * `-nih` removes the server hostname from directory listings
2036
2069
 
2037
2070
  * option `-sss` is a shortcut for the above plus:
2038
2071
  * `--no-dav` disables webdav support
@@ -1,17 +1,17 @@
1
1
  copyparty/__init__.py,sha256=fUINM1abqDGzCCH_JcXdOnLdKOV-SrTI2Xo2QgQW2P4,1703
2
- copyparty/__main__.py,sha256=0fQcGqHkcYXRqtkh9as-xyBfV_5R6z2fQf41WFtjRe8,108093
3
- copyparty/__version__.py,sha256=nvd8B5TJuiwdP2pBNNqiQlQQi41vsmExvBjCabqN22Q,257
4
- copyparty/authsrv.py,sha256=jWXTjZLT8cGymfa9wBwGJqyBIi80aXcvzAMgI74G8iA,95750
5
- copyparty/broker_mp.py,sha256=YFe1S6Zziht8Qc__dCLj_ff8z0DDny9lqk_Mi5ajsJk,3868
6
- copyparty/broker_mpw.py,sha256=4ZI7bJYOwUibeAJVv9_FPGNmHrr9eOtkj_Kz0JEppTU,3197
7
- copyparty/broker_thr.py,sha256=eKr--HJGig5zqvNGwH9UoBG9Nvi9mT2axrRmJwknd0s,1759
2
+ copyparty/__main__.py,sha256=M8o_4CGNuteh7j_3iiFN_FTu0IIHKrjRScZOBFKqXis,109083
3
+ copyparty/__version__.py,sha256=BCJou8sLX4iTHVA4RubRxWxlC8xKh9t-i3XAUnB-aq8,256
4
+ copyparty/authsrv.py,sha256=pX-Dax35ClxftNnN50UslvZZbPTFI73v-EFLGSqtAA4,98516
5
+ copyparty/broker_mp.py,sha256=krsUWduBULlZ1LnroHhWLGnUBWYtWc_kohZXgHsE458,4004
6
+ copyparty/broker_mpw.py,sha256=9kb_3BYUduwtmluuqdm0OhY6T4DwpUSX2xW7jo6veQ8,3326
7
+ copyparty/broker_thr.py,sha256=BErWJkpd1bnRCcUHowAPNHCfo3CSqVmD-5yVRKjIIhU,1800
8
8
  copyparty/broker_util.py,sha256=w0E-GhoOgq8ow7mEWi3GOyqraux6VG9yk1tif1yo0jc,1474
9
9
  copyparty/cert.py,sha256=kRFkMwBUCV_Vo7BYweD-yJ7Hpp5BCpaXneyBWxlu1PM,7759
10
- copyparty/cfg.py,sha256=i8-bjWgbguQooxiA172RcptqR_SEOwDHJ4cqldrZ8oQ,9792
10
+ copyparty/cfg.py,sha256=6cj2xJnBa9vRubM5U_mkA87zG2Ug11vnyk2hYz0XfxI,9965
11
11
  copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
12
12
  copyparty/fsutil.py,sha256=hnEHgySI43-XJJKbI8n6t1A6oVHzR_nYdsBcAwtreBk,4610
13
13
  copyparty/ftpd.py,sha256=1vD-KTy07xfEEEk1dx37pUYModpNO2gIhVXvFUr205M,17497
14
- copyparty/httpcli.py,sha256=QTOrZOuVh__C_r5REpTiUeGEhrRAke2ejEOOi4zyfbo,182619
14
+ copyparty/httpcli.py,sha256=T-bISKn73-zt-q3C4dbRDgfB1tspze7dhM3gUY0ztX0,183570
15
15
  copyparty/httpconn.py,sha256=mwIDup85cBowIfJOse8rla5bqTz7nf-ChgfR-5-V0JM,6938
16
16
  copyparty/httpsrv.py,sha256=8_1Ivg3eco7HJDjqL_rUB58IOUaUnoXGhO62bOMXLBk,17242
17
17
  copyparty/ico.py,sha256=eWSxEae4wOCfheHl-m-wchYvFRAR_97kJDb4NGaB-Z8,3561
@@ -24,15 +24,15 @@ copyparty/smbd.py,sha256=8zkC9BjVtGiKXMLajbdakxoKeFzACdM75SW0_SvqXJA,14490
24
24
  copyparty/ssdp.py,sha256=8iyF5sqIjATJLWcAtnJa8eadHosOn0CP4ywltzJ7bVY,7023
25
25
  copyparty/star.py,sha256=tV5BbX6AiQ7N4UU8DYtSTckNYeoeey4DBqq4LjfymbY,3818
26
26
  copyparty/sutil.py,sha256=JTMrQwcWH85hXB_cKG206eDZ967WZDGaP00AWvl_gB0,3214
27
- copyparty/svchub.py,sha256=v0f8KU65dj2MXOjrd-7kckgiFZSu8kpnTUMyLfn9NIM,38429
27
+ copyparty/svchub.py,sha256=mhELkl2XCvaTrxLcXbfGSPbRtXA1wE66ap73wEWcvFI,40087
28
28
  copyparty/szip.py,sha256=tor4yjdHhEL4Ox-Xg7-cuUFrMO0IwQD29aRX5Cp8MYs,8605
29
29
  copyparty/tcpsrv.py,sha256=jM_Za64O8LEMfMrU4irJluIJZrU494e2b759r_KhaUQ,19881
30
30
  copyparty/tftpd.py,sha256=jZbf2JpeJmkuQWJErmAPG-dKhtYNvIUHbkAgodSXw9Y,13582
31
31
  copyparty/th_cli.py,sha256=o6FMkerYvAXS455z3DUossVztu_nzFlYSQhs6qN6Jt8,4636
32
32
  copyparty/th_srv.py,sha256=27IftjIXUQzRRiUytt-CgXkybEoP3HHHoXaDAvxEmLo,29217
33
33
  copyparty/u2idx.py,sha256=t4mzjj2GDrkjIHt0RM68y1EgT5qOBoz6mkYgjMbqA38,13526
34
- copyparty/up2k.py,sha256=K2FIxvL4RQ9Er8pH7gQnIU-OHdOJJ5P60oW-SX-silQ,155373
35
- copyparty/util.py,sha256=aWKONxHJh73PCvq9aKKJW9LcU3EqiZynpQ-b1MvK_50,88604
34
+ copyparty/up2k.py,sha256=USxHI5IN-9DQp_P7Yl4683yxlvaWTslZT90h6sfqpuk,159853
35
+ copyparty/util.py,sha256=qkwrCRqDI7iCiO3X2RQ1LdGVblnkIQe1YTuJPlF27u4,88666
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
@@ -55,9 +55,9 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
55
55
  copyparty/stolen/ifaddr/_shared.py,sha256=uNC4SdEIgdSLKvuUzsf1aM-H1Xrc_9mpLoOT43YukGs,6206
56
56
  copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
57
57
  copyparty/web/baguettebox.js.gz,sha256=4dS8-r4si84ca71l98672ahnRI86Aq95MU-bc5knykk,7962
58
- copyparty/web/browser.css.gz,sha256=PoW_IIwFigZaMo3atpPU0o05Jj5Flbsm1bhW_KfcX-U,11491
58
+ copyparty/web/browser.css.gz,sha256=TM9gYp-MFSjj_2kV-mKrLFit0Ayz2e7AxI4L0LJmrBE,11608
59
59
  copyparty/web/browser.html,sha256=vvfWiu_aOFRar8u5lridMRKQSPF4R0YkA41zrsh82Qs,4878
60
- copyparty/web/browser.js.gz,sha256=vbgNK0skbOyQHqUeYbLxi0qkdAXzWBTGxhgFaKBhxx8,80863
60
+ copyparty/web/browser.js.gz,sha256=EZhEAuKeZH9qO1gfRzyARG-PFmP7rFtQfHRr0ZnUEYs,84762
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
@@ -80,12 +80,12 @@ copyparty/web/splash.js.gz,sha256=pxEHaRDpxTnW6WdRWpKlRux8jtI7B5RImRjUVs9gdQQ,25
80
80
  copyparty/web/svcs.html,sha256=v0C3cOFWXYlvp3GEifz1Qj0W3MD8JANT3WTON05GZ9o,11797
81
81
  copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
82
82
  copyparty/web/ui.css.gz,sha256=ae1JosPYS8d2F9e_b95bTwa7qYwk8Ur_UhoVpRYEp0Y,2658
83
- copyparty/web/up2k.js.gz,sha256=M9n-VLZP7olT-kL5FfT_X_FW1FrQV-bB3_xPhhFic3U,22943
84
- copyparty/web/util.js.gz,sha256=dPuhXEBJ_T-d2tYUUufGTUul4FYIbuh6GQmtK7iBkEo,14682
83
+ copyparty/web/up2k.js.gz,sha256=t6mUaIYN8lrEJoWO_-2MZ9nIuEplimQgCqdWSsHnuGA,22811
84
+ copyparty/web/util.js.gz,sha256=1umlPsqbe_uuM_xX1QwIp9KC8KQAOFUh3aq6HxozIms,14682
85
85
  copyparty/web/w.hash.js.gz,sha256=7wP9EZQNXQxwZnCCFUVsi_-6TM9PLZJeZ9krutXRRj8,1060
86
86
  copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
87
  copyparty/web/a/partyfuse.py,sha256=MuRkaSuYsdfWfBFMOkbPwDXqSvNTw3sd7QhhlKCDZ8I,32311
88
- copyparty/web/a/u2c.py,sha256=WG9njRxY9g9xjO93-fas9Wo-AM8vtrWrUTwpJ5Afmvk,42482
88
+ copyparty/web/a/u2c.py,sha256=jeSwm0sD-uxXQbKX9srI36-RJQHL3t6EEupD-lv5xdo,44960
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
@@ -105,9 +105,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
105
105
  copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
106
106
  copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
107
107
  copyparty/web/deps/sha512.hw.js.gz,sha256=vqoXeracj-99Z5MfY3jK2N4WiSzYQdfjy0RnUlQDhSU,8110
108
- copyparty-1.14.4.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
109
- copyparty-1.14.4.dist-info/METADATA,sha256=9NRNTHBaC3QV4ruHXtp6kuOcakkBtme8iY17_lRmaPI,131776
110
- copyparty-1.14.4.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
111
- copyparty-1.14.4.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
112
- copyparty-1.14.4.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
113
- copyparty-1.14.4.dist-info/RECORD,,
108
+ copyparty-1.15.1.dist-info/LICENSE,sha256=gOr4h33pCsBEg9uIy9AYmb7qlocL4V9t2uPJS5wllr0,1072
109
+ copyparty-1.15.1.dist-info/METADATA,sha256=sfkSpMV_LX0ITSPAYWbMeaYs8Zz1LC0ZSuv5GSpTjLw,134165
110
+ copyparty-1.15.1.dist-info/WHEEL,sha256=cVxcB9AmuTcXqmwrtPhNK88dr7IR_b6qagTj0UvIEbY,91
111
+ copyparty-1.15.1.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
112
+ copyparty-1.15.1.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
113
+ copyparty-1.15.1.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (74.0.0)
2
+ Generator: setuptools (74.1.2)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5