copyparty 1.9.12__py3-none-any.whl → 1.9.14__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 +13 -8
- copyparty/__version__.py +2 -2
- copyparty/authsrv.py +21 -13
- copyparty/cfg.py +29 -2
- copyparty/httpcli.py +31 -12
- copyparty/sutil.py +2 -2
- copyparty/svchub.py +28 -8
- copyparty/u2idx.py +5 -0
- copyparty/up2k.py +24 -17
- copyparty/util.py +50 -2
- copyparty/web/a/partyfuse.py +3 -2
- copyparty/web/browser.css.gz +0 -0
- copyparty/web/browser.js.gz +0 -0
- copyparty/web/up2k.js.gz +0 -0
- {copyparty-1.9.12.dist-info → copyparty-1.9.14.dist-info}/METADATA +33 -18
- {copyparty-1.9.12.dist-info → copyparty-1.9.14.dist-info}/RECORD +20 -20
- {copyparty-1.9.12.dist-info → copyparty-1.9.14.dist-info}/LICENSE +0 -0
- {copyparty-1.9.12.dist-info → copyparty-1.9.14.dist-info}/WHEEL +0 -0
- {copyparty-1.9.12.dist-info → copyparty-1.9.14.dist-info}/entry_points.txt +0 -0
- {copyparty-1.9.12.dist-info → copyparty-1.9.14.dist-info}/top_level.txt +0 -0
copyparty/__main__.py
CHANGED
@@ -27,6 +27,8 @@ from .authsrv import expand_config_file, re_vol, split_cfg_ln, upgrade_cfg_fmt
|
|
27
27
|
from .cfg import flagcats, onedash
|
28
28
|
from .svchub import SvcHub
|
29
29
|
from .util import (
|
30
|
+
DEF_MTE,
|
31
|
+
DEF_MTH,
|
30
32
|
IMPLICATIONS,
|
31
33
|
JINJA_VER,
|
32
34
|
PYFTPD_VER,
|
@@ -178,7 +180,10 @@ def init_E(E ) :
|
|
178
180
|
|
179
181
|
with open_binary("copyparty", "z.tar") as tgz:
|
180
182
|
with tarfile.open(fileobj=tgz) as tf:
|
181
|
-
|
183
|
+
try:
|
184
|
+
tf.extractall(tdn, filter="tar")
|
185
|
+
except TypeError:
|
186
|
+
tf.extractall(tdn) # nosec (archive is safe)
|
182
187
|
|
183
188
|
return tdn
|
184
189
|
|
@@ -800,6 +805,8 @@ def add_upload(ap):
|
|
800
805
|
ap2.add_argument("--no-dedup", action="store_true", help="disable symlink/hardlink creation; copy file contents instead (volflag=copydupes)")
|
801
806
|
ap2.add_argument("--no-dupe", action="store_true", help="reject duplicate files during upload; only matches within the same volume (volflag=nodupe)")
|
802
807
|
ap2.add_argument("--no-snap", action="store_true", help="disable snapshots -- forget unfinished uploads on shutdown; don't create .hist/up2k.snap files -- abandoned/interrupted uploads must be cleaned up manually")
|
808
|
+
ap2.add_argument("--snap-wri", metavar="SEC", type=int, default=300, help="write upload state to ./hist/up2k.snap every SEC seconds; allows resuming incomplete uploads after a server crash")
|
809
|
+
ap2.add_argument("--snap-drop", metavar="MIN", type=float, default=1440, help="forget unfinished uploads after MIN minutes; impossible to resume them after that (360=6h, 1440=24h)")
|
803
810
|
ap2.add_argument("--u2ts", metavar="TXT", type=u, default="c", help="how to timestamp uploaded files; [\033[32mc\033[0m]=client-last-modified, [\033[32mu\033[0m]=upload-time, [\033[32mfc\033[0m]=force-c, [\033[32mfu\033[0m]=force-u (volflag=u2ts)")
|
804
811
|
ap2.add_argument("--rand", action="store_true", help="force randomized filenames, --nrand chars long (volflag=rand)")
|
805
812
|
ap2.add_argument("--nrand", metavar="NUM", type=int, default=9, help="randomized filenames length (volflag=nrand)")
|
@@ -990,7 +997,7 @@ def add_optouts(ap):
|
|
990
997
|
def add_safety(ap):
|
991
998
|
ap2 = ap.add_argument_group('safety options')
|
992
999
|
ap2.add_argument("-s", action="count", default=0, help="increase safety: Disable thumbnails / potentially dangerous software (ffmpeg/pillow/vips), hide partial uploads, avoid crawlers.\n └─Alias of\033[32m --dotpart --no-thumb --no-mtag-ff --no-robots --force-js")
|
993
|
-
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403
|
1000
|
+
ap2.add_argument("-ss", action="store_true", help="further increase safety: Prevent js-injection, accidental move/delete, broken symlinks, webdav, 404 on 403, ban on excessive 404s.\n └─Alias of\033[32m -s --unpost=0 --no-del --no-mv --hardlink --vague-403 -nih")
|
994
1001
|
ap2.add_argument("-sss", action="store_true", help="further increase safety: Enable logging to disk, scan for dangerous symlinks.\n └─Alias of\033[32m -ss --no-dav --no-logues --no-readme -lo=cpp-%%Y-%%m%%d-%%H%%M%%S.txt.xz --ls=**,*,ln,p,r")
|
995
1002
|
ap2.add_argument("--ls", metavar="U[,V[,F]]", type=u, help="do a sanity/safety check of all volumes on startup; arguments \033[33mUSER\033[0m,\033[33mVOL\033[0m,\033[33mFLAGS\033[0m; example [\033[32m**,*,ln,p,r\033[0m]")
|
996
1003
|
ap2.add_argument("--xvol", action="store_true", help="never follow symlinks leaving the volume root, unless the link is into another volume where the user has similar access (volflag=xvol)")
|
@@ -1004,10 +1011,10 @@ def add_safety(ap):
|
|
1004
1011
|
ap2.add_argument("--no-robots", action="store_true", help="adds http and html headers asking search engines to not index anything (volflag=norobots)")
|
1005
1012
|
ap2.add_argument("--logout", metavar="H", type=float, default="8086", help="logout clients after H hours of inactivity; [\033[32m0.0028\033[0m]=10sec, [\033[32m0.1\033[0m]=6min, [\033[32m24\033[0m]=day, [\033[32m168\033[0m]=week, [\033[32m720\033[0m]=month, [\033[32m8760\033[0m]=year)")
|
1006
1013
|
ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
1007
|
-
ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="
|
1014
|
+
ap2.add_argument("--ban-404", metavar="N,W,B", type=u, default="50,60,1440", help="hitting more than \033[33mN\033[0m 404's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; only affects users who cannot see directory listings because their access is either g/G/h")
|
1008
1015
|
ap2.add_argument("--ban-403", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 403's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; [\033[32m1440\033[0m]=day, [\033[32m10080\033[0m]=week, [\033[32m43200\033[0m]=month")
|
1009
1016
|
ap2.add_argument("--ban-422", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m 422's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (422 is server fuzzing, invalid POSTs and so)")
|
1010
|
-
ap2.add_argument("--ban-url", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m sus URL's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes (decent replacement for --ban-404 if that can't be used)")
|
1017
|
+
ap2.add_argument("--ban-url", metavar="N,W,B", type=u, default="9,2,1440", help="hitting more than \033[33mN\033[0m sus URL's in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; applies only to access g/G/h (decent replacement for --ban-404 if that can't be used)")
|
1011
1018
|
ap2.add_argument("--sus-urls", metavar="R", type=u, default=r"\.php$|(^|/)wp-(admin|content|includes)/", help="URLs which are considered sus / eligible for banning; disable with blank or [\033[32mno\033[0m]")
|
1012
1019
|
ap2.add_argument("--nonsus-urls", metavar="R", type=u, default=r"^(favicon\.ico|robots\.txt)$|^apple-touch-icon|^\.well-known", help="harmless URLs ignored from 404-bans; disable with blank or [\033[32mno\033[0m]")
|
1013
1020
|
ap2.add_argument("--aclose", metavar="MIN", type=int, default=10, help="if a client maxes out the server connection limit, downgrade it from connection:keep-alive to connection:close for MIN minutes (and also kill its active connections) -- disable with 0")
|
@@ -1126,10 +1133,8 @@ def add_db_metadata(ap):
|
|
1126
1133
|
ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such")
|
1127
1134
|
ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/ffprobe parsers")
|
1128
1135
|
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping")
|
1129
|
-
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.)",
|
1130
|
-
|
1131
|
-
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.)",
|
1132
|
-
default=".vq,.aq,vc,ac,fmt,res,.fps")
|
1136
|
+
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar", default=DEF_MTE)
|
1137
|
+
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.); assign/add/remove same as -mte", default=DEF_MTH)
|
1133
1138
|
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag M using program BIN to parse the file")
|
1134
1139
|
|
1135
1140
|
|
copyparty/__version__.py
CHANGED
copyparty/authsrv.py
CHANGED
@@ -21,11 +21,14 @@ from .util import (
|
|
21
21
|
META_NOBOTS,
|
22
22
|
SQLITE_VER,
|
23
23
|
UNPLICATIONS,
|
24
|
+
ODict,
|
24
25
|
Pebkac,
|
26
|
+
UTC,
|
25
27
|
absreal,
|
26
28
|
afsenc,
|
27
29
|
get_df,
|
28
30
|
humansize,
|
31
|
+
odfusion,
|
29
32
|
relchk,
|
30
33
|
statdir,
|
31
34
|
uncyg,
|
@@ -206,7 +209,7 @@ class Lim(object):
|
|
206
209
|
if self.rot_re.search(path.replace("\\", "/")):
|
207
210
|
return path, ""
|
208
211
|
|
209
|
-
suf = datetime.
|
212
|
+
suf = datetime.now(UTC).strftime(self.rotf)
|
210
213
|
if path:
|
211
214
|
path += "/"
|
212
215
|
|
@@ -1419,12 +1422,12 @@ class AuthSrv(object):
|
|
1419
1422
|
|
1420
1423
|
for ga, vf in [["no_hash", "nohash"], ["no_idx", "noidx"]]:
|
1421
1424
|
if vf in vol.flags:
|
1422
|
-
ptn = vol.flags.pop(vf)
|
1425
|
+
ptn = re.compile(vol.flags.pop(vf))
|
1423
1426
|
else:
|
1424
1427
|
ptn = getattr(self.args, ga)
|
1425
1428
|
|
1426
1429
|
if ptn:
|
1427
|
-
vol.flags[vf] =
|
1430
|
+
vol.flags[vf] = ptn
|
1428
1431
|
|
1429
1432
|
for ga, vf in vf_bmap().items():
|
1430
1433
|
if getattr(self.args, ga):
|
@@ -1470,13 +1473,14 @@ class AuthSrv(object):
|
|
1470
1473
|
|
1471
1474
|
# default tag cfgs if unset
|
1472
1475
|
if "mte" not in vol.flags:
|
1473
|
-
vol.flags["mte"] = self.args.mte
|
1474
|
-
|
1475
|
-
vol.flags["mte"] =
|
1476
|
-
|
1477
|
-
)
|
1476
|
+
vol.flags["mte"] = self.args.mte.copy()
|
1477
|
+
else:
|
1478
|
+
vol.flags["mte"] = odfusion(self.args.mte, vol.flags["mte"])
|
1479
|
+
|
1478
1480
|
if "mth" not in vol.flags:
|
1479
|
-
vol.flags["mth"] = self.args.mth
|
1481
|
+
vol.flags["mth"] = self.args.mth.copy()
|
1482
|
+
else:
|
1483
|
+
vol.flags["mth"] = odfusion(self.args.mth, vol.flags["mth"])
|
1480
1484
|
|
1481
1485
|
# append additive args from argv to volflags
|
1482
1486
|
hooks = "xbu xau xiu xbr xar xbd xad xm xban".split()
|
@@ -1530,7 +1534,11 @@ class AuthSrv(object):
|
|
1530
1534
|
if vol.flags.get(grp, False):
|
1531
1535
|
continue
|
1532
1536
|
|
1533
|
-
vol.flags = {
|
1537
|
+
vol.flags = {
|
1538
|
+
k: v
|
1539
|
+
for k, v in vol.flags.items()
|
1540
|
+
if not k.startswith(rm) or k == "mte"
|
1541
|
+
}
|
1534
1542
|
|
1535
1543
|
for grp, rm in [["d2v", "e2v"]]:
|
1536
1544
|
if not vol.flags.get(grp, False):
|
@@ -1577,12 +1585,12 @@ class AuthSrv(object):
|
|
1577
1585
|
if local:
|
1578
1586
|
local_only_mtp[a] = True
|
1579
1587
|
|
1580
|
-
local_mte =
|
1581
|
-
for a in vol.flags.get("mte",
|
1588
|
+
local_mte = ODict()
|
1589
|
+
for a in vol.flags.get("mte", {}).keys():
|
1582
1590
|
local = True
|
1583
1591
|
all_mte[a] = True
|
1584
1592
|
local_mte[a] = True
|
1585
|
-
for b in self.args.mte.
|
1593
|
+
for b in self.args.mte.keys():
|
1586
1594
|
if not a or not b:
|
1587
1595
|
continue
|
1588
1596
|
|
copyparty/cfg.py
CHANGED
@@ -13,12 +13,20 @@ def vf_bmap() :
|
|
13
13
|
"no_dedup": "copydupes",
|
14
14
|
"no_dupe": "nodupe",
|
15
15
|
"no_forget": "noforget",
|
16
|
+
"no_robots": "norobots",
|
17
|
+
"no_thumb": "dthumb",
|
18
|
+
"no_vthumb": "dvthumb",
|
19
|
+
"no_athumb": "dathumb",
|
20
|
+
"re_maxage": "scan",
|
16
21
|
"th_no_crop": "nocrop",
|
17
22
|
"dav_auth": "davauth",
|
18
23
|
"dav_rt": "davrt",
|
19
24
|
}
|
20
25
|
for k in (
|
21
26
|
"dotsrch",
|
27
|
+
"e2d",
|
28
|
+
"e2ds",
|
29
|
+
"e2dsa",
|
22
30
|
"e2t",
|
23
31
|
"e2ts",
|
24
32
|
"e2tsr",
|
@@ -41,7 +49,12 @@ def vf_bmap() :
|
|
41
49
|
|
42
50
|
def vf_vmap() :
|
43
51
|
"""argv-to-volflag: simple values"""
|
44
|
-
ret = {
|
52
|
+
ret = {
|
53
|
+
"no_hash": "nohash",
|
54
|
+
"no_idx": "noidx",
|
55
|
+
"th_convt": "convt",
|
56
|
+
"th_size": "thsize",
|
57
|
+
}
|
45
58
|
for k in ("dbd", "lg_sbf", "md_sbf", "nrand", "sort", "unlist", "u2ts"):
|
46
59
|
ret[k] = k
|
47
60
|
return ret
|
@@ -50,7 +63,21 @@ def vf_vmap() :
|
|
50
63
|
def vf_cmap() :
|
51
64
|
"""argv-to-volflag: complex/lists"""
|
52
65
|
ret = {}
|
53
|
-
for k in (
|
66
|
+
for k in (
|
67
|
+
"html_head",
|
68
|
+
"mte",
|
69
|
+
"mth",
|
70
|
+
"mtp",
|
71
|
+
"xad",
|
72
|
+
"xar",
|
73
|
+
"xau",
|
74
|
+
"xban",
|
75
|
+
"xbd",
|
76
|
+
"xbr",
|
77
|
+
"xbu",
|
78
|
+
"xiu",
|
79
|
+
"xm",
|
80
|
+
):
|
54
81
|
ret[k] = k
|
55
82
|
return ret
|
56
83
|
|
copyparty/httpcli.py
CHANGED
@@ -40,7 +40,9 @@ from .util import (
|
|
40
40
|
HTTPCODE,
|
41
41
|
META_NOBOTS,
|
42
42
|
MultipartParser,
|
43
|
+
ODict,
|
43
44
|
Pebkac,
|
45
|
+
UTC,
|
44
46
|
UnrecvEOF,
|
45
47
|
absreal,
|
46
48
|
alltrace,
|
@@ -650,6 +652,7 @@ class HttpCli(object):
|
|
650
652
|
and not body.startswith(b"<pre>source file busy")
|
651
653
|
)
|
652
654
|
)
|
655
|
+
and (status != 404 or (self.can_get and not self.can_read))
|
653
656
|
):
|
654
657
|
if status == 404:
|
655
658
|
g = self.conn.hsrv.g404
|
@@ -1967,8 +1970,7 @@ class HttpCli(object):
|
|
1967
1970
|
self.log("q#: {} ({:.2f}s)".format(msg, idx.p_dur))
|
1968
1971
|
|
1969
1972
|
order = []
|
1970
|
-
|
1971
|
-
for t in cfg:
|
1973
|
+
for t in self.args.mte:
|
1972
1974
|
if t in taglist:
|
1973
1975
|
order.append(t)
|
1974
1976
|
for t in taglist:
|
@@ -3987,7 +3989,7 @@ class HttpCli(object):
|
|
3987
3989
|
margin = "-"
|
3988
3990
|
|
3989
3991
|
sz = inf.st_size
|
3990
|
-
zd = datetime.
|
3992
|
+
zd = datetime.fromtimestamp(linf.st_mtime, UTC)
|
3991
3993
|
dt = "%04d-%02d-%02d %02d:%02d:%02d" % (
|
3992
3994
|
zd.year,
|
3993
3995
|
zd.month,
|
@@ -4047,6 +4049,9 @@ class HttpCli(object):
|
|
4047
4049
|
ap = vn.canonical(rem)
|
4048
4050
|
return self.tx_file(ap) # is no-cache
|
4049
4051
|
|
4052
|
+
mte = vn.flags.get("mte", {})
|
4053
|
+
add_up_at = ".up_at" in mte
|
4054
|
+
is_admin = self.can_admin
|
4050
4055
|
tagset = set()
|
4051
4056
|
for fe in files:
|
4052
4057
|
fn = fe["name"]
|
@@ -4074,24 +4079,38 @@ class HttpCli(object):
|
|
4074
4079
|
self.log(t.format(rd, fn, min_ex()))
|
4075
4080
|
break
|
4076
4081
|
|
4077
|
-
|
4082
|
+
tags = {k: v for k, v in r}
|
4078
4083
|
|
4079
|
-
if
|
4084
|
+
if is_admin:
|
4080
4085
|
q = "select ip, at from up where rd=? and fn=?"
|
4081
4086
|
try:
|
4082
4087
|
zs1, zs2 = icur.execute(q, erd_efn).fetchone()
|
4083
|
-
|
4084
|
-
|
4088
|
+
if zs1:
|
4089
|
+
tags["up_ip"] = zs1
|
4090
|
+
if zs2:
|
4091
|
+
tags[".up_at"] = zs2
|
4092
|
+
except:
|
4093
|
+
pass
|
4094
|
+
elif add_up_at:
|
4095
|
+
q = "select at from up where rd=? and fn=?"
|
4096
|
+
try:
|
4097
|
+
(zs1,) = icur.execute(q, erd_efn).fetchone()
|
4098
|
+
if zs1:
|
4099
|
+
tags[".up_at"] = zs1
|
4085
4100
|
except:
|
4086
4101
|
pass
|
4087
4102
|
|
4088
|
-
_ = [tagset.add(k) for k in
|
4103
|
+
_ = [tagset.add(k) for k in tags]
|
4104
|
+
fe["tags"] = tags
|
4089
4105
|
|
4090
4106
|
if icur:
|
4091
|
-
|
4092
|
-
|
4107
|
+
lmte = list(mte)
|
4108
|
+
if self.can_admin:
|
4109
|
+
lmte += ["up_ip", ".up_at"]
|
4110
|
+
|
4111
|
+
taglist = [k for k in lmte if k in tagset]
|
4093
4112
|
for fe in dirs:
|
4094
|
-
fe["tags"] =
|
4113
|
+
fe["tags"] = ODict()
|
4095
4114
|
else:
|
4096
4115
|
taglist = list(tagset)
|
4097
4116
|
|
@@ -4138,7 +4157,7 @@ class HttpCli(object):
|
|
4138
4157
|
j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
|
4139
4158
|
|
4140
4159
|
if "mth" in vn.flags:
|
4141
|
-
j2a["def_hcols"] = vn.flags["mth"]
|
4160
|
+
j2a["def_hcols"] = list(vn.flags["mth"])
|
4142
4161
|
|
4143
4162
|
html = self.j2s(tpl, **j2a)
|
4144
4163
|
self.reply(html.encode("utf-8", "replace"))
|
copyparty/sutil.py
CHANGED
@@ -8,7 +8,7 @@ from datetime import datetime
|
|
8
8
|
from .__init__ import CORES
|
9
9
|
from .bos import bos
|
10
10
|
from .th_cli import ThumbCli
|
11
|
-
from .util import vjoin
|
11
|
+
from .util import UTC, vjoin
|
12
12
|
|
13
13
|
class StreamArc(object):
|
14
14
|
def __init__(
|
@@ -102,7 +102,7 @@ def errdesc(errors ) :
|
|
102
102
|
tf_path = tf.name
|
103
103
|
tf.write("\r\n".join(report).encode("utf-8", "replace"))
|
104
104
|
|
105
|
-
dt = datetime.
|
105
|
+
dt = datetime.now(UTC).strftime("%Y-%m%d-%H%M%S")
|
106
106
|
|
107
107
|
bos.chmod(tf_path, 0o444)
|
108
108
|
return {
|
copyparty/svchub.py
CHANGED
@@ -33,13 +33,18 @@ from .util import (
|
|
33
33
|
FFMPEG_URL,
|
34
34
|
VERSIONS,
|
35
35
|
Daemon,
|
36
|
+
DEF_MTE,
|
37
|
+
DEF_MTH,
|
36
38
|
Garda,
|
37
39
|
HLog,
|
38
40
|
HMaccas,
|
41
|
+
ODict,
|
42
|
+
UTC,
|
39
43
|
alltrace,
|
40
44
|
ansi_re,
|
41
45
|
min_ex,
|
42
46
|
mp,
|
47
|
+
odfusion,
|
43
48
|
pybin,
|
44
49
|
start_log_thrs,
|
45
50
|
start_stackmon,
|
@@ -109,8 +114,6 @@ class SvcHub(object):
|
|
109
114
|
args.no_mv = True
|
110
115
|
args.hardlink = True
|
111
116
|
args.vague_403 = True
|
112
|
-
args.ban_404 = "50,60,1440"
|
113
|
-
args.turbo = -1
|
114
117
|
args.nih = True
|
115
118
|
|
116
119
|
if args.s:
|
@@ -427,6 +430,17 @@ class SvcHub(object):
|
|
427
430
|
zs = al.xff_src.replace(" ", "").replace(".", "\\.").replace(",", "|")
|
428
431
|
al.xff_re = re.compile("^(?:" + zs + ")")
|
429
432
|
|
433
|
+
mte = ODict.fromkeys(DEF_MTE.split(","), True)
|
434
|
+
al.mte = odfusion(mte, al.mte)
|
435
|
+
|
436
|
+
mth = ODict.fromkeys(DEF_MTH.split(","), True)
|
437
|
+
al.mth = odfusion(mth, al.mth)
|
438
|
+
|
439
|
+
for k in ["no_hash", "no_idx"]:
|
440
|
+
ptn = getattr(self.args, k)
|
441
|
+
if ptn:
|
442
|
+
setattr(self.args, k, re.compile(ptn))
|
443
|
+
|
430
444
|
return True
|
431
445
|
|
432
446
|
def _setlimits(self) :
|
@@ -470,7 +484,7 @@ class SvcHub(object):
|
|
470
484
|
self.args.nc = min(self.args.nc, soft // 2)
|
471
485
|
|
472
486
|
def _logname(self) :
|
473
|
-
dt = datetime.
|
487
|
+
dt = datetime.now(UTC)
|
474
488
|
fn = str(self.args.lo)
|
475
489
|
for fs in "YmdHMS":
|
476
490
|
fs = "%" + fs
|
@@ -719,7 +733,7 @@ class SvcHub(object):
|
|
719
733
|
return
|
720
734
|
|
721
735
|
with self.log_mutex:
|
722
|
-
zd = datetime.
|
736
|
+
zd = datetime.now(UTC)
|
723
737
|
ts = self.log_dfmt % (
|
724
738
|
zd.year,
|
725
739
|
zd.month * 100 + zd.day,
|
@@ -737,7 +751,7 @@ class SvcHub(object):
|
|
737
751
|
self.logf.close()
|
738
752
|
self._setup_logfile("")
|
739
753
|
|
740
|
-
dt = datetime.
|
754
|
+
dt = datetime.now(UTC)
|
741
755
|
|
742
756
|
# unix timestamp of next 00:00:00 (leap-seconds safe)
|
743
757
|
day_now = dt.day
|
@@ -745,14 +759,20 @@ class SvcHub(object):
|
|
745
759
|
dt += timedelta(hours=12)
|
746
760
|
|
747
761
|
dt = dt.replace(hour=0, minute=0, second=0)
|
748
|
-
|
762
|
+
try:
|
763
|
+
tt = dt.utctimetuple()
|
764
|
+
except:
|
765
|
+
# still makes me hella uncomfortable
|
766
|
+
tt = dt.timetuple()
|
767
|
+
|
768
|
+
self.next_day = calendar.timegm(tt)
|
749
769
|
|
750
770
|
def _log_enabled(self, src , msg , c = 0) :
|
751
771
|
"""handles logging from all components"""
|
752
772
|
with self.log_mutex:
|
753
773
|
now = time.time()
|
754
774
|
if now >= self.next_day:
|
755
|
-
dt = datetime.
|
775
|
+
dt = datetime.fromtimestamp(now, UTC)
|
756
776
|
zs = "{}\n" if self.no_ansi else "\033[36m{}\033[0m\n"
|
757
777
|
zs = zs.format(dt.strftime("%Y-%m-%d"))
|
758
778
|
print(zs, end="")
|
@@ -775,7 +795,7 @@ class SvcHub(object):
|
|
775
795
|
else:
|
776
796
|
msg = "%s%s\033[0m" % (c, msg)
|
777
797
|
|
778
|
-
zd = datetime.
|
798
|
+
zd = datetime.fromtimestamp(now, UTC)
|
779
799
|
ts = self.log_efmt % (
|
780
800
|
zd.hour,
|
781
801
|
zd.minute,
|
copyparty/u2idx.py
CHANGED
copyparty/up2k.py
CHANGED
@@ -24,7 +24,7 @@ from queue import Queue
|
|
24
24
|
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, WINDOWS
|
25
25
|
from .authsrv import LEELOO_DALLAS, SSEELOG, VFS, AuthSrv
|
26
26
|
from .bos import bos
|
27
|
-
from .cfg import vf_bmap, vf_vmap
|
27
|
+
from .cfg import vf_bmap, vf_cmap, vf_vmap
|
28
28
|
from .fsutil import Fstab
|
29
29
|
from .mtag import MParser, MTag
|
30
30
|
from .util import (
|
@@ -131,8 +131,6 @@ class Up2k(object):
|
|
131
131
|
self.vol_act = {}
|
132
132
|
self.busy_aps = set()
|
133
133
|
self.dupesched = {}
|
134
|
-
self.snap_persist_interval = 300 # persist unfinished index every 5 min
|
135
|
-
self.snap_discard_interval = 21600 # drop unfinished after 6 hours inactivity
|
136
134
|
self.snap_prev = {}
|
137
135
|
|
138
136
|
self.mtag = None
|
@@ -639,10 +637,7 @@ class Up2k(object):
|
|
639
637
|
if self.stop:
|
640
638
|
break
|
641
639
|
|
642
|
-
en
|
643
|
-
if "mte" in vol.flags:
|
644
|
-
en = set(vol.flags["mte"].split(","))
|
645
|
-
|
640
|
+
en = set(vol.flags.get("mte", {}))
|
646
641
|
self.entags[vol.realpath] = en
|
647
642
|
|
648
643
|
if "e2d" in vol.flags:
|
@@ -798,13 +793,25 @@ class Up2k(object):
|
|
798
793
|
fv = "\033[0;36m{}:\033[90m{}"
|
799
794
|
fx = set(("html_head",))
|
800
795
|
fd = vf_bmap()
|
796
|
+
fd.update(vf_cmap())
|
801
797
|
fd.update(vf_vmap())
|
802
798
|
fd = {v: k for k, v in fd.items()}
|
803
799
|
fl = {
|
804
800
|
k: v
|
805
801
|
for k, v in flags.items()
|
806
|
-
if k not in fd
|
802
|
+
if k not in fd
|
803
|
+
or (
|
804
|
+
v != getattr(self.args, fd[k])
|
805
|
+
and str(v) != str(getattr(self.args, fd[k]))
|
806
|
+
)
|
807
807
|
}
|
808
|
+
for k1, k2 in vf_cmap().items():
|
809
|
+
if k1 not in fl or k1 in fx:
|
810
|
+
continue
|
811
|
+
if str(fl[k1]) == str(getattr(self.args, k2)):
|
812
|
+
del fl[k1]
|
813
|
+
else:
|
814
|
+
fl[k1] = ",".join(x for x in fl)
|
808
815
|
a = [
|
809
816
|
(ft if v is True else ff if v is False else fv).format(k, str(v))
|
810
817
|
for k, v in fl.items()
|
@@ -823,7 +830,7 @@ class Up2k(object):
|
|
823
830
|
vpath += "/"
|
824
831
|
|
825
832
|
zs = " ".join(sorted(a))
|
826
|
-
zs = zs.replace("
|
833
|
+
zs = zs.replace("90mre.compile(", "90m(") # nohash
|
827
834
|
self.log("/{} {}".format(vpath, zs), "35")
|
828
835
|
|
829
836
|
reg = {}
|
@@ -2132,7 +2139,7 @@ class Up2k(object):
|
|
2132
2139
|
|
2133
2140
|
try:
|
2134
2141
|
nfiles = next(cur.execute("select count(w) from up"))[0]
|
2135
|
-
self.log("
|
2142
|
+
self.log(" {} |{}|".format(db_path, nfiles), "90")
|
2136
2143
|
return cur
|
2137
2144
|
except:
|
2138
2145
|
self.log("WARN: could not list files; DB corrupt?\n" + min_ex())
|
@@ -3745,13 +3752,16 @@ class Up2k(object):
|
|
3745
3752
|
self._finish_upload(job["ptop"], job["wark"])
|
3746
3753
|
|
3747
3754
|
def _snapshot(self) :
|
3748
|
-
slp = self.
|
3755
|
+
slp = self.args.snap_wri
|
3756
|
+
if not slp or self.args.no_snap:
|
3757
|
+
return
|
3758
|
+
|
3749
3759
|
while True:
|
3750
3760
|
time.sleep(slp)
|
3751
3761
|
if self.pp:
|
3752
3762
|
slp = 5
|
3753
3763
|
else:
|
3754
|
-
slp = self.
|
3764
|
+
slp = self.args.snap_wri
|
3755
3765
|
self.do_snapshot()
|
3756
3766
|
|
3757
3767
|
def do_snapshot(self) :
|
@@ -3765,11 +3775,8 @@ class Up2k(object):
|
|
3765
3775
|
if not histpath:
|
3766
3776
|
return
|
3767
3777
|
|
3768
|
-
|
3769
|
-
|
3770
|
-
for x in reg.values()
|
3771
|
-
if x["need"] and now - x["poke"] > self.snap_discard_interval
|
3772
|
-
]
|
3778
|
+
idrop = self.args.snap_drop * 60
|
3779
|
+
rm = [x for x in reg.values() if x["need"] and now - x["poke"] >= idrop]
|
3773
3780
|
|
3774
3781
|
if self.args.nw:
|
3775
3782
|
lost = []
|
copyparty/util.py
CHANGED
@@ -25,7 +25,6 @@ import threading
|
|
25
25
|
import time
|
26
26
|
import traceback
|
27
27
|
from collections import Counter
|
28
|
-
from datetime import datetime
|
29
28
|
from email.utils import formatdate
|
30
29
|
|
31
30
|
from ipaddress import IPv4Address, IPv4Network, IPv6Address, IPv6Network
|
@@ -35,6 +34,35 @@ from .__init__ import ANYWIN, EXE, MACOS, PY2, TYPE_CHECKING, VT100, WINDOWS
|
|
35
34
|
from .__version__ import S_BUILD_DT, S_VERSION
|
36
35
|
from .stolen import surrogateescape
|
37
36
|
|
37
|
+
try:
|
38
|
+
from datetime import datetime, timezone
|
39
|
+
|
40
|
+
UTC = timezone.utc
|
41
|
+
except:
|
42
|
+
from datetime import datetime, timedelta, tzinfo
|
43
|
+
|
44
|
+
TD_ZERO = timedelta(0)
|
45
|
+
|
46
|
+
class _UTC(tzinfo):
|
47
|
+
def utcoffset(self, dt):
|
48
|
+
return TD_ZERO
|
49
|
+
|
50
|
+
def tzname(self, dt):
|
51
|
+
return "UTC"
|
52
|
+
|
53
|
+
def dst(self, dt):
|
54
|
+
return TD_ZERO
|
55
|
+
|
56
|
+
UTC = _UTC()
|
57
|
+
|
58
|
+
|
59
|
+
if sys.version_info >= (3, 7) or (
|
60
|
+
sys.version_info >= (3, 6) and platform.python_implementation() == "CPython"
|
61
|
+
):
|
62
|
+
ODict = dict
|
63
|
+
else:
|
64
|
+
from collections import OrderedDict as ODict
|
65
|
+
|
38
66
|
|
39
67
|
def _ens(want ) :
|
40
68
|
ret = []
|
@@ -245,6 +273,11 @@ EXTS["vnd.mozilla.apng"] = "png"
|
|
245
273
|
MAGIC_MAP = {"jpeg": "jpg"}
|
246
274
|
|
247
275
|
|
276
|
+
DEF_MTE = "circle,album,.tn,artist,title,.bpm,key,.dur,.q,.vq,.aq,vc,ac,fmt,res,.fps,ahash,vhash"
|
277
|
+
|
278
|
+
DEF_MTH = ".vq,.aq,vc,ac,fmt,res,.fps"
|
279
|
+
|
280
|
+
|
248
281
|
REKOBO_KEY = {
|
249
282
|
v: ln.split(" ", 1)[0]
|
250
283
|
for ln in """
|
@@ -1102,7 +1135,7 @@ def stackmon(fp , ival , suffix ) :
|
|
1102
1135
|
buf = lzma.compress(buf, preset=0)
|
1103
1136
|
|
1104
1137
|
if "%" in fp:
|
1105
|
-
dt = datetime.
|
1138
|
+
dt = datetime.now(UTC)
|
1106
1139
|
for fs in "YmdHMS":
|
1107
1140
|
fs = "%" + fs
|
1108
1141
|
if fs in fp:
|
@@ -1758,6 +1791,21 @@ def exclude_dotfiles(filepaths ) :
|
|
1758
1791
|
return [x for x in filepaths if not x.split("/")[-1].startswith(".")]
|
1759
1792
|
|
1760
1793
|
|
1794
|
+
def odfusion(base , oth ) :
|
1795
|
+
# merge an "ordered set" (just a dict really) with another list of keys
|
1796
|
+
ret = base.copy()
|
1797
|
+
if oth.startswith("+"):
|
1798
|
+
for k in oth[1:].split(","):
|
1799
|
+
ret[k] = True
|
1800
|
+
elif oth[:1] in ("-", "/"):
|
1801
|
+
for k in oth[1:].split(","):
|
1802
|
+
ret.pop(k, None)
|
1803
|
+
else:
|
1804
|
+
ret = ODict.fromkeys(oth.split(","), True)
|
1805
|
+
|
1806
|
+
return ret
|
1807
|
+
|
1808
|
+
|
1761
1809
|
def ipnorm(ip ) :
|
1762
1810
|
if ":" in ip:
|
1763
1811
|
# assume /64 clients; drop 4 groups
|
copyparty/web/a/partyfuse.py
CHANGED
@@ -46,12 +46,13 @@ import traceback
|
|
46
46
|
import http.client # py2: httplib
|
47
47
|
import urllib.parse
|
48
48
|
import calendar
|
49
|
-
from datetime import datetime
|
49
|
+
from datetime import datetime, timezone
|
50
50
|
from urllib.parse import quote_from_bytes as quote
|
51
51
|
from urllib.parse import unquote_to_bytes as unquote
|
52
52
|
|
53
53
|
WINDOWS = sys.platform == "win32"
|
54
54
|
MACOS = platform.system() == "Darwin"
|
55
|
+
UTC = timezone.utc
|
55
56
|
info = log = dbg = None
|
56
57
|
|
57
58
|
|
@@ -176,7 +177,7 @@ class RecentLog(object):
|
|
176
177
|
def put(self, msg):
|
177
178
|
msg = "{:10.6f} {} {}\n".format(time.time() % 900, rice_tid(), msg)
|
178
179
|
if self.f:
|
179
|
-
fmsg = " ".join([datetime.
|
180
|
+
fmsg = " ".join([datetime.now(UTC).strftime("%H%M%S.%f"), str(msg)])
|
180
181
|
self.f.write(fmsg.encode("utf-8"))
|
181
182
|
|
182
183
|
with self.mtx:
|
copyparty/web/browser.css.gz
CHANGED
Binary file
|
copyparty/web/browser.js.gz
CHANGED
Binary file
|
copyparty/web/up2k.js.gz
CHANGED
Binary file
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: copyparty
|
3
|
-
Version: 1.9.
|
3
|
+
Version: 1.9.14
|
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
|
@@ -71,9 +71,8 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
71
71
|
* [testimonials](#testimonials) - small collection of user feedback
|
72
72
|
* [motivations](#motivations) - project goals / philosophy
|
73
73
|
* [notes](#notes) - general notes
|
74
|
-
* [bugs](#bugs)
|
75
|
-
* [
|
76
|
-
* [not my bugs](#not-my-bugs)
|
74
|
+
* [bugs](#bugs) - roughly sorted by chance of encounter
|
75
|
+
* [not my bugs](#not-my-bugs) - same order here too
|
77
76
|
* [breaking changes](#breaking-changes) - upgrade notes
|
78
77
|
* [FAQ](#FAQ) - "frequently" asked questions
|
79
78
|
* [accounts and volumes](#accounts-and-volumes) - per-folder, per-user permissions
|
@@ -91,7 +90,7 @@ turn almost any device into a file server with resumable uploads/downloads using
|
|
91
90
|
* [file manager](#file-manager) - cut/paste, rename, and delete files/folders (if you have permission)
|
92
91
|
* [batch rename](#batch-rename) - select some files and press `F2` to bring up the rename UI
|
93
92
|
* [media player](#media-player) - plays almost every audio format there is
|
94
|
-
* [audio equalizer](#audio-equalizer) -
|
93
|
+
* [audio equalizer](#audio-equalizer) - and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
95
94
|
* [fix unreliable playback on android](#fix-unreliable-playback-on-android) - due to phone / app settings
|
96
95
|
* [markdown viewer](#markdown-viewer) - and there are *two* editors
|
97
96
|
* [other tricks](#other-tricks)
|
@@ -314,20 +313,28 @@ server notes:
|
|
314
313
|
|
315
314
|
# bugs
|
316
315
|
|
317
|
-
|
318
|
-
* Windows: python 2.7 cannot handle filenames with mojibake
|
319
|
-
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
320
|
-
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
316
|
+
roughly sorted by chance of encounter
|
321
317
|
|
322
|
-
|
318
|
+
* general:
|
319
|
+
* `--th-ff-jpg` may fix video thumbnails on some FFmpeg versions (macos, some linux)
|
320
|
+
* `--th-ff-swr` may fix audio thumbnails on some FFmpeg versions
|
321
|
+
* if the `up2k.db` (filesystem index) is on a samba-share or network disk, you'll get unpredictable behavior if the share is disconnected for a bit
|
322
|
+
* use `--hist` or the `hist` volflag (`-v [...]:c,hist=/tmp/foo`) to place the db on a local disk instead
|
323
|
+
* all volumes must exist / be available on startup; up2k (mtp especially) gets funky otherwise
|
324
|
+
* probably more, pls let me know
|
323
325
|
|
324
|
-
*
|
325
|
-
*
|
326
|
-
*
|
327
|
-
|
326
|
+
* python 3.4 and older (including 2.7):
|
327
|
+
* many rare and exciting edge-cases because [python didn't handle EINTR yet](https://peps.python.org/pep-0475/)
|
328
|
+
* downloads from copyparty may suddenly fail, but uploads *should* be fine
|
329
|
+
|
330
|
+
* python 2.7 on Windows:
|
331
|
+
* cannot index non-ascii filenames with `-e2d`
|
332
|
+
* cannot handle filenames with mojibake
|
328
333
|
|
329
334
|
## not my bugs
|
330
335
|
|
336
|
+
same order here too
|
337
|
+
|
331
338
|
* [Chrome issue 1317069](https://bugs.chromium.org/p/chromium/issues/detail?id=1317069) -- if you try to upload a folder which contains symlinks by dragging it into the browser, the symlinked files will not get uploaded
|
332
339
|
|
333
340
|
* [Chrome issue 1352210](https://bugs.chromium.org/p/chromium/issues/detail?id=1352210) -- plaintext http may be faster at filehashing than https (but also extremely CPU-intensive)
|
@@ -410,7 +417,7 @@ permissions:
|
|
410
417
|
* `g` (get): only download files, cannot see folder contents or zip/tar
|
411
418
|
* `G` (upget): same as `g` except uploaders get to see their own [filekeys](#filekeys) (see `fk` in examples below)
|
412
419
|
* `h` (html): same as `g` except folders return their index.html, and filekeys are not necessary for index.html
|
413
|
-
* `a` (admin): can see uploader IPs, config-reload
|
420
|
+
* `a` (admin): can see upload time, uploader IPs, config-reload
|
414
421
|
|
415
422
|
examples:
|
416
423
|
* add accounts named u1, u2, u3 with passwords p1, p2, p3: `-a u1:p1 -a u2:p2 -a u3:p3`
|
@@ -787,7 +794,7 @@ open the `[🎺]` media-player-settings tab to configure it,
|
|
787
794
|
|
788
795
|
### audio equalizer
|
789
796
|
|
790
|
-
|
797
|
+
and [dynamic range compressor](https://en.wikipedia.org/wiki/Dynamic_range_compression)
|
791
798
|
|
792
799
|
can also boost the volume in general, or increase/decrease stereo width (like [crossfeed](https://www.foobar2000.org/components/view/foo_dsp_meiercf) just worse)
|
793
800
|
|
@@ -998,6 +1005,15 @@ authenticate with one of the following:
|
|
998
1005
|
* username `$password`, password `k`
|
999
1006
|
|
1000
1007
|
|
1008
|
+
## browser ux
|
1009
|
+
|
1010
|
+
tweaking the ui
|
1011
|
+
|
1012
|
+
* set default sort order globally with `--sort` or per-volume with the `sort` volflag; specify one or more comma-separated columns to sort by, and prefix the column name with `-` for reverse sort
|
1013
|
+
* column names are visible as tooltips when hovering over the column headers in the directory listing, for example `href ext sz ts tags/.up_at tags/Cirle tags/.tn tags/Artist tags/Title`
|
1014
|
+
* to sort by upload date, first enable showing the upload date in the listing with `-e2d -mte +.up_at` and then `--sort tags/.up_at`
|
1015
|
+
|
1016
|
+
|
1001
1017
|
## file indexing
|
1002
1018
|
|
1003
1019
|
enables dedup and music search ++
|
@@ -1024,6 +1040,7 @@ the same arguments can be set as volflags, in addition to `d2d`, `d2ds`, `d2t`,
|
|
1024
1040
|
* `-v ~/music::r:c,d2ts` same except only affecting tags
|
1025
1041
|
|
1026
1042
|
note:
|
1043
|
+
* 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)
|
1027
1044
|
* `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
|
1028
1045
|
* the rescan button in the admin panel has no effect unless the volume has `-e2ds` or higher
|
1029
1046
|
* deduplication is possible on windows if you run copyparty as administrator (not saying you should!)
|
@@ -1687,8 +1704,6 @@ safety profiles:
|
|
1687
1704
|
* `--hardlink` creates hardlinks instead of symlinks when deduplicating uploads, which is less maintenance
|
1688
1705
|
* however note if you edit one file it will also affect the other copies
|
1689
1706
|
* `--vague-403` returns a "404 not found" instead of "401 unauthorized" which is a common enterprise meme
|
1690
|
-
* `--ban-404=50,60,1440` ban client for 1440min (24h) if they hit 50 404's in 60min
|
1691
|
-
* `--turbo=-1` to force-disable turbo-mode in the uploader which could otherwise hit the 404-ban
|
1692
1707
|
* `--nih` removes the server hostname from directory listings
|
1693
1708
|
|
1694
1709
|
* option `-sss` is a shortcut for the above plus:
|
@@ -1,17 +1,17 @@
|
|
1
1
|
copyparty/__init__.py,sha256=JA6xnECt2WITjgMEUsk7ZKYgxieda4QvXQtgxfnfkR4,1812
|
2
|
-
copyparty/__main__.py,sha256=
|
3
|
-
copyparty/__version__.py,sha256=
|
4
|
-
copyparty/authsrv.py,sha256=
|
2
|
+
copyparty/__main__.py,sha256=CeB5mT4r4lw8RX23nPI-MOMnJZlM2nOUVTDI__OMRZk,82974
|
3
|
+
copyparty/__version__.py,sha256=c1QkkzhyGQtqboArLfXkMPfdc-IatiVz-9MgujN-y7c,255
|
4
|
+
copyparty/authsrv.py,sha256=uUQwTB9v-0HbiT68VR2_gX1s22YmBpPzjfIQoqup90E,71301
|
5
5
|
copyparty/broker_mp.py,sha256=OwxJk6mil0aPopz_JbONsk-b4Qmoa_sdS5G-tIIXjoM,3916
|
6
6
|
copyparty/broker_mpw.py,sha256=GlSn4PRd_OqqeG39FiXgNvPzXVQW6UCiAcqmBSr2q6g,3200
|
7
7
|
copyparty/broker_thr.py,sha256=eKr--HJGig5zqvNGwH9UoBG9Nvi9mT2axrRmJwknd0s,1759
|
8
8
|
copyparty/broker_util.py,sha256=CnX_LAhQQqouONcDLtVkVlcBX3Z6pWuKDQDmmbHGEg4,1489
|
9
9
|
copyparty/cert.py,sha256=r6zG-eLxwJW8AYz6ZTYzIlzuN6Wb62Ea4mZUrc_t6F0,7239
|
10
|
-
copyparty/cfg.py,sha256=
|
10
|
+
copyparty/cfg.py,sha256=uOG5GGNpDLwXW6VWDgfQMzBKUdWOfTPUJh9iBuLu_8c,8490
|
11
11
|
copyparty/dxml.py,sha256=lZpg-kn-kQsXRtNY1n6fRaS-b7uXzMCyv8ovKnhZcZc,1548
|
12
12
|
copyparty/fsutil.py,sha256=c4fTvmclKbVABNsjU4rGddsjCgRwi9YExAyo-06ATc8,3932
|
13
13
|
copyparty/ftpd.py,sha256=6o_HpezJ-afXLsOkKXyIMQYKVz_MqZSOoy5L4z4dEeU,15369
|
14
|
-
copyparty/httpcli.py,sha256=
|
14
|
+
copyparty/httpcli.py,sha256=bi501chz7ThECoGq5xaEjRPj5jPwf3jd19xkKBDKKcI,136717
|
15
15
|
copyparty/httpconn.py,sha256=CJU4wK_6QJFvgK9mQwEV55j6Muh_9k-GTe4AIehzJiw,6825
|
16
16
|
copyparty/httpsrv.py,sha256=B2wmyXfohtqxC0lZ3j9UACYS8f9Zxlh4QSRH8_1owkw,16044
|
17
17
|
copyparty/ico.py,sha256=8QXApIqAVC1WnpM_RVFUgqerP7Y71DbxxF-IpUeV-n0,4042
|
@@ -23,15 +23,15 @@ copyparty/pwhash.py,sha256=6RcQE35B-vo7evU4SS2YktEvT1h-r0FZRWP5cSNp98c,3859
|
|
23
23
|
copyparty/smbd.py,sha256=-ey_edugqUGCKZtsKC1TZnFdaeSw7M7RvphUIpL75V4,13997
|
24
24
|
copyparty/ssdp.py,sha256=H6ZftXttydcnBxcg2-Prm4P-XiybgT3xiJRUXU1pbrE,6343
|
25
25
|
copyparty/star.py,sha256=LUfDc6Oy3EC5IZHxAgVzqBPKEDb4n7U94HB6U0-GndQ,3771
|
26
|
-
copyparty/sutil.py,sha256=
|
27
|
-
copyparty/svchub.py,sha256=
|
26
|
+
copyparty/sutil.py,sha256=dZhDAzVAp02i6YmGqcedy4LaYVffnJCSp3F6WEwfz7c,2967
|
27
|
+
copyparty/svchub.py,sha256=JnafYOUphQ2s_fCfwVjVYFaEbd8MIveP7NSkZCHRjXg,26623
|
28
28
|
copyparty/szip.py,sha256=SJg5nzN_5oaIsIYXlRvcLHVTqngLAOPfe4_WVsuhSkw,8520
|
29
29
|
copyparty/tcpsrv.py,sha256=vz94zy-eUg5-U1lskN3VAQiTXVr80PPnwJfwzybVcW4,17169
|
30
30
|
copyparty/th_cli.py,sha256=MSp2kpoAPiX1bndMthv6JK2gt3K6CjrloWuJsI_CL94,3869
|
31
31
|
copyparty/th_srv.py,sha256=68MCzYVTm62Yct25Fs2udiLEB7tW7t8bLc3zext9IPs,23226
|
32
|
-
copyparty/u2idx.py,sha256=
|
33
|
-
copyparty/up2k.py,sha256=
|
34
|
-
copyparty/util.py,sha256=
|
32
|
+
copyparty/u2idx.py,sha256=hOnScTNMnZ5sdbU_vR5L75qZdQ-dn_gwHBVCVcIRaOQ,10815
|
33
|
+
copyparty/up2k.py,sha256=5czsvwrZqruid5Jq4YnDsn332ET7QMIhJVL98w-BB2w,128718
|
34
|
+
copyparty/util.py,sha256=zr3gL4_vfzlnq5Uu_StgJgNrkAk4UTwLjUTSe0lIlkM,74609
|
35
35
|
copyparty/bos/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
36
36
|
copyparty/bos/bos.py,sha256=Md2RwMauEdOS7SfK5aiHby8T1KgQoTaoEjVCYU98_4I,1560
|
37
37
|
copyparty/bos/path.py,sha256=yEjCq2ki9CvxA5sCT8pS0keEXwugs0ZeUyUhdBziOCI,777
|
@@ -54,9 +54,9 @@ copyparty/stolen/ifaddr/_posix.py,sha256=-67NdfGrCktfQPakT2fLbjl2U00QMvyBGkSvrUu
|
|
54
54
|
copyparty/stolen/ifaddr/_shared.py,sha256=cJACl8cOxQ-HSYphZTzKMAjAx_TAFyJwUPjfD102Xqw,6111
|
55
55
|
copyparty/stolen/ifaddr/_win32.py,sha256=EE-QyoBgeB7lYQ6z62VjXNaRozaYfCkaJBHGNA8QtZM,4026
|
56
56
|
copyparty/web/baguettebox.js.gz,sha256=fyJfNSipzg093wMQAWiqI6SGoPcCe4JdLIvlOYkFG9Q,7379
|
57
|
-
copyparty/web/browser.css.gz,sha256=
|
57
|
+
copyparty/web/browser.css.gz,sha256=w2lFkbfJgY1vt1eyMXOKqgMySS_YyJ1jxu4MrKhkaOQ,11206
|
58
58
|
copyparty/web/browser.html,sha256=3L31n92yTaMpHFmvoiNjAgCUMi60YHN2qYN6YQdUcBs,4839
|
59
|
-
copyparty/web/browser.js.gz,sha256=
|
59
|
+
copyparty/web/browser.js.gz,sha256=pX-jsYSBpi-RPI5exmzbU_X5WnU1NR5e13234nAWARo,63685
|
60
60
|
copyparty/web/browser2.html,sha256=3kR3QiDXYqtAo7gOoBtdTP3eRvibUCZHVVAbmAfaAVU,1604
|
61
61
|
copyparty/web/cf.html,sha256=_tgwgNtK5MpjvvthGXx6Q9sasDaiWruyZfXsXYVW2KA,588
|
62
62
|
copyparty/web/dbg-audio.js.gz,sha256=Ma-KZtK8LnmiwNvNKFKXMPYl_Nn_3U7GsJ6-DRWC2HE,688
|
@@ -76,11 +76,11 @@ copyparty/web/splash.js.gz,sha256=3PMKsMLwEsHP8eonBmtvonm9yeNq69xjMi8ZqnVeKcA,12
|
|
76
76
|
copyparty/web/svcs.html,sha256=esTRzw4tkgWR_BPFZpDP0NX9slnkNnysE1E5weUdlOA,10591
|
77
77
|
copyparty/web/svcs.js.gz,sha256=k81ZvZ3I-f4fMHKrNGGOgOlvXnCBz0mVjD-8mieoWCA,520
|
78
78
|
copyparty/web/ui.css.gz,sha256=_3liYHDeJjgtiQecpTHQ3qvcMGvx8347ViKpEm8DjWU,2456
|
79
|
-
copyparty/web/up2k.js.gz,sha256=
|
79
|
+
copyparty/web/up2k.js.gz,sha256=ZWxdh7v1OVCYPlWUQxxlGcdgupTtdYuXYlO8xJeP9EM,21887
|
80
80
|
copyparty/web/util.js.gz,sha256=oJDTYgqi6tKLKbRYAtxW-RFzy6eNjbgayct6ZhB3SEE,13735
|
81
81
|
copyparty/web/w.hash.js.gz,sha256=P9469QknH8-1aKwI_1n1_S4yKvIGOu7bGoty9N3zYMI,1060
|
82
82
|
copyparty/web/a/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
83
|
-
copyparty/web/a/partyfuse.py,sha256=
|
83
|
+
copyparty/web/a/partyfuse.py,sha256=Ki0ViQr9TTSvDBFY1x8c8v531oMnhNwgnYlTVhqwF_s,32305
|
84
84
|
copyparty/web/a/u2c.py,sha256=DendjoyF15_LlEblW_STKoLT7oSCPyzp9TOncsA4PgE,36595
|
85
85
|
copyparty/web/a/webdav-cfg.bat,sha256=Y4NoGZlksAIg4cBMb7KdJrpKC6Nx97onaTl6yMjaimk,1449
|
86
86
|
copyparty/web/dd/2.png,sha256=gJ14XFPzaw95L6z92fSq9eMPikSQyu-03P1lgiGe0_I,258
|
@@ -98,9 +98,9 @@ copyparty/web/deps/prismd.css.gz,sha256=ObUlksQVr-OuYlTz-I4B23TeBg2QDVVGRnWBz8cV
|
|
98
98
|
copyparty/web/deps/scp.woff2,sha256=w99BDU5i8MukkMEL-iW0YO9H4vFFZSPWxbkH70ytaAg,8612
|
99
99
|
copyparty/web/deps/sha512.ac.js.gz,sha256=lFZaCLumgWxrvEuDr4bqdKHsqjX82AbVAb7_F45Yk88,7033
|
100
100
|
copyparty/web/deps/sha512.hw.js.gz,sha256=km3_b5IoaVwg02Ex6PxnhDLZxKiOMP2cHW35j9CSWFA,8107
|
101
|
-
copyparty-1.9.
|
102
|
-
copyparty-1.9.
|
103
|
-
copyparty-1.9.
|
104
|
-
copyparty-1.9.
|
105
|
-
copyparty-1.9.
|
106
|
-
copyparty-1.9.
|
101
|
+
copyparty-1.9.14.dist-info/LICENSE,sha256=yyzj1id78vWoLs8zbMRJY7xkkLz0lv-9dfyeIauqdfM,1059
|
102
|
+
copyparty-1.9.14.dist-info/METADATA,sha256=KPpp97_-MbWj3Rk0VJ26hVpm7wyWDza6a0o_rmnJ4c8,105322
|
103
|
+
copyparty-1.9.14.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
|
104
|
+
copyparty-1.9.14.dist-info/entry_points.txt,sha256=4zw6a3rqASywQomiYLObjjlxybaI65LYYOTJwgKz7b0,128
|
105
|
+
copyparty-1.9.14.dist-info/top_level.txt,sha256=LnYUPsDyk-8kFgM6YJLG4h820DQekn81cObKSu9g-sI,10
|
106
|
+
copyparty-1.9.14.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|