copyparty 1.10.1__tar.gz → 1.10.2__tar.gz

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.
Files changed (114) hide show
  1. {copyparty-1.10.1 → copyparty-1.10.2}/PKG-INFO +1 -1
  2. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/__version__.py +2 -2
  3. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/ftpd.py +3 -0
  4. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/httpcli.py +20 -7
  5. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/ico.py +3 -4
  6. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/tftpd.py +50 -12
  7. copyparty-1.10.2/copyparty/web/browser.css.gz +0 -0
  8. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/browser.html +1 -0
  9. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/browser.js.gz +0 -0
  10. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/browser2.html +1 -0
  11. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/cf.html +1 -0
  12. copyparty-1.10.2/copyparty/web/deps/marked.js.gz +0 -0
  13. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/md.html +1 -0
  14. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/mde.html +1 -0
  15. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/msg.html +2 -1
  16. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/splash.html +1 -0
  17. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/svcs.html +1 -0
  18. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty.egg-info/PKG-INFO +1 -1
  19. copyparty-1.10.1/copyparty/web/browser.css.gz +0 -0
  20. copyparty-1.10.1/copyparty/web/deps/marked.js.gz +0 -0
  21. {copyparty-1.10.1 → copyparty-1.10.2}/LICENSE +0 -0
  22. {copyparty-1.10.1 → copyparty-1.10.2}/README.md +0 -0
  23. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/__init__.py +0 -0
  24. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/__main__.py +0 -0
  25. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/authsrv.py +0 -0
  26. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/bos/__init__.py +0 -0
  27. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/bos/bos.py +0 -0
  28. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/bos/path.py +0 -0
  29. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/broker_mp.py +0 -0
  30. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/broker_mpw.py +0 -0
  31. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/broker_thr.py +0 -0
  32. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/broker_util.py +0 -0
  33. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/cert.py +0 -0
  34. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/cfg.py +0 -0
  35. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/dxml.py +0 -0
  36. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/fsutil.py +0 -0
  37. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/httpconn.py +0 -0
  38. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/httpsrv.py +0 -0
  39. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/mdns.py +0 -0
  40. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/metrics.py +0 -0
  41. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/mtag.py +0 -0
  42. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/multicast.py +0 -0
  43. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/pwhash.py +0 -0
  44. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/res/COPYING.txt +0 -0
  45. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/res/__init__.py +0 -0
  46. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/res/insecure.pem +0 -0
  47. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/smbd.py +0 -0
  48. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/ssdp.py +0 -0
  49. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/star.py +0 -0
  50. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/__init__.py +0 -0
  51. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/__init__.py +0 -0
  52. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/bimap.py +0 -0
  53. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/bit.py +0 -0
  54. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/buffer.py +0 -0
  55. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/dns.py +0 -0
  56. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/label.py +0 -0
  57. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/lex.py +0 -0
  58. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/dnslib/ranges.py +0 -0
  59. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/ifaddr/__init__.py +0 -0
  60. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/ifaddr/_posix.py +0 -0
  61. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/ifaddr/_shared.py +0 -0
  62. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/ifaddr/_win32.py +0 -0
  63. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/qrcodegen.py +0 -0
  64. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/stolen/surrogateescape.py +0 -0
  65. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/sutil.py +0 -0
  66. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/svchub.py +0 -0
  67. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/szip.py +0 -0
  68. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/tcpsrv.py +0 -0
  69. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/th_cli.py +0 -0
  70. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/th_srv.py +0 -0
  71. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/u2idx.py +0 -0
  72. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/up2k.py +0 -0
  73. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/util.py +0 -0
  74. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/a/__init__.py +0 -0
  75. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/a/partyfuse.py +0 -0
  76. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/a/u2c.py +0 -0
  77. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/a/webdav-cfg.bat +0 -0
  78. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/baguettebox.js.gz +0 -0
  79. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/dbg-audio.js.gz +0 -0
  80. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/dd/2.png +0 -0
  81. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/dd/3.png +0 -0
  82. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/dd/4.png +0 -0
  83. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/dd/5.png +0 -0
  84. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/dd/__init__.py +0 -0
  85. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/__init__.py +0 -0
  86. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/mini-fa.css.gz +0 -0
  87. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/mini-fa.woff +0 -0
  88. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/prism.css.gz +0 -0
  89. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/prism.js.gz +0 -0
  90. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/prismd.css.gz +0 -0
  91. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/scp.woff2 +0 -0
  92. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/sha512.ac.js.gz +0 -0
  93. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/deps/sha512.hw.js.gz +0 -0
  94. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/md.css.gz +0 -0
  95. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/md.js.gz +0 -0
  96. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/md2.css.gz +0 -0
  97. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/md2.js.gz +0 -0
  98. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/mde.css.gz +0 -0
  99. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/mde.js.gz +0 -0
  100. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/msg.css.gz +0 -0
  101. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/splash.css.gz +0 -0
  102. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/splash.js.gz +0 -0
  103. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/svcs.js.gz +0 -0
  104. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/ui.css.gz +0 -0
  105. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/up2k.js.gz +0 -0
  106. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/util.js.gz +0 -0
  107. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty/web/w.hash.js.gz +0 -0
  108. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty.egg-info/SOURCES.txt +0 -0
  109. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty.egg-info/dependency_links.txt +0 -0
  110. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty.egg-info/entry_points.txt +0 -0
  111. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty.egg-info/requires.txt +0 -0
  112. {copyparty-1.10.1 → copyparty-1.10.2}/copyparty.egg-info/top_level.txt +0 -0
  113. {copyparty-1.10.1 → copyparty-1.10.2}/pyproject.toml +0 -0
  114. {copyparty-1.10.1 → copyparty-1.10.2}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.10.1
3
+ Version: 1.10.2
4
4
  Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
5
5
  Author-email: ed <copyparty@ocv.me>
6
6
  License: MIT
@@ -1,8 +1,8 @@
1
1
  # coding: utf-8
2
2
 
3
- VERSION = (1, 10, 1)
3
+ VERSION = (1, 10, 2)
4
4
  CODENAME = "tftp"
5
- BUILD_DT = (2024, 2, 18)
5
+ BUILD_DT = (2024, 2, 21)
6
6
 
7
7
  S_VERSION = ".".join(map(str, VERSION))
8
8
  S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
@@ -20,6 +20,7 @@ from .authsrv import VFS
20
20
  from .bos import bos
21
21
  from .util import (
22
22
  Daemon,
23
+ ODict,
23
24
  Pebkac,
24
25
  exclude_dotfiles,
25
26
  fsenc,
@@ -540,6 +541,8 @@ class Ftpd(object):
540
541
  if self.args.ftp4:
541
542
  ips = [x for x in ips if ":" not in x]
542
543
 
544
+ ips = list(ODict.fromkeys(ips)) # dedup
545
+
543
546
  ioloop = IOLoop()
544
547
  for ip in ips:
545
548
  for h, lp in hs:
@@ -3135,11 +3135,15 @@ class HttpCli(object):
3135
3135
 
3136
3136
  ext = ext.rstrip(".") or "unk"
3137
3137
  if len(ext) > 11:
3138
- ext = "" + ext[-9:]
3138
+ ext = "~" + ext[-9:]
3139
3139
 
3140
+ return self.tx_svg(ext, exact)
3141
+
3142
+ def tx_svg(self, txt , small = False) :
3140
3143
  # chrome cannot handle more than ~2000 unique SVGs
3141
- chrome = " rv:" not in self.ua
3142
- mime, ico = self.ico.get(ext, not exact, chrome)
3144
+ # so url-param "raster" returns a png/webp instead
3145
+ # (useragent-sniffing kinshi due to caching proxies)
3146
+ mime, ico = self.ico.get(txt, not small, "raster" in self.uparam)
3143
3147
 
3144
3148
  lm = formatdate(self.E.t0, usegmt=True)
3145
3149
  self.reply(ico, mime=mime, headers={"Last-Modified": lm})
@@ -3403,6 +3407,9 @@ class HttpCli(object):
3403
3407
  self.reply(pt.encode("utf-8"), status=rc)
3404
3408
  return True
3405
3409
 
3410
+ if "th" in self.ouparam:
3411
+ return self.tx_svg("e" + pt[:3])
3412
+
3406
3413
  t = t.format(self.args.SR)
3407
3414
  qv = quotep(self.vpaths) + self.ourlq()
3408
3415
  html = self.j2s("splash", this=self, qvpath=qv, msg=t)
@@ -3783,12 +3790,15 @@ class HttpCli(object):
3783
3790
  if idx and hasattr(idx, "p_end"):
3784
3791
  icur = idx.get_cur(dbv.realpath)
3785
3792
 
3793
+ th_fmt = self.uparam.get("th")
3786
3794
  if self.can_read:
3787
- th_fmt = self.uparam.get("th")
3788
3795
  if th_fmt is not None:
3796
+ nothumb = "dthumb" in dbv.flags
3789
3797
  if is_dir:
3790
3798
  vrem = vrem.rstrip("/")
3791
- if icur and vrem:
3799
+ if nothumb:
3800
+ pass
3801
+ elif icur and vrem:
3792
3802
  q = "select fn from cv where rd=? and dn=?"
3793
3803
  crd, cdn = vrem.rsplit("/", 1) if "/" in vrem else ("", vrem)
3794
3804
  # no mojibake support:
@@ -3811,10 +3821,10 @@ class HttpCli(object):
3811
3821
  break
3812
3822
 
3813
3823
  if is_dir:
3814
- return self.tx_ico("a.folder")
3824
+ return self.tx_svg("folder")
3815
3825
 
3816
3826
  thp = None
3817
- if self.thumbcli:
3827
+ if self.thumbcli and not nothumb:
3818
3828
  thp = self.thumbcli.get(dbv, vrem, int(st.st_mtime), th_fmt)
3819
3829
 
3820
3830
  if thp:
@@ -3825,6 +3835,9 @@ class HttpCli(object):
3825
3835
 
3826
3836
  return self.tx_ico(rem)
3827
3837
 
3838
+ elif self.can_write and th_fmt is not None:
3839
+ return self.tx_svg("upload\nonly")
3840
+
3828
3841
  elif self.can_get and self.avn:
3829
3842
  axs = self.avn.axs
3830
3843
  if self.uname not in axs.uhtml:
@@ -8,7 +8,7 @@ import re
8
8
 
9
9
  from .__init__ import PY2
10
10
  from .th_srv import HAVE_PIL, HAVE_PILF
11
- from .util import BytesIO # type: ignore
11
+ from .util import BytesIO, html_escape # type: ignore
12
12
 
13
13
 
14
14
  class Ico(object):
@@ -31,10 +31,9 @@ class Ico(object):
31
31
 
32
32
  w = 100
33
33
  h = 30
34
- if "n" in self.args.th_crop and as_thumb:
34
+ if as_thumb:
35
35
  sw, sh = self.args.th_size.split("x")
36
36
  h = int(100.0 / (float(sw) / float(sh)))
37
- w = 100
38
37
 
39
38
  if chrome:
40
39
  # cannot handle more than ~2000 unique SVGs
@@ -99,6 +98,6 @@ class Ico(object):
99
98
  fill="#{}" font-family="monospace" font-size="14px" style="letter-spacing:.5px">{}</text>
100
99
  </g></svg>
101
100
  """
102
- svg = svg.format(h, c[:6], c[6:], ext)
101
+ svg = svg.format(h, c[:6], c[6:], html_escape(ext, True))
103
102
 
104
103
  return "image/svg+xml", svg.encode("utf-8")
@@ -36,7 +36,7 @@ from partftpy.TftpShared import TftpException
36
36
  from .__init__ import EXE, TYPE_CHECKING
37
37
  from .authsrv import VFS
38
38
  from .bos import bos
39
- from .util import BytesIO, Daemon, exclude_dotfiles, min_ex, runhook, undot
39
+ from .util import BytesIO, Daemon, ODict, exclude_dotfiles, min_ex, runhook, undot
40
40
 
41
41
  if TYPE_CHECKING:
42
42
  from .svchub import SvcHub
@@ -166,6 +166,8 @@ class Tftpd(object):
166
166
  if self.args.ftp4:
167
167
  ips = [x for x in ips if ":" not in x]
168
168
 
169
+ ips = list(ODict.fromkeys(ips)) # dedup
170
+
169
171
  for ip in ips:
170
172
  name = "tftp_%s" % (ip,)
171
173
  Daemon(self._start, name, [ip, ports])
@@ -176,18 +178,54 @@ class Tftpd(object):
176
178
 
177
179
  def _start(self, ip, ports):
178
180
  fam = socket.AF_INET6 if ":" in ip else socket.AF_INET
179
- srv = TftpServer.TftpServer("/", self._ls)
180
- with self.mutex:
181
- self.srv.append(srv)
182
- self.ips.append(ip)
183
- try:
184
- srv.listen(ip, self.port, af_family=fam, ports=ports)
185
- except OSError:
181
+ have_been_alive = False
182
+ while True:
183
+ srv = TftpServer.TftpServer("/", self._ls)
186
184
  with self.mutex:
187
- self.srv.remove(srv)
188
- self.ips.remove(ip)
189
- if ip != "0.0.0.0" or "::" not in self.ips:
190
- raise
185
+ self.srv.append(srv)
186
+ self.ips.append(ip)
187
+
188
+ try:
189
+ # this is the listen loop; it should block forever
190
+ srv.listen(ip, self.port, af_family=fam, ports=ports)
191
+ except:
192
+ with self.mutex:
193
+ self.srv.remove(srv)
194
+ self.ips.remove(ip)
195
+
196
+ try:
197
+ srv.sock.close()
198
+ except:
199
+ pass
200
+
201
+ try:
202
+ bound = bool(srv.listenport)
203
+ except:
204
+ bound = False
205
+
206
+ if bound:
207
+ # this instance has managed to bind at least once
208
+ have_been_alive = True
209
+
210
+ if have_been_alive:
211
+ t = "tftp server [%s]:%d crashed; restarting in 3 sec:\n%s"
212
+ error(t, ip, self.port, min_ex())
213
+ time.sleep(3)
214
+ continue
215
+
216
+ # server failed to start; could be due to dualstack (ipv6 managed to bind and this is ipv4)
217
+ if ip != "0.0.0.0" or "::" not in self.ips:
218
+ # nope, it's fatal
219
+ t = "tftp server [%s]:%d failed to start:\n%s"
220
+ error(t, ip, self.port, min_ex())
221
+
222
+ # yep; ignore
223
+ # (TODO: move the "listening @ ..." infolog in partftpy to
224
+ # after the bind attempt so it doesn't print twice)
225
+ return
226
+
227
+ info("tftp server [%s]:%d terminated", ip, self.port)
228
+ break
191
229
 
192
230
  def stop(self):
193
231
  with self.mutex:
@@ -25,3 +25,4 @@
25
25
  </body>
26
26
 
27
27
  </html>
28
+
@@ -160,3 +160,4 @@ try { l.light = drk? 0:1; } catch (ex) { }
160
160
  <script src="{{ r }}/.cpr/md2.js?_={{ ts }}"></script>
161
161
  {%- endif %}
162
162
  </body></html>
163
+
@@ -54,3 +54,4 @@ try { l.light = drk? 0:1; } catch (ex) { }
54
54
  <script src="{{ r }}/.cpr/deps/easymde.js?_={{ ts }}"></script>
55
55
  <script src="{{ r }}/.cpr/mde.js?_={{ ts }}"></script>
56
56
  </body></html>
57
+
@@ -48,4 +48,5 @@
48
48
  {%- endif %}
49
49
  </body>
50
50
 
51
- </html>
51
+ </html>
52
+
@@ -118,3 +118,4 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
118
118
  <script src="{{ r }}/.cpr/splash.js?_={{ ts }}"></script>
119
119
  </body>
120
120
  </html>
121
+
@@ -246,3 +246,4 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ args.theme }}";
246
246
  <script src="{{ r }}/.cpr/svcs.js?_={{ ts }}"></script>
247
247
  </body>
248
248
  </html>
249
+
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: copyparty
3
- Version: 1.10.1
3
+ Version: 1.10.2
4
4
  Summary: Portable file server with accelerated resumable uploads, deduplication, WebDAV, FTP, zeroconf, media indexer, video thumbnails, audio transcoding, and write-only folders
5
5
  Author-email: ed <copyparty@ocv.me>
6
6
  License: MIT
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes