copyparty 1.13.5__py3-none-any.whl → 1.13.7__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 +25 -7
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +9 -6
- copyparty/cert.py +1 -1
- copyparty/fsutil.py +3 -3
- copyparty/ftpd.py +15 -2
- copyparty/httpcli.py +221 -81
- copyparty/httpconn.py +3 -0
- copyparty/httpsrv.py +35 -11
- copyparty/ico.py +1 -1
- copyparty/mtag.py +15 -6
- copyparty/pwhash.py +10 -0
- copyparty/smbd.py +20 -2
- copyparty/ssdp.py +3 -3
- copyparty/stolen/dnslib/dns.py +6 -0
- copyparty/stolen/ifaddr/__init__.py +15 -1
- copyparty/stolen/ifaddr/_shared.py +1 -0
- copyparty/stolen/qrcodegen.py +6 -0
- copyparty/sutil.py +1 -1
- copyparty/svchub.py +72 -3
- copyparty/szip.py +1 -3
- copyparty/tcpsrv.py +60 -8
- copyparty/tftpd.py +30 -4
- copyparty/th_srv.py +22 -1
- copyparty/u2idx.py +4 -1
- copyparty/up2k.py +222 -94
- copyparty/util.py +166 -31
- copyparty/web/a/u2c.py +22 -9
- copyparty/web/baguettebox.js.gz +0 -0
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/browser2.html +0 -1
- copyparty/web/md.html +3 -0
- copyparty/web/mde.html +3 -0
- copyparty/web/msg.html +3 -0
- copyparty/web/splash.html +3 -0
- copyparty/web/svcs.html +5 -2
- copyparty/web/ui.css.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- copyparty/web/util.js.gz +0 -0
- {copyparty-1.13.5.dist-info → copyparty-1.13.7.dist-info}/METADATA +66 -14
- {copyparty-1.13.5.dist-info → copyparty-1.13.7.dist-info}/RECORD +46 -46
- {copyparty-1.13.5.dist-info → copyparty-1.13.7.dist-info}/WHEEL +1 -1
- {copyparty-1.13.5.dist-info → copyparty-1.13.7.dist-info}/LICENSE +0 -0
- {copyparty-1.13.5.dist-info → copyparty-1.13.7.dist-info}/entry_points.txt +0 -0
- {copyparty-1.13.5.dist-info → copyparty-1.13.7.dist-info}/top_level.txt +0 -0
copyparty/util.py
CHANGED
@@ -26,7 +26,6 @@ import threading
|
|
26
26
|
import time
|
27
27
|
import traceback
|
28
28
|
from collections import Counter
|
29
|
-
from email.utils import formatdate
|
30
29
|
|
31
30
|
from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network
|
32
31
|
from queue import Queue
|
@@ -60,6 +59,10 @@ except:
|
|
60
59
|
UTC = _UTC()
|
61
60
|
|
62
61
|
|
62
|
+
if PY2:
|
63
|
+
range = xrange # type: ignore
|
64
|
+
|
65
|
+
|
63
66
|
if sys.version_info >= (3, 7) or (
|
64
67
|
sys.version_info >= (3, 6) and platform.python_implementation() == "CPython"
|
65
68
|
):
|
@@ -99,6 +102,9 @@ except:
|
|
99
102
|
pass
|
100
103
|
|
101
104
|
try:
|
105
|
+
if os.environ.get("PRTY_NO_SQLITE"):
|
106
|
+
raise Exception()
|
107
|
+
|
102
108
|
HAVE_SQLITE3 = True
|
103
109
|
import sqlite3
|
104
110
|
|
@@ -107,6 +113,9 @@ except:
|
|
107
113
|
HAVE_SQLITE3 = False
|
108
114
|
|
109
115
|
try:
|
116
|
+
if os.environ.get("PRTY_NO_PSUTIL"):
|
117
|
+
raise Exception()
|
118
|
+
|
110
119
|
HAVE_PSUTIL = True
|
111
120
|
import psutil
|
112
121
|
except:
|
@@ -116,10 +125,15 @@ if TYPE_CHECKING:
|
|
116
125
|
import magic
|
117
126
|
|
118
127
|
from .authsrv import VFS
|
128
|
+
from .broker_util import BrokerCli
|
129
|
+
from .up2k import Up2k
|
119
130
|
|
120
131
|
FAKE_MP = False
|
121
132
|
|
122
133
|
try:
|
134
|
+
if os.environ.get("PRTY_NO_MP"):
|
135
|
+
raise ImportError()
|
136
|
+
|
123
137
|
import multiprocessing as mp
|
124
138
|
|
125
139
|
# import multiprocessing.dummy as mp
|
@@ -138,6 +152,9 @@ else:
|
|
138
152
|
|
139
153
|
|
140
154
|
try:
|
155
|
+
if os.environ.get("PRTY_NO_IPV6"):
|
156
|
+
raise Exception()
|
157
|
+
|
141
158
|
socket.inet_pton(socket.AF_INET6, "::1")
|
142
159
|
HAVE_IPV6 = True
|
143
160
|
except:
|
@@ -773,7 +790,7 @@ class CachedSet(object):
|
|
773
790
|
|
774
791
|
c = self.c = {k: v for k, v in self.c.items() if now - v < self.maxage}
|
775
792
|
try:
|
776
|
-
self.oldest = c[min(c, key=c.get)]
|
793
|
+
self.oldest = c[min(c, key=c.get)] # type: ignore
|
777
794
|
except:
|
778
795
|
self.oldest = now
|
779
796
|
|
@@ -1800,10 +1817,21 @@ def gen_filekey_dbg(
|
|
1800
1817
|
return ret
|
1801
1818
|
|
1802
1819
|
|
1820
|
+
WKDAYS = "Mon Tue Wed Thu Fri Sat Sun".split()
|
1821
|
+
MONTHS = "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split()
|
1822
|
+
RFC2822 = "%s, %02d %s %04d %02d:%02d:%02d GMT"
|
1823
|
+
|
1824
|
+
|
1825
|
+
def formatdate(ts = None) :
|
1826
|
+
# gmtime ~= datetime.fromtimestamp(ts, UTC).timetuple()
|
1827
|
+
y, mo, d, h, mi, s, wd, _, _ = time.gmtime(ts)
|
1828
|
+
return RFC2822 % (WKDAYS[wd], d, MONTHS[mo - 1], y, h, mi, s)
|
1829
|
+
|
1830
|
+
|
1803
1831
|
def gencookie(k , v , r , tls , dur = 0, txt = "") :
|
1804
1832
|
v = v.replace("%", "%25").replace(";", "%3B")
|
1805
1833
|
if dur:
|
1806
|
-
exp = formatdate(time.time() + dur
|
1834
|
+
exp = formatdate(time.time() + dur)
|
1807
1835
|
else:
|
1808
1836
|
exp = "Fri, 15 Aug 1997 01:00:00 GMT"
|
1809
1837
|
|
@@ -1818,12 +1846,10 @@ def humansize(sz , terse = False) :
|
|
1818
1846
|
|
1819
1847
|
sz /= 1024.0
|
1820
1848
|
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
return
|
1825
|
-
|
1826
|
-
return ret.replace("iB", "").replace(" ", "")
|
1849
|
+
if terse:
|
1850
|
+
return "%s%s" % (str(sz)[:4].rstrip("."), unit[:1])
|
1851
|
+
else:
|
1852
|
+
return "%s %s" % (str(sz)[:4].rstrip("."), unit)
|
1827
1853
|
|
1828
1854
|
|
1829
1855
|
def unhumanize(sz ) :
|
@@ -1875,7 +1901,7 @@ def uncyg(path ) :
|
|
1875
1901
|
def undot(path ) :
|
1876
1902
|
ret = []
|
1877
1903
|
for node in path.split("/"):
|
1878
|
-
if node
|
1904
|
+
if node == "." or not node:
|
1879
1905
|
continue
|
1880
1906
|
|
1881
1907
|
if node == "..":
|
@@ -2028,7 +2054,7 @@ def _quotep2(txt ) :
|
|
2028
2054
|
"""url quoter which deals with bytes correctly"""
|
2029
2055
|
btxt = w8enc(txt)
|
2030
2056
|
quot = quote(btxt, safe=b"/")
|
2031
|
-
return w8dec(quot.replace(b" ", b"+"))
|
2057
|
+
return w8dec(quot.replace(b" ", b"+")) # type: ignore
|
2032
2058
|
|
2033
2059
|
|
2034
2060
|
def _quotep3(txt ) :
|
@@ -2072,6 +2098,72 @@ def ujoin(rd , fn ) :
|
|
2072
2098
|
return rd or fn
|
2073
2099
|
|
2074
2100
|
|
2101
|
+
def log_reloc(
|
2102
|
+
log ,
|
2103
|
+
re ,
|
2104
|
+
pm ,
|
2105
|
+
ap ,
|
2106
|
+
vp ,
|
2107
|
+
fn ,
|
2108
|
+
vn ,
|
2109
|
+
rem ,
|
2110
|
+
) :
|
2111
|
+
nap, nvp, nfn, (nvn, nrem) = pm
|
2112
|
+
t = "reloc %s:\nold ap [%s]\nnew ap [%s\033[36m/%s\033[0m]\nold vp [%s]\nnew vp [%s\033[36m/%s\033[0m]\nold fn [%s]\nnew fn [%s]\nold vfs [%s]\nnew vfs [%s]\nold rem [%s]\nnew rem [%s]"
|
2113
|
+
log(t % (re, ap, nap, nfn, vp, nvp, nfn, fn, nfn, vn.vpath, nvn.vpath, rem, nrem))
|
2114
|
+
|
2115
|
+
|
2116
|
+
def pathmod(
|
2117
|
+
vfs , ap , vp , mod
|
2118
|
+
) :
|
2119
|
+
# vfs: authsrv.vfs
|
2120
|
+
# ap: original abspath to a file
|
2121
|
+
# vp: original urlpath to a file
|
2122
|
+
# mod: modification (ap/vp/fn)
|
2123
|
+
|
2124
|
+
nvp = "\n" # new vpath
|
2125
|
+
ap = os.path.dirname(ap)
|
2126
|
+
vp, fn = vsplit(vp)
|
2127
|
+
if mod.get("fn"):
|
2128
|
+
fn = mod["fn"]
|
2129
|
+
nvp = vp
|
2130
|
+
|
2131
|
+
for ref, k in ((ap, "ap"), (vp, "vp")):
|
2132
|
+
if k not in mod:
|
2133
|
+
continue
|
2134
|
+
|
2135
|
+
ms = mod[k].replace(os.sep, "/")
|
2136
|
+
if ms.startswith("/"):
|
2137
|
+
np = ms
|
2138
|
+
elif k == "vp":
|
2139
|
+
np = undot(vjoin(ref, ms))
|
2140
|
+
else:
|
2141
|
+
np = os.path.abspath(os.path.join(ref, ms))
|
2142
|
+
|
2143
|
+
if k == "vp":
|
2144
|
+
nvp = np.lstrip("/")
|
2145
|
+
continue
|
2146
|
+
|
2147
|
+
# try to map abspath to vpath
|
2148
|
+
np = np.replace("/", os.sep)
|
2149
|
+
for vn_ap, vn in vfs.all_aps:
|
2150
|
+
if not np.startswith(vn_ap):
|
2151
|
+
continue
|
2152
|
+
zs = np[len(vn_ap) :].replace(os.sep, "/")
|
2153
|
+
nvp = vjoin(vn.vpath, zs)
|
2154
|
+
break
|
2155
|
+
|
2156
|
+
if nvp == "\n":
|
2157
|
+
return None
|
2158
|
+
|
2159
|
+
vn, rem = vfs.get(nvp, "*", False, False)
|
2160
|
+
if not vn.realpath:
|
2161
|
+
raise Exception("unmapped vfs")
|
2162
|
+
|
2163
|
+
ap = vn.canonical(rem)
|
2164
|
+
return ap, nvp, fn, (vn, rem)
|
2165
|
+
|
2166
|
+
|
2075
2167
|
def _w8dec2(txt ) :
|
2076
2168
|
"""decodes filesystem-bytes to wtf8"""
|
2077
2169
|
return surrogateescape.decodefilename(txt)
|
@@ -2688,30 +2780,30 @@ def rmdirs_up(top , stop ) :
|
|
2688
2780
|
|
2689
2781
|
def unescape_cookie(orig ) :
|
2690
2782
|
# mw=idk; doot=qwe%2Crty%3Basd+fgh%2Bjkl%25zxc%26vbn # qwe,rty;asd fgh+jkl%zxc&vbn
|
2691
|
-
ret =
|
2783
|
+
ret = []
|
2692
2784
|
esc = ""
|
2693
2785
|
for ch in orig:
|
2694
2786
|
if ch == "%":
|
2695
|
-
if
|
2696
|
-
ret
|
2787
|
+
if esc:
|
2788
|
+
ret.append(esc)
|
2697
2789
|
esc = ch
|
2698
2790
|
|
2699
|
-
elif
|
2791
|
+
elif esc:
|
2700
2792
|
esc += ch
|
2701
2793
|
if len(esc) == 3:
|
2702
2794
|
try:
|
2703
|
-
ret
|
2795
|
+
ret.append(chr(int(esc[1:], 16)))
|
2704
2796
|
except:
|
2705
|
-
ret
|
2797
|
+
ret.append(esc)
|
2706
2798
|
esc = ""
|
2707
2799
|
|
2708
2800
|
else:
|
2709
|
-
ret
|
2801
|
+
ret.append(ch)
|
2710
2802
|
|
2711
|
-
if
|
2712
|
-
ret
|
2803
|
+
if esc:
|
2804
|
+
ret.append(esc)
|
2713
2805
|
|
2714
|
-
return ret
|
2806
|
+
return "".join(ret)
|
2715
2807
|
|
2716
2808
|
|
2717
2809
|
def guess_mime(url , fallback = "application/octet-stream") :
|
@@ -3085,6 +3177,7 @@ def runihook(
|
|
3085
3177
|
|
3086
3178
|
def _runhook(
|
3087
3179
|
log ,
|
3180
|
+
src ,
|
3088
3181
|
cmd ,
|
3089
3182
|
ap ,
|
3090
3183
|
vp ,
|
@@ -3096,14 +3189,16 @@ def _runhook(
|
|
3096
3189
|
ip ,
|
3097
3190
|
at ,
|
3098
3191
|
txt ,
|
3099
|
-
)
|
3192
|
+
) :
|
3193
|
+
ret = {"rc": 0}
|
3100
3194
|
areq, chk, fork, jtxt, wait, sp_ka, acmd = _parsehook(log, cmd)
|
3101
3195
|
if areq:
|
3102
3196
|
for ch in areq:
|
3103
3197
|
if ch not in perms:
|
3104
3198
|
t = "user %s not allowed to run hook %s; need perms %s, have %s"
|
3105
|
-
log
|
3106
|
-
|
3199
|
+
if log:
|
3200
|
+
log(t % (uname, cmd, areq, perms))
|
3201
|
+
return ret # fallthrough to next hook
|
3107
3202
|
if jtxt:
|
3108
3203
|
ja = {
|
3109
3204
|
"ap": ap,
|
@@ -3115,6 +3210,7 @@ def _runhook(
|
|
3115
3210
|
"host": host,
|
3116
3211
|
"user": uname,
|
3117
3212
|
"perms": perms,
|
3213
|
+
"src": src,
|
3118
3214
|
"txt": txt,
|
3119
3215
|
}
|
3120
3216
|
arg = json.dumps(ja)
|
@@ -3133,18 +3229,34 @@ def _runhook(
|
|
3133
3229
|
else:
|
3134
3230
|
rc, v, err = runcmd(bcmd, **sp_ka) # type: ignore
|
3135
3231
|
if chk and rc:
|
3232
|
+
ret["rc"] = rc
|
3136
3233
|
retchk(rc, bcmd, err, log, 5)
|
3137
|
-
|
3234
|
+
else:
|
3235
|
+
try:
|
3236
|
+
ret = json.loads(v)
|
3237
|
+
except:
|
3238
|
+
ret = {}
|
3239
|
+
|
3240
|
+
try:
|
3241
|
+
if "stdout" not in ret:
|
3242
|
+
ret["stdout"] = v
|
3243
|
+
if "rc" not in ret:
|
3244
|
+
ret["rc"] = rc
|
3245
|
+
except:
|
3246
|
+
ret = {"rc": rc, "stdout": v}
|
3138
3247
|
|
3139
3248
|
wait -= time.time() - t0
|
3140
3249
|
if wait > 0:
|
3141
3250
|
time.sleep(wait)
|
3142
3251
|
|
3143
|
-
return
|
3252
|
+
return ret
|
3144
3253
|
|
3145
3254
|
|
3146
3255
|
def runhook(
|
3147
3256
|
log ,
|
3257
|
+
broker ,
|
3258
|
+
up2k ,
|
3259
|
+
src ,
|
3148
3260
|
cmds ,
|
3149
3261
|
ap ,
|
3150
3262
|
vp ,
|
@@ -3156,19 +3268,42 @@ def runhook(
|
|
3156
3268
|
ip ,
|
3157
3269
|
at ,
|
3158
3270
|
txt ,
|
3159
|
-
)
|
3271
|
+
) :
|
3272
|
+
assert broker or up2k
|
3273
|
+
asrv = (broker or up2k).asrv
|
3274
|
+
args = (broker or up2k).args
|
3160
3275
|
vp = vp.replace("\\", "/")
|
3276
|
+
ret = {"rc": 0}
|
3161
3277
|
for cmd in cmds:
|
3162
3278
|
try:
|
3163
|
-
|
3164
|
-
|
3279
|
+
hr = _runhook(
|
3280
|
+
log, src, cmd, ap, vp, host, uname, perms, mt, sz, ip, at, txt
|
3281
|
+
)
|
3282
|
+
if log and args.hook_v:
|
3283
|
+
log("hook(%s) [%s] => \033[32m%s" % (src, cmd, hr), 6)
|
3284
|
+
if not hr:
|
3285
|
+
return {}
|
3286
|
+
for k, v in hr.items():
|
3287
|
+
if k in ("idx", "del") and v:
|
3288
|
+
if broker:
|
3289
|
+
broker.say("up2k.hook_fx", k, v, vp)
|
3290
|
+
else:
|
3291
|
+
up2k.fx_backlog.append((k, v, vp))
|
3292
|
+
elif k == "reloc" and v:
|
3293
|
+
# idk, just take the last one ig
|
3294
|
+
ret["reloc"] = v
|
3295
|
+
elif k in ret:
|
3296
|
+
if k == "rc" and v:
|
3297
|
+
ret[k] = v
|
3298
|
+
else:
|
3299
|
+
ret[k] = v
|
3165
3300
|
except Exception as ex:
|
3166
3301
|
(log or print)("hook: {}".format(ex))
|
3167
3302
|
if ",c," in "," + cmd:
|
3168
|
-
return
|
3303
|
+
return {}
|
3169
3304
|
break
|
3170
3305
|
|
3171
|
-
return
|
3306
|
+
return ret
|
3172
3307
|
|
3173
3308
|
|
3174
3309
|
def loadpy(ap , hot ) :
|
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.
|
5
|
-
S_BUILD_DT = "2024-
|
4
|
+
S_VERSION = "1.22"
|
5
|
+
S_BUILD_DT = "2024-08-08"
|
6
6
|
|
7
7
|
"""
|
8
8
|
u2c.py: upload to copyparty
|
@@ -660,8 +660,15 @@ def upload(fsl, pw, stats):
|
|
660
660
|
# type: (FileSlice, str, str) -> None
|
661
661
|
"""upload a range of file data, defined by one or more `cid` (chunk-hash)"""
|
662
662
|
|
663
|
+
ctxt = fsl.cids[0]
|
664
|
+
if len(fsl.cids) > 1:
|
665
|
+
n = 192 // len(fsl.cids)
|
666
|
+
n = 9 if n > 9 else 2 if n < 2 else n
|
667
|
+
zsl = [zs[:n] for zs in fsl.cids[1:]]
|
668
|
+
ctxt += ",%d,%s" % (n, "".join(zsl))
|
669
|
+
|
663
670
|
headers = {
|
664
|
-
"X-Up2k-Hash":
|
671
|
+
"X-Up2k-Hash": ctxt,
|
665
672
|
"X-Up2k-Wark": fsl.file.wark,
|
666
673
|
"Content-Type": "application/octet-stream",
|
667
674
|
}
|
@@ -755,6 +762,7 @@ class Ctl(object):
|
|
755
762
|
else:
|
756
763
|
self.at_hash = 0.0
|
757
764
|
self.at_up = 0.0
|
765
|
+
self.at_upr = 0.0
|
758
766
|
self.hash_f = 0
|
759
767
|
self.hash_c = 0
|
760
768
|
self.hash_b = 0
|
@@ -903,8 +911,9 @@ class Ctl(object):
|
|
903
911
|
t = "{0} eta @ {1}/s, {2}, {3}# left".format(self.eta, spd, sleft, nleft)
|
904
912
|
eprint(txt + "\033]0;{0}\033\\\r{0}{1}".format(t, tail))
|
905
913
|
|
906
|
-
|
907
|
-
|
914
|
+
if self.hash_b and self.at_hash:
|
915
|
+
spd = humansize(self.hash_b / self.at_hash)
|
916
|
+
eprint("\nhasher: %.2f sec, %s/s\n" % (self.at_hash, spd))
|
908
917
|
if self.up_b and self.at_up:
|
909
918
|
spd = humansize(self.up_b / self.at_up)
|
910
919
|
eprint("upload: %.2f sec, %s/s\n" % (self.at_up, spd))
|
@@ -1099,9 +1108,6 @@ class Ctl(object):
|
|
1099
1108
|
|
1100
1109
|
if not hs:
|
1101
1110
|
self.at_hash += file.t_hash
|
1102
|
-
if file.up_b:
|
1103
|
-
t_up = file.t1_up - file.t0_up
|
1104
|
-
self.at_up += t_up
|
1105
1111
|
|
1106
1112
|
if self.ar.spd:
|
1107
1113
|
if VT100:
|
@@ -1112,6 +1118,7 @@ class Ctl(object):
|
|
1112
1118
|
|
1113
1119
|
spd_h = humansize(file.size / file.t_hash, True)
|
1114
1120
|
if file.up_b:
|
1121
|
+
t_up = file.t1_up - file.t0_up
|
1115
1122
|
spd_u = humansize(file.size / t_up, True)
|
1116
1123
|
|
1117
1124
|
t = "uploaded %s %s(h:%.2fs,%s/s,up:%.2fs,%s/s)%s"
|
@@ -1123,13 +1130,15 @@ class Ctl(object):
|
|
1123
1130
|
kw = "uploaded" if file.up_b else " found"
|
1124
1131
|
print("{0} {1}".format(kw, upath))
|
1125
1132
|
|
1133
|
+
chunksz = up2k_chunksize(file.size)
|
1134
|
+
njoin = (self.ar.sz * 1024 * 1024) // chunksz
|
1126
1135
|
cs = hs[:]
|
1127
1136
|
while cs:
|
1128
1137
|
fsl = FileSlice(file, cs[:1])
|
1129
1138
|
try:
|
1130
1139
|
if file.nojoin:
|
1131
1140
|
raise Exception()
|
1132
|
-
for n in range(2, min(len(cs),
|
1141
|
+
for n in range(2, min(len(cs), njoin + 1)):
|
1133
1142
|
fsl = FileSlice(file, cs[:n])
|
1134
1143
|
except:
|
1135
1144
|
pass
|
@@ -1147,6 +1156,8 @@ class Ctl(object):
|
|
1147
1156
|
cids = fsl.cids
|
1148
1157
|
|
1149
1158
|
with self.mutex:
|
1159
|
+
if not self.uploader_busy:
|
1160
|
+
self.at_upr = time.time()
|
1150
1161
|
self.uploader_busy += 1
|
1151
1162
|
if not file.t0_up:
|
1152
1163
|
file.t0_up = time.time()
|
@@ -1185,6 +1196,8 @@ class Ctl(object):
|
|
1185
1196
|
file.up_c += 1
|
1186
1197
|
self.up_c += 1
|
1187
1198
|
self.uploader_busy -= 1
|
1199
|
+
if not self.uploader_busy:
|
1200
|
+
self.at_up += time.time() - self.at_upr
|
1188
1201
|
|
1189
1202
|
def up_done(self, file):
|
1190
1203
|
if self.ar.dl:
|
copyparty/web/baguettebox.js.gz
CHANGED
Binary file
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/browser2.html
CHANGED
copyparty/web/md.html
CHANGED
copyparty/web/mde.html
CHANGED
@@ -53,5 +53,8 @@ try { l.light = drk? 0:1; } catch (ex) { }
|
|
53
53
|
<script src="{{ r }}/.cpr/deps/marked.js?_={{ ts }}"></script>
|
54
54
|
<script src="{{ r }}/.cpr/deps/easymde.js?_={{ ts }}"></script>
|
55
55
|
<script src="{{ r }}/.cpr/mde.js?_={{ ts }}"></script>
|
56
|
+
{%- if js %}
|
57
|
+
<script src="{{ js }}_={{ ts }}"></script>
|
58
|
+
{%- endif %}
|
56
59
|
</body></html>
|
57
60
|
|
copyparty/web/msg.html
CHANGED
copyparty/web/splash.html
CHANGED
@@ -119,6 +119,9 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ this.args.theme
|
|
119
119
|
</script>
|
120
120
|
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
|
121
121
|
<script src="{{ r }}/.cpr/splash.js?_={{ ts }}"></script>
|
122
|
+
{%- if js %}
|
123
|
+
<script src="{{ js }}_={{ ts }}"></script>
|
124
|
+
{%- endif %}
|
122
125
|
</body>
|
123
126
|
</html>
|
124
127
|
|
copyparty/web/svcs.html
CHANGED
@@ -56,7 +56,7 @@
|
|
56
56
|
<li>running <code>rclone mount</code> as root? add <code>--allow-other</code></li>
|
57
57
|
<li>old version of rclone? replace all <code>=</code> with <code> </code> (space)</li>
|
58
58
|
</ul>
|
59
|
-
|
59
|
+
|
60
60
|
<p>if you want to use the native WebDAV client in windows instead (slow and buggy), first run <a href="{{ r }}/.cpr/a/webdav-cfg.bat">webdav-cfg.bat</a> to remove the 47 MiB filesize limit (also fixes latency and password login), then connect:</p>
|
61
61
|
<pre>
|
62
62
|
net use <b>w:</b> http{{ s }}://{{ ep }}/{{ rvp }}{% if accs %} k /user:<b>{{ pw }}</b>{% endif %}
|
@@ -105,7 +105,7 @@
|
|
105
105
|
<pre>
|
106
106
|
http{{ s }}://k:<b>{{ pw }}</b>@{{ ep }}/{{ rvp }}
|
107
107
|
</pre>
|
108
|
-
|
108
|
+
|
109
109
|
{% if s %}
|
110
110
|
<p><em>replace <code>https</code> with <code>http</code> if it doesn't work</em></p>
|
111
111
|
{% endif %}
|
@@ -245,6 +245,9 @@ document.documentElement.className = (STG && STG.cpp_thm) || "{{ args.theme }}";
|
|
245
245
|
</script>
|
246
246
|
<script src="{{ r }}/.cpr/util.js?_={{ ts }}"></script>
|
247
247
|
<script src="{{ r }}/.cpr/svcs.js?_={{ ts }}"></script>
|
248
|
+
{%- if js %}
|
249
|
+
<script src="{{ js }}_={{ ts }}"></script>
|
250
|
+
{%- endif %}
|
248
251
|
</body>
|
249
252
|
</html>
|
250
253
|
|
copyparty/web/ui.css.gz
CHANGED
Binary file
|
copyparty/web/up2k.js.gz
CHANGED
Binary file
|
copyparty/web/util.js.gz
CHANGED
Binary file
|