copyparty 1.10.2__py3-none-any.whl → 1.11.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.
Files changed (45) hide show
  1. copyparty/__main__.py +16 -6
  2. copyparty/__version__.py +3 -3
  3. copyparty/authsrv.py +365 -66
  4. copyparty/cfg.py +3 -0
  5. copyparty/ftpd.py +2 -2
  6. copyparty/httpcli.py +113 -48
  7. copyparty/httpconn.py +4 -1
  8. copyparty/httpsrv.py +8 -3
  9. copyparty/metrics.py +3 -0
  10. copyparty/multicast.py +1 -1
  11. copyparty/smbd.py +1 -1
  12. copyparty/svchub.py +55 -14
  13. copyparty/tftpd.py +11 -9
  14. copyparty/up2k.py +143 -49
  15. copyparty/util.py +52 -8
  16. copyparty/web/baguettebox.js.gz +0 -0
  17. copyparty/web/browser.css.gz +0 -0
  18. copyparty/web/browser.html +1 -1
  19. copyparty/web/browser.js.gz +0 -0
  20. copyparty/web/browser2.html +1 -1
  21. copyparty/web/deps/easymde.css.gz +0 -0
  22. copyparty/web/deps/easymde.js.gz +0 -0
  23. copyparty/web/md.css.gz +0 -0
  24. copyparty/web/md.html +1 -1
  25. copyparty/web/md.js.gz +0 -0
  26. copyparty/web/md2.css.gz +0 -0
  27. copyparty/web/md2.js.gz +0 -0
  28. copyparty/web/mde.css.gz +0 -0
  29. copyparty/web/mde.html +1 -1
  30. copyparty/web/mde.js.gz +0 -0
  31. copyparty/web/msg.css.gz +0 -0
  32. copyparty/web/msg.html +1 -1
  33. copyparty/web/splash.css.gz +0 -0
  34. copyparty/web/splash.html +4 -2
  35. copyparty/web/splash.js.gz +0 -0
  36. copyparty/web/svcs.html +1 -1
  37. copyparty/web/ui.css.gz +0 -0
  38. copyparty/web/up2k.js.gz +0 -0
  39. copyparty/web/util.js.gz +0 -0
  40. {copyparty-1.10.2.dist-info → copyparty-1.11.1.dist-info}/METADATA +62 -20
  41. {copyparty-1.10.2.dist-info → copyparty-1.11.1.dist-info}/RECORD +45 -43
  42. {copyparty-1.10.2.dist-info → copyparty-1.11.1.dist-info}/WHEEL +1 -1
  43. {copyparty-1.10.2.dist-info → copyparty-1.11.1.dist-info}/LICENSE +0 -0
  44. {copyparty-1.10.2.dist-info → copyparty-1.11.1.dist-info}/entry_points.txt +0 -0
  45. {copyparty-1.10.2.dist-info → copyparty-1.11.1.dist-info}/top_level.txt +0 -0
copyparty/up2k.py CHANGED
@@ -196,11 +196,16 @@ class Up2k(object):
196
196
 
197
197
  Daemon(self.deferred_init, "up2k-deferred-init")
198
198
 
199
- def reload(self) :
200
- self.gid += 1
201
- self.log("reload #{} initiated".format(self.gid))
199
+ def reload(self, rescan_all_vols ) :
200
+ """mutex me"""
201
+ self.log("reload #{} scheduled".format(self.gid + 1))
202
202
  all_vols = self.asrv.vfs.all_vols
203
- self.rescan(all_vols, list(all_vols.keys()), True, False)
203
+
204
+ scan_vols = [k for k, v in all_vols.items() if v.realpath not in self.registry]
205
+ if rescan_all_vols:
206
+ scan_vols = list(all_vols.keys())
207
+
208
+ self._rescan(all_vols, scan_vols, True, False)
204
209
 
205
210
  def deferred_init(self) :
206
211
  all_vols = self.asrv.vfs.all_vols
@@ -229,8 +234,6 @@ class Up2k(object):
229
234
  for n in range(max(1, self.args.mtag_mt)):
230
235
  Daemon(self._tagger, "tagger-{}".format(n))
231
236
 
232
- Daemon(self._run_all_mtp, "up2k-mtp-init")
233
-
234
237
  def log(self, msg , c = 0) :
235
238
  if self.pp:
236
239
  msg += "\033[K"
@@ -279,9 +282,48 @@ class Up2k(object):
279
282
  }
280
283
  return json.dumps(ret, indent=4)
281
284
 
285
+ def get_unfinished_by_user(self, uname, ip) :
286
+ if PY2 or not self.mutex.acquire(timeout=2):
287
+ return '[{"timeout":1}]'
288
+
289
+ ret = []
290
+ try:
291
+ for ptop, tab2 in self.registry.items():
292
+ cfg = self.flags.get(ptop, {}).get("u2abort", 1)
293
+ if not cfg:
294
+ continue
295
+ addr = (ip or "\n") if cfg in (1, 2) else ""
296
+ user = (uname or "\n") if cfg in (1, 3) else ""
297
+ drp = self.droppable.get(ptop, {})
298
+ for wark, job in tab2.items():
299
+ if (
300
+ wark in drp
301
+ or (user and user != job["user"])
302
+ or (addr and addr != job["addr"])
303
+ ):
304
+ continue
305
+
306
+ zt5 = (
307
+ int(job["t0"]),
308
+ djoin(job["vtop"], job["prel"], job["name"]),
309
+ job["size"],
310
+ len(job["need"]),
311
+ len(job["hash"]),
312
+ )
313
+ ret.append(zt5)
314
+ finally:
315
+ self.mutex.release()
316
+
317
+ ret.sort(reverse=True)
318
+ ret2 = [
319
+ {"at": at, "vp": "/" + vp, "pd": 100 - ((nn * 100) // (nh or 1)), "sz": sz}
320
+ for (at, vp, sz, nn, nh) in ret
321
+ ]
322
+ return json.dumps(ret2, indent=0)
323
+
282
324
  def get_unfinished(self) :
283
325
  if PY2 or not self.mutex.acquire(timeout=0.5):
284
- return "{}"
326
+ return ""
285
327
 
286
328
  ret = {}
287
329
  try:
@@ -334,14 +376,21 @@ class Up2k(object):
334
376
  def rescan(
335
377
  self, all_vols , scan_vols , wait , fscan
336
378
  ) :
379
+ with self.mutex:
380
+ return self._rescan(all_vols, scan_vols, wait, fscan)
381
+
382
+ def _rescan(
383
+ self, all_vols , scan_vols , wait , fscan
384
+ ) :
385
+ """mutex me"""
337
386
  if not wait and self.pp:
338
387
  return "cannot initiate; scan is already in progress"
339
388
 
340
- args = (all_vols, scan_vols, fscan)
389
+ self.gid += 1
341
390
  Daemon(
342
391
  self.init_indexes,
343
392
  "up2k-rescan-{}".format(scan_vols[0] if scan_vols else "all"),
344
- args,
393
+ (all_vols, scan_vols, fscan, self.gid),
345
394
  )
346
395
  return ""
347
396
 
@@ -453,7 +502,7 @@ class Up2k(object):
453
502
  if vp:
454
503
  fvp = "%s/%s" % (vp, fvp)
455
504
 
456
- self._handle_rm(LEELOO_DALLAS, "", fvp, [], True)
505
+ self._handle_rm(LEELOO_DALLAS, "", fvp, [], True, False)
457
506
  nrm += 1
458
507
 
459
508
  if nrm:
@@ -572,19 +621,32 @@ class Up2k(object):
572
621
  return True, ret
573
622
 
574
623
  def init_indexes(
575
- self, all_vols , scan_vols , fscan
624
+ self, all_vols , scan_vols , fscan , gid = 0
576
625
  ) :
577
- gid = self.gid
578
- while self.pp and gid == self.gid:
579
- time.sleep(0.1)
626
+ if not gid:
627
+ with self.mutex:
628
+ gid = self.gid
580
629
 
581
- if gid != self.gid:
582
- return False
630
+ nspin = 0
631
+ while True:
632
+ nspin += 1
633
+ if nspin > 1:
634
+ time.sleep(0.1)
635
+
636
+ with self.mutex:
637
+ if gid != self.gid:
638
+ return False
639
+
640
+ if self.pp:
641
+ continue
642
+
643
+ self.pp = ProgressPrinter(self.log, self.args)
644
+
645
+ break
583
646
 
584
647
  if gid:
585
- self.log("reload #{} running".format(self.gid))
648
+ self.log("reload #%d running" % (gid,))
586
649
 
587
- self.pp = ProgressPrinter(self.log, self.args)
588
650
  vols = list(all_vols.values())
589
651
  t0 = time.time()
590
652
  have_e2d = False
@@ -768,20 +830,14 @@ class Up2k(object):
768
830
  msg = "could not read tags because no backends are available (Mutagen or FFprobe)"
769
831
  self.log(msg, c=1)
770
832
 
771
- thr = None
772
- if self.mtag:
773
- t = "online (running mtp)"
774
- if scan_vols:
775
- thr = Daemon(self._run_all_mtp, "up2k-mtp-scan", r=False)
776
- else:
777
- self.pp = None
778
- t = "online, idle"
779
-
833
+ t = "online (running mtp)" if self.mtag else "online, idle"
780
834
  for vol in vols:
781
835
  self.volstate[vol.vpath] = t
782
836
 
783
- if thr:
784
- thr.start()
837
+ if self.mtag:
838
+ Daemon(self._run_all_mtp, "up2k-mtp-scan", (gid,))
839
+ else:
840
+ self.pp = None
785
841
 
786
842
  return have_e2d
787
843
 
@@ -1806,26 +1862,28 @@ class Up2k(object):
1806
1862
  self.pending_tags = []
1807
1863
  return ret
1808
1864
 
1809
- def _run_all_mtp(self) :
1810
- gid = self.gid
1865
+ def _run_all_mtp(self, gid ) :
1811
1866
  t0 = time.time()
1812
1867
  for ptop, flags in self.flags.items():
1813
1868
  if "mtp" in flags:
1814
1869
  if ptop not in self.entags:
1815
1870
  t = "skipping mtp for unavailable volume {}"
1816
1871
  self.log(t.format(ptop), 1)
1817
- continue
1818
- self._run_one_mtp(ptop, gid)
1872
+ else:
1873
+ self._run_one_mtp(ptop, gid)
1874
+
1875
+ vtop = "\n"
1876
+ for vol in self.asrv.vfs.all_vols.values():
1877
+ if vol.realpath == ptop:
1878
+ vtop = vol.vpath
1879
+ if "running mtp" in self.volstate.get(vtop, ""):
1880
+ self.volstate[vtop] = "online, idle"
1819
1881
 
1820
1882
  td = time.time() - t0
1821
1883
  msg = "mtp finished in {:.2f} sec ({})"
1822
1884
  self.log(msg.format(td, s2hms(td, True)))
1823
1885
 
1824
1886
  self.pp = None
1825
- for k in list(self.volstate.keys()):
1826
- if "OFFLINE" not in self.volstate[k]:
1827
- self.volstate[k] = "online, idle"
1828
-
1829
1887
  if self.args.exit == "idx":
1830
1888
  self.hub.sigterm()
1831
1889
 
@@ -2668,6 +2726,9 @@ class Up2k(object):
2668
2726
  a = [job[x] for x in zs.split()]
2669
2727
  self.db_add(cur, vfs.flags, *a)
2670
2728
  cur.connection.commit()
2729
+ elif wark in reg:
2730
+ # checks out, but client may have hopped IPs
2731
+ job["addr"] = cj["addr"]
2671
2732
 
2672
2733
  if not job:
2673
2734
  ap1 = djoin(cj["ptop"], cj["prel"])
@@ -3204,7 +3265,13 @@ class Up2k(object):
3204
3265
  pass
3205
3266
 
3206
3267
  def handle_rm(
3207
- self, uname , ip , vpaths , lim , rm_up
3268
+ self,
3269
+ uname ,
3270
+ ip ,
3271
+ vpaths ,
3272
+ lim ,
3273
+ rm_up ,
3274
+ unpost ,
3208
3275
  ) :
3209
3276
  n_files = 0
3210
3277
  ok = {}
@@ -3214,7 +3281,7 @@ class Up2k(object):
3214
3281
  self.log("hit delete limit of {} files".format(lim[1]), 3)
3215
3282
  break
3216
3283
 
3217
- a, b, c = self._handle_rm(uname, ip, vp, lim, rm_up)
3284
+ a, b, c = self._handle_rm(uname, ip, vp, lim, rm_up, unpost)
3218
3285
  n_files += a
3219
3286
  for k in b:
3220
3287
  ok[k] = 1
@@ -3228,25 +3295,43 @@ class Up2k(object):
3228
3295
  return "deleted {} files (and {}/{} folders)".format(n_files, iok, iok + ing)
3229
3296
 
3230
3297
  def _handle_rm(
3231
- self, uname , ip , vpath , lim , rm_up
3298
+ self, uname , ip , vpath , lim , rm_up , unpost
3232
3299
  ) :
3233
3300
  self.db_act = time.time()
3234
- try:
3301
+ partial = ""
3302
+ if not unpost:
3235
3303
  permsets = [[True, False, False, True]]
3236
3304
  vn, rem = self.asrv.vfs.get(vpath, uname, *permsets[0])
3237
3305
  vn, rem = vn.get_dbv(rem)
3238
- unpost = False
3239
- except:
3306
+ else:
3240
3307
  # unpost with missing permissions? verify with db
3241
- if not self.args.unpost:
3242
- raise Pebkac(400, "the unpost feature is disabled in server config")
3243
-
3244
- unpost = True
3245
3308
  permsets = [[False, True]]
3246
3309
  vn, rem = self.asrv.vfs.get(vpath, uname, *permsets[0])
3247
3310
  vn, rem = vn.get_dbv(rem)
3311
+ ptop = vn.realpath
3248
3312
  with self.mutex:
3249
- _, _, _, _, dip, dat = self._find_from_vpath(vn.realpath, rem)
3313
+ abrt_cfg = self.flags.get(ptop, {}).get("u2abort", 1)
3314
+ addr = (ip or "\n") if abrt_cfg in (1, 2) else ""
3315
+ user = (uname or "\n") if abrt_cfg in (1, 3) else ""
3316
+ reg = self.registry.get(ptop, {}) if abrt_cfg else {}
3317
+ for wark, job in reg.items():
3318
+ if (user and user != job["user"]) or (addr and addr != job["addr"]):
3319
+ continue
3320
+ if djoin(job["prel"], job["name"]) == rem:
3321
+ if job["ptop"] != ptop:
3322
+ t = "job.ptop [%s] != vol.ptop [%s] ??"
3323
+ raise Exception(t % (job["ptop"] != ptop))
3324
+ partial = vn.canonical(vjoin(job["prel"], job["tnam"]))
3325
+ break
3326
+ if partial:
3327
+ dip = ip
3328
+ dat = time.time()
3329
+ else:
3330
+ if not self.args.unpost:
3331
+ t = "the unpost feature is disabled in server config"
3332
+ raise Pebkac(400, t)
3333
+
3334
+ _, _, _, _, dip, dat = self._find_from_vpath(ptop, rem)
3250
3335
 
3251
3336
  t = "you cannot delete this: "
3252
3337
  if not dip:
@@ -3339,6 +3424,9 @@ class Up2k(object):
3339
3424
  cur.connection.commit()
3340
3425
 
3341
3426
  wunlink(self.log, abspath, dbv.flags)
3427
+ if partial:
3428
+ wunlink(self.log, partial, dbv.flags)
3429
+ partial = ""
3342
3430
  if xad:
3343
3431
  runhook(
3344
3432
  self.log,
@@ -3934,7 +4022,13 @@ class Up2k(object):
3934
4022
 
3935
4023
  if not ANYWIN and sprs and sz > 1024 * 1024:
3936
4024
  fs = self.fstab.get(pdir)
3937
- if fs != "ok":
4025
+ if fs == "ok":
4026
+ pass
4027
+ elif "sparse" in self.flags[job["ptop"]]:
4028
+ t = "volflag 'sparse' is forcing use of sparse files for uploads to [%s]"
4029
+ self.log(t % (job["ptop"],))
4030
+ relabel = True
4031
+ else:
3938
4032
  relabel = True
3939
4033
  f.seek(1024 * 1024 - 1)
3940
4034
  f.write(b"e")
copyparty/util.py CHANGED
@@ -165,7 +165,7 @@ else:
165
165
 
166
166
  SYMTIME = sys.version_info > (3, 6) and os.utime in os.supports_follow_symlinks
167
167
 
168
- META_NOBOTS = '<meta name="robots" content="noindex, nofollow">'
168
+ META_NOBOTS = '<meta name="robots" content="noindex, nofollow">\n'
169
169
 
170
170
  FFMPEG_URL = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-git-full.7z"
171
171
 
@@ -538,20 +538,26 @@ class HLog(logging.Handler):
538
538
 
539
539
 
540
540
  class NetMap(object):
541
- def __init__(self, ips , netdevs ) :
541
+ def __init__(self, ips , cidrs , keep_lo=False) :
542
+ """
543
+ ips: list of plain ipv4/ipv6 IPs, not cidr
544
+ cidrs: list of cidr-notation IPs (ip/prefix)
545
+ """
542
546
  if "::" in ips:
543
547
  ips = [x for x in ips if x != "::"] + list(
544
- [x.split("/")[0] for x in netdevs if ":" in x]
548
+ [x.split("/")[0] for x in cidrs if ":" in x]
545
549
  )
546
550
  ips.append("0.0.0.0")
547
551
 
548
552
  if "0.0.0.0" in ips:
549
553
  ips = [x for x in ips if x != "0.0.0.0"] + list(
550
- [x.split("/")[0] for x in netdevs if ":" not in x]
554
+ [x.split("/")[0] for x in cidrs if ":" not in x]
551
555
  )
552
556
 
553
- ips = [x for x in ips if x not in ("::1", "127.0.0.1")]
554
- ips = find_prefix(ips, netdevs)
557
+ if not keep_lo:
558
+ ips = [x for x in ips if x not in ("::1", "127.0.0.1")]
559
+
560
+ ips = find_prefix(ips, cidrs)
555
561
 
556
562
  self.cache = {}
557
563
  self.b2sip = {}
@@ -568,6 +574,9 @@ class NetMap(object):
568
574
  self.bip.sort(reverse=True)
569
575
 
570
576
  def map(self, ip ) :
577
+ if ip.startswith("::ffff:"):
578
+ ip = ip[7:]
579
+
571
580
  try:
572
581
  return self.cache[ip]
573
582
  except:
@@ -1899,10 +1908,10 @@ def ipnorm(ip ) :
1899
1908
  return ip
1900
1909
 
1901
1910
 
1902
- def find_prefix(ips , netdevs ) :
1911
+ def find_prefix(ips , cidrs ) :
1903
1912
  ret = []
1904
1913
  for ip in ips:
1905
- hit = next((x for x in netdevs if x.startswith(ip + "/")), None)
1914
+ hit = next((x for x in cidrs if x.startswith(ip + "/") or ip == x), None)
1906
1915
  if hit:
1907
1916
  ret.append(hit)
1908
1917
  return ret
@@ -2296,6 +2305,41 @@ def list_ips() :
2296
2305
  return list(ret)
2297
2306
 
2298
2307
 
2308
+ def build_netmap(csv ):
2309
+ csv = csv.lower().strip()
2310
+
2311
+ if csv in ("any", "all", "no", ",", ""):
2312
+ return None
2313
+
2314
+ if csv in ("lan", "local", "private", "prvt"):
2315
+ csv = "10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fd00::/8" # lan
2316
+ csv += ", 169.254.0.0/16, fe80::/10" # link-local
2317
+ csv += ", 127.0.0.0/8, ::1/128" # loopback
2318
+
2319
+ srcs = [x.strip() for x in csv.split(",") if x.strip()]
2320
+ cidrs = []
2321
+ for zs in srcs:
2322
+ if not zs.endswith("."):
2323
+ cidrs.append(zs)
2324
+ continue
2325
+
2326
+ # translate old syntax "172.19." => "172.19.0.0/16"
2327
+ words = len(zs.rstrip(".").split("."))
2328
+ if words == 1:
2329
+ zs += "0.0.0/8"
2330
+ elif words == 2:
2331
+ zs += "0.0/16"
2332
+ elif words == 3:
2333
+ zs += "0/24"
2334
+ else:
2335
+ raise Exception("invalid config value [%s]" % (zs,))
2336
+
2337
+ cidrs.append(zs)
2338
+
2339
+ ips = [x.split("/")[0] for x in cidrs]
2340
+ return NetMap(ips, cidrs, True)
2341
+
2342
+
2299
2343
  def yieldfile(fn ) :
2300
2344
  with open(fsenc(fn), "rb", 512 * 1024) as f:
2301
2345
  while True:
Binary file
Binary file
@@ -7,9 +7,9 @@
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8, minimum-scale=0.6">
9
9
  <meta name="theme-color" content="#333">
10
- {{ html_head }}
11
10
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
12
11
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/browser.css?_={{ ts }}">
12
+ {{ html_head }}
13
13
  {%- if css %}
14
14
  <link rel="stylesheet" media="screen" href="{{ css }}_={{ ts }}">
15
15
  {%- endif %}
Binary file
@@ -6,12 +6,12 @@
6
6
  <title>{{ title }}</title>
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
- {{ html_head }}
10
9
  <style>
11
10
  html{font-family:sans-serif}
12
11
  td{border:1px solid #999;border-width:1px 1px 0 0;padding:0 5px}
13
12
  a{display:block}
14
13
  </style>
14
+ {{ html_head }}
15
15
  </head>
16
16
 
17
17
  <body>
Binary file
Binary file
copyparty/web/md.css.gz CHANGED
Binary file
copyparty/web/md.html CHANGED
@@ -4,12 +4,12 @@
4
4
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=0.7">
6
6
  <meta name="theme-color" content="#333">
7
- {{ html_head }}
8
7
  <link rel="stylesheet" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
9
8
  <link rel="stylesheet" href="{{ r }}/.cpr/md.css?_={{ ts }}">
10
9
  {%- if edit %}
11
10
  <link rel="stylesheet" href="{{ r }}/.cpr/md2.css?_={{ ts }}">
12
11
  {%- endif %}
12
+ {{ html_head }}
13
13
  </head>
14
14
  <body>
15
15
  <div id="mn"></div>
copyparty/web/md.js.gz CHANGED
Binary file
copyparty/web/md2.css.gz CHANGED
Binary file
copyparty/web/md2.js.gz CHANGED
Binary file
copyparty/web/mde.css.gz CHANGED
Binary file
copyparty/web/mde.html CHANGED
@@ -4,11 +4,11 @@
4
4
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=0.7">
6
6
  <meta name="theme-color" content="#333">
7
- {{ html_head }}
8
7
  <link rel="stylesheet" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
9
8
  <link rel="stylesheet" href="{{ r }}/.cpr/mde.css?_={{ ts }}">
10
9
  <link rel="stylesheet" href="{{ r }}/.cpr/deps/mini-fa.css?_={{ ts }}">
11
10
  <link rel="stylesheet" href="{{ r }}/.cpr/deps/easymde.css?_={{ ts }}">
11
+ {{ html_head }}
12
12
  </head>
13
13
  <body>
14
14
  <div id="mw">
copyparty/web/mde.js.gz CHANGED
Binary file
copyparty/web/msg.css.gz CHANGED
Binary file
copyparty/web/msg.html CHANGED
@@ -7,8 +7,8 @@
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
9
  <meta name="theme-color" content="#333">
10
- {{ html_head }}
11
10
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/msg.css?_={{ ts }}">
11
+ {{ html_head }}
12
12
  </head>
13
13
 
14
14
  <body>
Binary file
copyparty/web/splash.html CHANGED
@@ -7,9 +7,9 @@
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
9
  <meta name="theme-color" content="#333">
10
- {{ html_head }}
11
10
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
12
11
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
12
+ {{ html_head }}
13
13
  </head>
14
14
 
15
15
  <body>
@@ -78,13 +78,15 @@
78
78
 
79
79
  <h1 id="cc">client config:</h1>
80
80
  <ul>
81
+ {% if k304 or k304vis %}
81
82
  {% if k304 %}
82
83
  <li><a id="h" href="{{ r }}/?k304=n">disable k304</a> (currently enabled)
83
84
  {%- else %}
84
85
  <li><a id="i" href="{{ r }}/?k304=y" class="r">enable k304</a> (currently disabled)
85
86
  {% endif %}
86
87
  <blockquote id="j">enabling this will disconnect your client on every HTTP 304, which can prevent some buggy proxies from getting stuck (suddenly not loading pages), <em>but</em> it will also make things slower in general</blockquote></li>
87
-
88
+ {% endif %}
89
+
88
90
  <li><a id="k" href="{{ r }}/?reset" class="r" onclick="localStorage.clear();return true">reset client settings</a></li>
89
91
  </ul>
90
92
 
Binary file
copyparty/web/svcs.html CHANGED
@@ -7,10 +7,10 @@
7
7
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
8
  <meta name="viewport" content="width=device-width, initial-scale=0.8">
9
9
  <meta name="theme-color" content="#333">
10
- {{ html_head }}
11
10
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
12
11
  <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
13
12
  <style>ul{padding-left:1.3em}li{margin:.4em 0}</style>
13
+ {{ html_head }}
14
14
  </head>
15
15
 
16
16
  <body>
copyparty/web/ui.css.gz CHANGED
Binary file
copyparty/web/up2k.js.gz CHANGED
Binary file
copyparty/web/util.js.gz CHANGED
Binary file