mirror of
https://github.com/9001/copyparty.git
synced 2026-01-12 15:52:39 -07:00
Merge branch 'hovudstraum' into hovudstraum
Signed-off-by: stackxp <170874486+stackxp@users.noreply.github.com>
This commit is contained in:
commit
80e1d11cd4
|
|
@ -1275,6 +1275,8 @@ def add_network(ap):
|
||||||
ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)")
|
ap2.add_argument("--ll", action="store_true", help="include link-local IPv4/IPv6 in mDNS replies, even if the NIC has routable IPs (breaks some mDNS clients)")
|
||||||
ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=9999999, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m-1\033[0m]=closest-proxy, [\033[32m-2\033[0m]=second-hop, [\033[32m-3\033[0m]=third-hop")
|
ap2.add_argument("--rproxy", metavar="DEPTH", type=int, default=9999999, help="which ip to associate clients with; [\033[32m0\033[0m]=tcp, [\033[32m1\033[0m]=origin (first x-fwd, unsafe), [\033[32m-1\033[0m]=closest-proxy, [\033[32m-2\033[0m]=second-hop, [\033[32m-3\033[0m]=third-hop")
|
||||||
ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from")
|
ap2.add_argument("--xff-hdr", metavar="NAME", type=u, default="x-forwarded-for", help="if reverse-proxied, which http header to read the client's real ip from")
|
||||||
|
ap2.add_argument("--xf-host", metavar="NAME", type=u, default="x-forwarded-host", help="if reverse-proxied, which http header to read the correct Host value from; this header must contain the server's external domain name")
|
||||||
|
ap2.add_argument("--xf-proto", metavar="NAME", type=u, default="x-forwarded-proto", help="if reverse-proxied, which http header to read the correct protocol value from; this header must contain either 'http' or 'https'")
|
||||||
ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="list of trusted reverse-proxy CIDRs (comma-separated); only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)")
|
ap2.add_argument("--xff-src", metavar="CIDR", type=u, default="127.0.0.0/8, ::1/128", help="list of trusted reverse-proxy CIDRs (comma-separated); only accept the real-ip header (\033[33m--xff-hdr\033[0m) and IdP headers if the incoming connection is from an IP within either of these subnets. Specify [\033[32mlan\033[0m] to allow all LAN / private / non-internet IPs. Can be disabled with [\033[32many\033[0m] if you are behind cloudflare (or similar) and are using \033[32m--xff-hdr=cf-connecting-ip\033[0m (or similar)")
|
||||||
ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
ap2.add_argument("--ipa", metavar="CIDR", type=u, default="", help="only accept connections from IP-addresses inside \033[33mCIDR\033[0m (comma-separated); examples: [\033[32mlan\033[0m] or [\033[32m10.89.0.0/16, 192.168.33.0/24\033[0m]")
|
||||||
ap2.add_argument("--rp-loc", metavar="PATH", type=u, default="", help="if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [\033[32m/foo/bar\033[0m]")
|
ap2.add_argument("--rp-loc", metavar="PATH", type=u, default="", help="if reverse-proxying on a location instead of a dedicated domain/subdomain, provide the base location here; example: [\033[32m/foo/bar\033[0m]")
|
||||||
|
|
@ -1556,6 +1558,8 @@ def add_safety(ap):
|
||||||
ap2.add_argument("--logout", metavar="H", type=float, default=8086.0, help="logout clients after \033[33mH\033[0m 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)")
|
ap2.add_argument("--logout", metavar="H", type=float, default=8086.0, help="logout clients after \033[33mH\033[0m 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)")
|
||||||
ap2.add_argument("--dont-ban", metavar="TXT", type=u, default="no", help="anyone at this accesslevel or above will not get banned: [\033[32mav\033[0m]=admin-in-volume, [\033[32maa\033[0m]=has-admin-anywhere, [\033[32mrw\033[0m]=read-write, [\033[32mauth\033[0m]=authenticated, [\033[32many\033[0m]=disable-all-bans, [\033[32mno\033[0m]=anyone-can-get-banned")
|
ap2.add_argument("--dont-ban", metavar="TXT", type=u, default="no", help="anyone at this accesslevel or above will not get banned: [\033[32mav\033[0m]=admin-in-volume, [\033[32maa\033[0m]=has-admin-anywhere, [\033[32mrw\033[0m]=read-write, [\033[32mauth\033[0m]=authenticated, [\033[32many\033[0m]=disable-all-bans, [\033[32mno\033[0m]=anyone-can-get-banned")
|
||||||
ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong or blank passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
ap2.add_argument("--ban-pw", metavar="N,W,B", type=u, default="9,60,1440", help="more than \033[33mN\033[0m wrong or blank passwords in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
||||||
|
ap2.add_argument("--banmsg", metavar="TXT", type=u, default="thank you for playing \u00a0 (see serverlog and readme)", help="the response to send to banned users; can be @ban.html to send the contents of ban.html")
|
||||||
|
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]")
|
||||||
ap2.add_argument("--ban-pwc", metavar="N,W,B", type=u, default="5,60,1440", help="more than \033[33mN\033[0m password-changes in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
ap2.add_argument("--ban-pwc", metavar="N,W,B", type=u, default="5,60,1440", help="more than \033[33mN\033[0m password-changes in \033[33mW\033[0m minutes = ban for \033[33mB\033[0m minutes; disable with [\033[32mno\033[0m]")
|
||||||
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")
|
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")
|
||||||
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")
|
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")
|
||||||
|
|
@ -1643,6 +1647,7 @@ def add_thumbnail(ap):
|
||||||
ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=th_ram, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
|
ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=th_ram, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
|
||||||
ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32my\033[0m]=crop, [\033[32mn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
|
ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32my\033[0m]=crop, [\033[32mn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
|
||||||
ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32my\033[0m]=yes, [\033[32mn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
|
ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32my\033[0m]=yes, [\033[32mn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
|
||||||
|
ap2.add_argument("--th-qv", metavar="N", type=int, default=40, help="thumbnail quality (10~90); higher is larger filesize and better quality (volflag=th_qv)")
|
||||||
ap2.add_argument("--th-dec", metavar="LIBS", default="vips,pil,raw,ff", help="image decoders, in order of preference")
|
ap2.add_argument("--th-dec", metavar="LIBS", default="vips,pil,raw,ff", help="image decoders, in order of preference")
|
||||||
ap2.add_argument("--th-no-jpg", action="store_true", help="disable jpg output")
|
ap2.add_argument("--th-no-jpg", action="store_true", help="disable jpg output")
|
||||||
ap2.add_argument("--th-no-webp", action="store_true", help="disable webp output")
|
ap2.add_argument("--th-no-webp", action="store_true", help="disable webp output")
|
||||||
|
|
|
||||||
|
|
@ -2384,7 +2384,7 @@ class AuthSrv(object):
|
||||||
if vf not in vol.flags:
|
if vf not in vol.flags:
|
||||||
vol.flags[vf] = getattr(self.args, ga)
|
vol.flags[vf] = getattr(self.args, ga)
|
||||||
|
|
||||||
zs = "forget_ip gid nrand tail_who th_spec_p u2abort u2ow uid unp_who ups_who zip_who"
|
zs = "forget_ip gid nrand tail_who th_qv th_spec_p u2abort u2ow uid unp_who ups_who zip_who"
|
||||||
for k in zs.split():
|
for k in zs.split():
|
||||||
if k in vol.flags:
|
if k in vol.flags:
|
||||||
vol.flags[k] = int(vol.flags[k])
|
vol.flags[k] = int(vol.flags[k])
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ def vf_vmap() -> dict[str, str]:
|
||||||
"tail_tmax",
|
"tail_tmax",
|
||||||
"tail_who",
|
"tail_who",
|
||||||
"tcolor",
|
"tcolor",
|
||||||
|
"th_qv",
|
||||||
"th_spec_p",
|
"th_spec_p",
|
||||||
"txt_eol",
|
"txt_eol",
|
||||||
"unlist",
|
"unlist",
|
||||||
|
|
@ -289,6 +290,7 @@ flagcats = {
|
||||||
"thsize": "thumbnail res; WxH",
|
"thsize": "thumbnail res; WxH",
|
||||||
"crop": "center-cropping (y/n/fy/fn)",
|
"crop": "center-cropping (y/n/fy/fn)",
|
||||||
"th3x": "3x resolution (y/n/fy/fn)",
|
"th3x": "3x resolution (y/n/fy/fn)",
|
||||||
|
"th_qv=40": "thumbnail quality (10~90)",
|
||||||
"convt": "convert-to-image timeout in seconds",
|
"convt": "convert-to-image timeout in seconds",
|
||||||
"aconvt": "convert-to-audio timeout in seconds",
|
"aconvt": "convert-to-audio timeout in seconds",
|
||||||
"th_spec_p=1": "make spectrograms? 0=never 1=fallback 2=always",
|
"th_spec_p=1": "make spectrograms? 0=never 1=fallback 2=always",
|
||||||
|
|
|
||||||
|
|
@ -127,6 +127,24 @@ class Fstab(object):
|
||||||
|
|
||||||
self.log("mtab has changed; reevaluating support for sparse files")
|
self.log("mtab has changed; reevaluating support for sparse files")
|
||||||
|
|
||||||
|
try:
|
||||||
|
fuses = [mp for mp, fs in dtab.items() if fs == "fuseblk"]
|
||||||
|
if not fuses or MACOS:
|
||||||
|
raise Exception()
|
||||||
|
try:
|
||||||
|
so, _ = chkcmd(["lsblk", "-nrfo", "FSTYPE,MOUNTPOINT"]) # centos6
|
||||||
|
except:
|
||||||
|
so, _ = chkcmd(["lsblk", "-nrfo", "FSTYPE,MOUNTPOINTS"]) # future
|
||||||
|
for ln in so.split("\n"):
|
||||||
|
zsl = ln.split(" ", 1)
|
||||||
|
if len(zsl) != 2:
|
||||||
|
continue
|
||||||
|
fs, mp = zsl
|
||||||
|
if mp in fuses:
|
||||||
|
dtab[mp] = fs
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
tab1 = list(dtab.items())
|
tab1 = list(dtab.items())
|
||||||
tab1.sort(key=lambda x: (len(x[0]), x[0]))
|
tab1.sort(key=lambda x: (len(x[0]), x[0]))
|
||||||
path1, fs1 = tab1[0]
|
path1, fs1 = tab1[0]
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,7 @@ NO_CACHE = {"Cache-Control": "no-cache"}
|
||||||
ALL_COOKIES = "k304 no304 js idxh dots cppwd cppws".split()
|
ALL_COOKIES = "k304 no304 js idxh dots cppwd cppws".split()
|
||||||
|
|
||||||
BADXFF = " due to dangerous misconfiguration (the http-header specified by --xff-hdr was received from an untrusted reverse-proxy)"
|
BADXFF = " due to dangerous misconfiguration (the http-header specified by --xff-hdr was received from an untrusted reverse-proxy)"
|
||||||
|
BADXFF2 = ". Some copyparty features are now disabled as a safety measure."
|
||||||
|
|
||||||
H_CONN_KEEPALIVE = "Connection: Keep-Alive"
|
H_CONN_KEEPALIVE = "Connection: Keep-Alive"
|
||||||
H_CONN_CLOSE = "Connection: Close"
|
H_CONN_CLOSE = "Connection: Close"
|
||||||
|
|
@ -221,12 +222,11 @@ class HttpCli(object):
|
||||||
self.log_func = conn.log_func # mypy404
|
self.log_func = conn.log_func # mypy404
|
||||||
self.log_src = conn.log_src # mypy404
|
self.log_src = conn.log_src # mypy404
|
||||||
self.gen_fk = self._gen_fk if self.args.log_fk else gen_filekey
|
self.gen_fk = self._gen_fk if self.args.log_fk else gen_filekey
|
||||||
self.tls: bool = hasattr(self.s, "cipher")
|
self.tls = self.is_https = hasattr(self.s, "cipher")
|
||||||
self.is_vproxied = bool(self.args.R)
|
self.is_vproxied = bool(self.args.R)
|
||||||
|
|
||||||
# placeholders; assigned by run()
|
# placeholders; assigned by run()
|
||||||
self.keepalive = False
|
self.keepalive = False
|
||||||
self.is_https = False
|
|
||||||
self.in_hdr_recv = True
|
self.in_hdr_recv = True
|
||||||
self.headers: dict[str, str] = {}
|
self.headers: dict[str, str] = {}
|
||||||
self.mode = " " # http verb
|
self.mode = " " # http verb
|
||||||
|
|
@ -390,9 +390,6 @@ class HttpCli(object):
|
||||||
self.keepalive = "close" not in zs and (
|
self.keepalive = "close" not in zs and (
|
||||||
self.http_ver != "HTTP/1.0" or zs == "keep-alive"
|
self.http_ver != "HTTP/1.0" or zs == "keep-alive"
|
||||||
)
|
)
|
||||||
self.is_https = (
|
|
||||||
self.headers.get("x-forwarded-proto", "").lower() == "https" or self.tls
|
|
||||||
)
|
|
||||||
self.host = self.headers.get("host") or ""
|
self.host = self.headers.get("host") or ""
|
||||||
if not self.host:
|
if not self.host:
|
||||||
if self.s.family == socket.AF_UNIX:
|
if self.s.family == socket.AF_UNIX:
|
||||||
|
|
@ -417,7 +414,7 @@ class HttpCli(object):
|
||||||
self.bad_xff = True
|
self.bad_xff = True
|
||||||
if self.args.rproxy != 9999999:
|
if self.args.rproxy != 9999999:
|
||||||
t = "global-option --rproxy %d could not be used (out-of-bounds) for the received header [%s]"
|
t = "global-option --rproxy %d could not be used (out-of-bounds) for the received header [%s]"
|
||||||
self.log(t % (self.args.rproxy, zso), c=3)
|
self.log(t % (self.args.rproxy, zso) + BADXFF2, c=3)
|
||||||
else:
|
else:
|
||||||
zsl = [
|
zsl = [
|
||||||
" rproxy: %d if this client's IP-address is [%s]"
|
" rproxy: %d if this client's IP-address is [%s]"
|
||||||
|
|
@ -436,6 +433,7 @@ class HttpCli(object):
|
||||||
t += ' Note: if you are behind cloudflare, then this default header is not a good choice; please first make sure your local reverse-proxy (if any) does not allow non-cloudflare IPs from providing cf-* headers, and then add this additional global setting: "--xff-hdr=cf-connecting-ip"'
|
t += ' Note: if you are behind cloudflare, then this default header is not a good choice; please first make sure your local reverse-proxy (if any) does not allow non-cloudflare IPs from providing cf-* headers, and then add this additional global setting: "--xff-hdr=cf-connecting-ip"'
|
||||||
else:
|
else:
|
||||||
t += ' Note: depending on your reverse-proxy, and/or WAF, and/or other intermediates, you may want to read the true client IP from another header by also specifying "--xff-hdr=SomeOtherHeader"'
|
t += ' Note: depending on your reverse-proxy, and/or WAF, and/or other intermediates, you may want to read the true client IP from another header by also specifying "--xff-hdr=SomeOtherHeader"'
|
||||||
|
t += BADXFF2
|
||||||
|
|
||||||
if "." in pip:
|
if "." in pip:
|
||||||
zs = ".".join(pip.split(".")[:2]) + ".0.0/16"
|
zs = ".".join(pip.split(".")[:2]) + ".0.0/16"
|
||||||
|
|
@ -448,7 +446,19 @@ class HttpCli(object):
|
||||||
else:
|
else:
|
||||||
self.ip = cli_ip
|
self.ip = cli_ip
|
||||||
self.log_src = self.conn.set_rproxy(self.ip)
|
self.log_src = self.conn.set_rproxy(self.ip)
|
||||||
self.host = self.headers.get("x-forwarded-host") or self.host
|
self.host = self.headers.get(self.args.xf_host, self.host)
|
||||||
|
try:
|
||||||
|
self.is_https = len(self.headers[self.args.xf_proto]) == 5
|
||||||
|
except:
|
||||||
|
self.bad_xff = True
|
||||||
|
self.host = "example.com"
|
||||||
|
t = 'got proxied request without header "%s" (global-option "xf-proto"). This header must contain either "http" or "https". Either fix your reverse-proxy config to include this header, or change the copyparty global-option "xf-proto" to another header-name to read this value from'
|
||||||
|
self.log(t % (self.args.xf_proto,) + BADXFF2, 3)
|
||||||
|
|
||||||
|
# the semantics of trusted_xff and bad_xff are different;
|
||||||
|
# trusted_xff is whether the connection came from a trusted reverseproxy,
|
||||||
|
# regardless of whether the client ip detection is correctly configured
|
||||||
|
# (the primary safeguard for idp is --idp-h-key)
|
||||||
trusted_xff = True
|
trusted_xff = True
|
||||||
|
|
||||||
m = RE_HOST.search(self.host)
|
m = RE_HOST.search(self.host)
|
||||||
|
|
@ -623,7 +633,7 @@ class HttpCli(object):
|
||||||
if relchk(self.vpath) and (self.vpath != "*" or self.mode != "OPTIONS"):
|
if relchk(self.vpath) and (self.vpath != "*" or self.mode != "OPTIONS"):
|
||||||
self.log("illegal relpath; req(%r) => %r" % (self.req, "/" + self.vpath))
|
self.log("illegal relpath; req(%r) => %r" % (self.req, "/" + self.vpath))
|
||||||
self.cbonk(self.conn.hsrv.gmal, self.req, "bad_vp", "invalid relpaths")
|
self.cbonk(self.conn.hsrv.gmal, self.req, "bad_vp", "invalid relpaths")
|
||||||
return self.tx_404() and self.keepalive
|
return self.tx_404() and False
|
||||||
|
|
||||||
zso = self.headers.get("authorization")
|
zso = self.headers.get("authorization")
|
||||||
bauth = ""
|
bauth = ""
|
||||||
|
|
@ -955,7 +965,7 @@ class HttpCli(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.log("banned for {:.0f} sec".format(rt), 6)
|
self.log("banned for {:.0f} sec".format(rt), 6)
|
||||||
self.terse_reply(b"thank you for playing (see serverlog and readme)", 403)
|
self.terse_reply(self.args.banmsg_b, 403)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def permit_caching(self) -> None:
|
def permit_caching(self) -> None:
|
||||||
|
|
@ -1138,7 +1148,10 @@ class HttpCli(object):
|
||||||
]
|
]
|
||||||
|
|
||||||
if body:
|
if body:
|
||||||
lines.append("Content-Length: " + unicode(len(body)))
|
lines.append(
|
||||||
|
"Content-Type: text/html; charset=utf-8\r\nContent-Length: "
|
||||||
|
+ unicode(len(body))
|
||||||
|
)
|
||||||
|
|
||||||
lines.append("\r\n")
|
lines.append("\r\n")
|
||||||
self.s.sendall("\r\n".join(lines).encode("utf-8") + body)
|
self.s.sendall("\r\n".join(lines).encode("utf-8") + body)
|
||||||
|
|
@ -5718,17 +5731,18 @@ class HttpCli(object):
|
||||||
and (self.uname in vol.axs.uread or self.uname in vol.axs.upget)
|
and (self.uname in vol.axs.uread or self.uname in vol.axs.upget)
|
||||||
}
|
}
|
||||||
|
|
||||||
bad_xff = hasattr(self, "bad_xff")
|
if hasattr(self, "bad_xff"):
|
||||||
if bad_xff:
|
|
||||||
allvols = []
|
allvols = []
|
||||||
t = "will not return list of recent uploads" + BADXFF
|
t = "will not return list of recent uploads" + BADXFF
|
||||||
self.log(t, 1)
|
self.log(t, 1)
|
||||||
if self.avol:
|
if self.avol:
|
||||||
raise Pebkac(500, t)
|
raise Pebkac(500, t)
|
||||||
|
|
||||||
x = self.conn.hsrv.broker.ask(
|
x = self.conn.hsrv.broker.ask("up2k.get_unfinished_by_user", self.uname, "")
|
||||||
"up2k.get_unfinished_by_user", self.uname, "" if bad_xff else self.ip
|
else:
|
||||||
)
|
x = self.conn.hsrv.broker.ask(
|
||||||
|
"up2k.get_unfinished_by_user", self.uname, self.ip
|
||||||
|
)
|
||||||
zdsa: dict[str, Any] = x.get()
|
zdsa: dict[str, Any] = x.get()
|
||||||
uret: list[dict[str, Any]] = []
|
uret: list[dict[str, Any]] = []
|
||||||
if "timeout" in zdsa:
|
if "timeout" in zdsa:
|
||||||
|
|
|
||||||
|
|
@ -1102,6 +1102,12 @@ class SvcHub(object):
|
||||||
else:
|
else:
|
||||||
setattr(al, k, re.compile("^" + vs + "$"))
|
setattr(al, k, re.compile("^" + vs + "$"))
|
||||||
|
|
||||||
|
if al.banmsg.startswith("@"):
|
||||||
|
with open(al.banmsg[1:], "rb") as f:
|
||||||
|
al.banmsg_b = f.read()
|
||||||
|
else:
|
||||||
|
al.banmsg_b = al.banmsg.encode("utf-8") + b"\n"
|
||||||
|
|
||||||
if not al.sus_urls:
|
if not al.sus_urls:
|
||||||
al.ban_url = "no"
|
al.ban_url = "no"
|
||||||
elif al.ban_url == "no":
|
elif al.ban_url == "no":
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ import time
|
||||||
|
|
||||||
from queue import Queue
|
from queue import Queue
|
||||||
|
|
||||||
from .__init__ import ANYWIN, PY2, TYPE_CHECKING
|
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, unicode
|
||||||
from .authsrv import VFS
|
from .authsrv import VFS
|
||||||
from .bos import bos
|
from .bos import bos
|
||||||
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, au_unpk, ffprobe
|
from .mtag import HAVE_FFMPEG, HAVE_FFPROBE, au_unpk, ffprobe
|
||||||
|
|
@ -56,6 +56,56 @@ EXTS_SPEC_SAFE = set("aif aiff flac mp3 opus wav".split())
|
||||||
|
|
||||||
PTN_TS = re.compile("^-?[0-9a-f]{8,10}$")
|
PTN_TS = re.compile("^-?[0-9a-f]{8,10}$")
|
||||||
|
|
||||||
|
# for n in {1..100}; do rm -rf /home/ed/Pictures/wp/.hist/th/ ; python3 -m copyparty -qv /home/ed/Pictures/wp/::r --th-no-webp --th-qv $n --th-dec pil >/dev/null 2>&1 & p=$!; printf '\033[A\033[J%3d ' $n; while true; do sleep 0.1; curl -s 127.1:3923 >/dev/null && break; done; curl -s '127.1:3923/?tar=j' >/dev/null ; cat /home/ed/Pictures/wp/.hist/th/1n/bs/1nBsjDetfie1iDq3y2D4YzF5/*.* | wc -c; kill $p; wait >/dev/null 2>&1; done
|
||||||
|
# filesize-equivalent, not quality (ff looks much shittier)
|
||||||
|
FF_JPG_Q = {
|
||||||
|
0: b"30", # 0
|
||||||
|
1: b"30", # 5
|
||||||
|
2: b"30", # 10
|
||||||
|
3: b"30", # 15
|
||||||
|
4: b"28", # 20
|
||||||
|
5: b"21", # 25
|
||||||
|
6: b"17", # 30
|
||||||
|
7: b"15", # 35
|
||||||
|
8: b"13", # 40
|
||||||
|
9: b"12", # 45
|
||||||
|
10: b"11", # 50
|
||||||
|
11: b"10", # 55
|
||||||
|
12: b"9", # 60
|
||||||
|
13: b"8", # 65
|
||||||
|
14: b"7", # 70
|
||||||
|
15: b"6", # 75
|
||||||
|
16: b"5", # 80
|
||||||
|
17: b"4", # 85
|
||||||
|
18: b"3", # 90
|
||||||
|
19: b"2", # 95
|
||||||
|
20: b"2", # 100
|
||||||
|
}
|
||||||
|
# FF_JPG_Q = {xn: ("%d" % (xn,)).encode("ascii") for xn in range(2, 33)}
|
||||||
|
VIPS_JPG_Q = {
|
||||||
|
0: 4, # 0
|
||||||
|
1: 7, # 5
|
||||||
|
2: 12, # 10
|
||||||
|
3: 17, # 15
|
||||||
|
4: 22, # 20
|
||||||
|
5: 27, # 25
|
||||||
|
6: 32, # 30
|
||||||
|
7: 37, # 35
|
||||||
|
8: 42, # 40
|
||||||
|
9: 47, # 45
|
||||||
|
10: 52, # 50
|
||||||
|
11: 56, # 55
|
||||||
|
12: 61, # 60
|
||||||
|
13: 66, # 65
|
||||||
|
14: 71, # 70
|
||||||
|
15: 75, # 75
|
||||||
|
16: 80, # 80
|
||||||
|
17: 85, # 85
|
||||||
|
18: 89, # 90 (vips explodes past this point)
|
||||||
|
19: 91, # 95
|
||||||
|
20: 97, # 100
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if os.environ.get("PRTY_NO_PIL"):
|
if os.environ.get("PRTY_NO_PIL"):
|
||||||
|
|
@ -308,6 +358,7 @@ class ThumbSrv(object):
|
||||||
if not bos.path.exists(inf_path):
|
if not bos.path.exists(inf_path):
|
||||||
with open(inf_path, "wb") as f:
|
with open(inf_path, "wb") as f:
|
||||||
f.write(afsenc(os.path.dirname(abspath)))
|
f.write(afsenc(os.path.dirname(abspath)))
|
||||||
|
self.writevolcfg(histpath)
|
||||||
|
|
||||||
self.busy[tpath] = [cond]
|
self.busy[tpath] = [cond]
|
||||||
do_conv = True
|
do_conv = True
|
||||||
|
|
@ -351,6 +402,47 @@ class ThumbSrv(object):
|
||||||
"ffa": self.fmt_ffa,
|
"ffa": self.fmt_ffa,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def volcfgi(self, vn: VFS) -> str:
|
||||||
|
ret = []
|
||||||
|
zs = "th_dec th_no_webp th_no_jpg"
|
||||||
|
for zs in zs.split(" "):
|
||||||
|
ret.append("%s(%s)\n" % (zs, getattr(self.args, zs)))
|
||||||
|
zs = "th_qv thsize th_spec_p convt"
|
||||||
|
for zs in zs.split(" "):
|
||||||
|
ret.append("%s(%s)\n" % (zs, vn.flags.get(zs)))
|
||||||
|
return "".join(ret)
|
||||||
|
|
||||||
|
def volcfga(self, vn: VFS) -> str:
|
||||||
|
ret = []
|
||||||
|
zs = "q_opus q_mp3"
|
||||||
|
for zs in zs.split(" "):
|
||||||
|
ret.append("%s(%s)\n" % (zs, getattr(self.args, zs)))
|
||||||
|
zs = "aconvt"
|
||||||
|
for zs in zs.split(" "):
|
||||||
|
ret.append("%s(%s)\n" % (zs, vn.flags.get(zs)))
|
||||||
|
return "".join(ret)
|
||||||
|
|
||||||
|
def writevolcfg(self, histpath: str) -> None:
|
||||||
|
try:
|
||||||
|
bos.stat(os.path.join(histpath, "th", "cfg.txt"))
|
||||||
|
bos.stat(os.path.join(histpath, "ac", "cfg.txt"))
|
||||||
|
return
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
cfgi = cfga = ""
|
||||||
|
for vn in self.asrv.vfs.all_vols.values():
|
||||||
|
if vn.histpath == histpath:
|
||||||
|
cfgi = self.volcfgi(vn)
|
||||||
|
cfga = self.volcfga(vn)
|
||||||
|
break
|
||||||
|
t = "writing thumbnailer-config %d,%d to %s"
|
||||||
|
self.log(t % (len(cfgi), len(cfga), histpath))
|
||||||
|
chmod = bos.MKD_700 if self.args.free_umask else bos.MKD_755
|
||||||
|
for cfg, cat in ((cfgi, "th"), (cfga, "ac")):
|
||||||
|
bos.makedirs(os.path.join(histpath, cat), vf=chmod)
|
||||||
|
with open(os.path.join(histpath, cat, "cfg.txt"), "wb") as f:
|
||||||
|
f.write(cfg.encode("utf-8"))
|
||||||
|
|
||||||
def wait4ram(self, need: float, ttpath: str) -> None:
|
def wait4ram(self, need: float, ttpath: str) -> None:
|
||||||
ram = self.args.th_ram_max
|
ram = self.args.th_ram_max
|
||||||
if need > ram * 0.99:
|
if need > ram * 0.99:
|
||||||
|
|
@ -529,7 +621,7 @@ class ThumbSrv(object):
|
||||||
im.thumbnail(self.getres(vn, fmt))
|
im.thumbnail(self.getres(vn, fmt))
|
||||||
|
|
||||||
fmts = ["RGB", "L"]
|
fmts = ["RGB", "L"]
|
||||||
args = {"quality": 40}
|
args = {"quality": vn.flags["th_qv"]}
|
||||||
|
|
||||||
if tpath.endswith(".webp"):
|
if tpath.endswith(".webp"):
|
||||||
# quality 80 = pillow-default
|
# quality 80 = pillow-default
|
||||||
|
|
@ -573,7 +665,12 @@ class ThumbSrv(object):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
assert img # type: ignore # !rm
|
assert img # type: ignore # !rm
|
||||||
img.write_to_file(tpath, Q=40)
|
args = {}
|
||||||
|
qv = vn.flags["th_qv"]
|
||||||
|
if tpath.endswith("jpg"):
|
||||||
|
qv = VIPS_JPG_Q[qv // 5]
|
||||||
|
args["optimize_coding"] = True
|
||||||
|
img.write_to_file(tpath, Q=qv, strip=True, **args)
|
||||||
|
|
||||||
def conv_raw(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
def conv_raw(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
||||||
self.wait4ram(0.2, tpath)
|
self.wait4ram(0.2, tpath)
|
||||||
|
|
@ -607,7 +704,12 @@ class ThumbSrv(object):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
assert img # type: ignore # !rm
|
assert img # type: ignore # !rm
|
||||||
img.write_to_file(tpath, Q=40)
|
args = {}
|
||||||
|
qv = vn.flags["th_qv"]
|
||||||
|
if tpath.endswith("jpg"):
|
||||||
|
qv = VIPS_JPG_Q[qv // 5]
|
||||||
|
args["optimize_coding"] = True
|
||||||
|
img.write_to_file(tpath, Q=qv, strip=True, **args)
|
||||||
elif HAVE_PIL:
|
elif HAVE_PIL:
|
||||||
if thumb.format == rawpy.ThumbFormat.BITMAP:
|
if thumb.format == rawpy.ThumbFormat.BITMAP:
|
||||||
im = Image.fromarray(thumb.data, "RGB")
|
im = Image.fromarray(thumb.data, "RGB")
|
||||||
|
|
@ -671,12 +773,12 @@ class ThumbSrv(object):
|
||||||
if tpath.endswith(".jpg"):
|
if tpath.endswith(".jpg"):
|
||||||
cmd += [
|
cmd += [
|
||||||
b"-q:v",
|
b"-q:v",
|
||||||
b"6", # default=??
|
FF_JPG_Q[vn.flags["th_qv"] // 5], # default=??
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
cmd += [
|
cmd += [
|
||||||
b"-q:v",
|
b"-q:v",
|
||||||
b"50", # default=75
|
unicode(vn.flags["th_qv"]).encode("ascii"), # default=75
|
||||||
b"-compression_level:v",
|
b"-compression_level:v",
|
||||||
b"6", # default=4, 0=fast, 6=max
|
b"6", # default=4, 0=fast, 6=max
|
||||||
]
|
]
|
||||||
|
|
@ -722,7 +824,7 @@ class ThumbSrv(object):
|
||||||
if len(lines) > 50:
|
if len(lines) > 50:
|
||||||
lines = lines[:25] + ["[...]"] + lines[-25:]
|
lines = lines[:25] + ["[...]"] + lines[-25:]
|
||||||
|
|
||||||
txt = "\n".join(["ff: " + str(x) for x in lines])
|
txt = "\n".join(["ff: " + unicode(x) for x in lines])
|
||||||
if len(txt) > 5000:
|
if len(txt) > 5000:
|
||||||
txt = txt[:2500] + "...\nff: [...]\nff: ..." + txt[-2500:]
|
txt = txt[:2500] + "...\nff: [...]\nff: ..." + txt[-2500:]
|
||||||
|
|
||||||
|
|
@ -880,12 +982,12 @@ class ThumbSrv(object):
|
||||||
if tpath.endswith(".jpg"):
|
if tpath.endswith(".jpg"):
|
||||||
cmd += [
|
cmd += [
|
||||||
b"-q:v",
|
b"-q:v",
|
||||||
b"6", # default=??
|
FF_JPG_Q[vn.flags["th_qv"] // 5], # default=??
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
cmd += [
|
cmd += [
|
||||||
b"-q:v",
|
b"-q:v",
|
||||||
b"50", # default=75
|
unicode(vn.flags["th_qv"]).encode("ascii"), # default=75
|
||||||
b"-compression_level:v",
|
b"-compression_level:v",
|
||||||
b"6", # default=4, 0=fast, 6=max
|
b"6", # default=4, 0=fast, 6=max
|
||||||
]
|
]
|
||||||
|
|
@ -1143,7 +1245,7 @@ class ThumbSrv(object):
|
||||||
ret = []
|
ret = []
|
||||||
for k, vs in raw_tags.items():
|
for k, vs in raw_tags.items():
|
||||||
for v in vs:
|
for v in vs:
|
||||||
if len(str(v)) >= 1024:
|
if len(unicode(v)) >= 1024:
|
||||||
bv = k.encode("utf-8", "replace")
|
bv = k.encode("utf-8", "replace")
|
||||||
ret += [b"-metadata", bv + b"="]
|
ret += [b"-metadata", bv + b"="]
|
||||||
break
|
break
|
||||||
|
|
@ -1181,6 +1283,28 @@ class ThumbSrv(object):
|
||||||
time.sleep(interval)
|
time.sleep(interval)
|
||||||
|
|
||||||
def clean(self, histpath: str) -> int:
|
def clean(self, histpath: str) -> int:
|
||||||
|
cfgi = cfga = ""
|
||||||
|
for vn in self.asrv.vfs.all_vols.values():
|
||||||
|
if vn.histpath == histpath:
|
||||||
|
cfgi = self.volcfgi(vn)
|
||||||
|
cfga = self.volcfga(vn)
|
||||||
|
break
|
||||||
|
for cfg, cat in ((cfgi, "th"), (cfga, "ac")):
|
||||||
|
if not cfg:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
with open(os.path.join(histpath, cat, "cfg.txt"), "rb") as f:
|
||||||
|
oldcfg = f.read().decode("utf-8")
|
||||||
|
except:
|
||||||
|
oldcfg = ""
|
||||||
|
if cfg == oldcfg:
|
||||||
|
continue
|
||||||
|
zs = os.path.join(histpath, cat)
|
||||||
|
if not os.path.exists(zs):
|
||||||
|
continue
|
||||||
|
self.log("thumbnailer-config changed; deleting %s" % (zs,), 3)
|
||||||
|
shutil.rmtree(zs)
|
||||||
|
|
||||||
ret = 0
|
ret = 0
|
||||||
for cat in ["th", "ac"]:
|
for cat in ["th", "ac"]:
|
||||||
top = os.path.join(histpath, cat)
|
top = os.path.join(histpath, cat)
|
||||||
|
|
@ -1239,7 +1363,7 @@ class ThumbSrv(object):
|
||||||
if len(b64) != 24 or len(ts) != 8 or ext not in exts:
|
if len(b64) != 24 or len(ts) != 8 or ext not in exts:
|
||||||
raise Exception()
|
raise Exception()
|
||||||
except:
|
except:
|
||||||
if f != "dir.txt":
|
if f != "dir.txt" and f != "cfg.txt":
|
||||||
self.log("foreign file in thumbs dir: [{}]".format(fp), 1)
|
self.log("foreign file in thumbs dir: [{}]".format(fp), 1)
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
|
||||||
|
|
@ -1139,6 +1139,20 @@ var ACtx = !IPHONE && (window.AudioContext || window.webkitAudioContext),
|
||||||
dk, mp;
|
dk, mp;
|
||||||
|
|
||||||
|
|
||||||
|
var x = '';
|
||||||
|
if (!fullui) {
|
||||||
|
if (window.ui_nombar || /[?&]nombar\b/.exec(sloc0)) x += '#ops,';
|
||||||
|
if (window.ui_noacci || /[?&]noacci\b/.exec(sloc0)) x += '#acc_info,';
|
||||||
|
if (window.ui_nosrvi || /[?&]nosrvi\b/.exec(sloc0)) x += '#srv_info,#srv_info2,';
|
||||||
|
if (window.ui_nocpla || /[?&]nocpla\b/.exec(sloc0)) x += '#goh,';
|
||||||
|
if (window.ui_nolbar || /[?&]nolbar\b/.exec(sloc0)) x += '#wfp,';
|
||||||
|
if (window.ui_noctxb || /[?&]noctxb\b/.exec(sloc0)) x += '#wtoggle,';
|
||||||
|
if (window.ui_norepl || /[?&]norepl\b/.exec(sloc0)) x += '#repl,';
|
||||||
|
}
|
||||||
|
if (x)
|
||||||
|
document.head.appendChild(mknod('style', '', x.slice(0, -1) + '{display:none!important}'));
|
||||||
|
|
||||||
|
|
||||||
if (location.pathname.indexOf('//') === 0)
|
if (location.pathname.indexOf('//') === 0)
|
||||||
hist_replace(location.pathname.replace(/^\/+/, '/'));
|
hist_replace(location.pathname.replace(/^\/+/, '/'));
|
||||||
|
|
||||||
|
|
@ -1242,6 +1256,7 @@ var mpl = (function () {
|
||||||
"os_ctl": bcfg_get('au_os_ctl', have_mctl) && have_mctl,
|
"os_ctl": bcfg_get('au_os_ctl', have_mctl) && have_mctl,
|
||||||
'traversals': 0,
|
'traversals': 0,
|
||||||
'm3ut': '#EXTM3U\n',
|
'm3ut': '#EXTM3U\n',
|
||||||
|
'np': [{'file': 'nothing'}, ['file']],
|
||||||
};
|
};
|
||||||
bcfg_bind(r, 'one', 'au_one', false, function (v) {
|
bcfg_bind(r, 'one', 'au_one', false, function (v) {
|
||||||
if (mp.au)
|
if (mp.au)
|
||||||
|
|
@ -1438,7 +1453,7 @@ var mpl = (function () {
|
||||||
if (!r.os_ctl || !mp.au)
|
if (!r.os_ctl || !mp.au)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var np = get_np()[0],
|
var np = mpl.np[0],
|
||||||
fns = np.file.split(' - '),
|
fns = np.file.split(' - '),
|
||||||
artist = (np.circle && np.circle != np.artist ? np.circle + ' // ' : '') + (np.artist || (fns.length > 1 ? fns[0] : '')),
|
artist = (np.circle && np.circle != np.artist ? np.circle + ' // ' : '') + (np.artist || (fns.length > 1 ? fns[0] : '')),
|
||||||
title = np.title || fns.pop(),
|
title = np.title || fns.pop(),
|
||||||
|
|
@ -1784,12 +1799,6 @@ function ft2dict(tr, skip) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function get_np() {
|
|
||||||
var tr = QS('#files tr.play');
|
|
||||||
return ft2dict(tr, { 'up_ip': 1 });
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// toggle player widget
|
// toggle player widget
|
||||||
var widget = (function () {
|
var widget = (function () {
|
||||||
var r = {},
|
var r = {},
|
||||||
|
|
@ -1847,9 +1856,8 @@ var widget = (function () {
|
||||||
ck = irc ? '06' : '',
|
ck = irc ? '06' : '',
|
||||||
cv = irc ? '07' : '',
|
cv = irc ? '07' : '',
|
||||||
m = ck + 'np: ',
|
m = ck + 'np: ',
|
||||||
npr = get_np(),
|
npk = mpl.np[1],
|
||||||
npk = npr[1],
|
np = mpl.np[0];
|
||||||
np = npr[0];
|
|
||||||
|
|
||||||
for (var a = 0; a < npk.length; a++)
|
for (var a = 0; a < npk.length; a++)
|
||||||
m += (npk[a] == 'file' ? '' : npk[a]).replace(/^\./, '') + '(' + cv + np[npk[a]] + ck + ') // ';
|
m += (npk[a] == 'file' ? '' : npk[a]).replace(/^\./, '') + '(' + cv + np[npk[a]] + ck + ') // ';
|
||||||
|
|
@ -2548,6 +2556,9 @@ var mpui = (function () {
|
||||||
if (mpl.prescan_evp == evp)
|
if (mpl.prescan_evp == evp)
|
||||||
throw "evp match";
|
throw "evp match";
|
||||||
|
|
||||||
|
if (treectl.trunc)
|
||||||
|
return treectl.showmore(99999, repreload);
|
||||||
|
|
||||||
if (mpl.traversals++ > 4) {
|
if (mpl.traversals++ > 4) {
|
||||||
mpl.prescan_evp = null;
|
mpl.prescan_evp = null;
|
||||||
toast.inf(10, L.mm_nof);
|
toast.inf(10, L.mm_nof);
|
||||||
|
|
@ -3024,6 +3035,9 @@ function play(tid, is_ev, seek) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tn >= mp.order.length) {
|
if (tn >= mp.order.length) {
|
||||||
|
if (treectl.trunc)
|
||||||
|
return treectl.showmore(99999, next_song);
|
||||||
|
|
||||||
if (mpl.pb_mode == 'loop' || ebi('unsearch')) {
|
if (mpl.pb_mode == 'loop' || ebi('unsearch')) {
|
||||||
tn = 0;
|
tn = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -3097,9 +3111,12 @@ function play(tid, is_ev, seek) {
|
||||||
for (var a = 0, aa = trs.length; a < aa; a++)
|
for (var a = 0, aa = trs.length; a < aa; a++)
|
||||||
clmod(trs[a], 'play');
|
clmod(trs[a], 'play');
|
||||||
|
|
||||||
var oid = 'a' + tid;
|
var oid = 'a' + tid,
|
||||||
clmod(ebi(oid), 'act', 1);
|
t_a = ebi(oid),
|
||||||
clmod(ebi(oid).closest('tr'), 'play', 1);
|
t_tr = t_a.closest('tr');
|
||||||
|
|
||||||
|
clmod(t_a, 'act', 1);
|
||||||
|
clmod(t_tr, 'play', 1);
|
||||||
clmod(ebi('wtoggle'), 'np', mpl.clip);
|
clmod(ebi('wtoggle'), 'np', mpl.clip);
|
||||||
clmod(ebi('wtoggle'), 'm3u', mpl.m3uen);
|
clmod(ebi('wtoggle'), 'm3u', mpl.m3uen);
|
||||||
if (thegrid)
|
if (thegrid)
|
||||||
|
|
@ -3121,12 +3138,12 @@ function play(tid, is_ev, seek) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!seek && !ebi('unsearch')) {
|
if (!seek && !ebi('unsearch')) {
|
||||||
var o = ebi(oid);
|
t_a.setAttribute('id', 'thx_js');
|
||||||
o.setAttribute('id', 'thx_js');
|
|
||||||
if (mpl.aplay)
|
if (mpl.aplay)
|
||||||
sethash(oid + getsort());
|
sethash(oid + getsort());
|
||||||
o.setAttribute('id', oid);
|
t_a.setAttribute('id', oid);
|
||||||
}
|
}
|
||||||
|
mpl.np = ft2dict(t_tr, { 'up_ip': 1 });
|
||||||
|
|
||||||
pbar.unwave();
|
pbar.unwave();
|
||||||
if (mpl.waves)
|
if (mpl.waves)
|
||||||
|
|
@ -3141,7 +3158,7 @@ function play(tid, is_ev, seek) {
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
toast.err(0, esc(L.mm_playerr + basenames(ex)));
|
toast.err(0, esc(L.mm_playerr + basenames(ex)));
|
||||||
}
|
}
|
||||||
clmod(ebi(oid), 'act');
|
clmod(t_a, 'act');
|
||||||
mpl.t_eplay = setTimeout(next_song, 5000);
|
mpl.t_eplay = setTimeout(next_song, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -7520,7 +7537,7 @@ var treectl = (function () {
|
||||||
catch (ex) { }
|
catch (ex) { }
|
||||||
};
|
};
|
||||||
|
|
||||||
r.showmore = function (n) {
|
r.showmore = function (n, cb) {
|
||||||
window.removeEventListener('scroll', r.tscroll);
|
window.removeEventListener('scroll', r.tscroll);
|
||||||
console.log('nvis {0} -> {1}'.format(r.nvis, n));
|
console.log('nvis {0} -> {1}'.format(r.nvis, n));
|
||||||
r.nvis = n;
|
r.nvis = n;
|
||||||
|
|
@ -7530,6 +7547,8 @@ var treectl = (function () {
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
r.gentab(get_evpath(), r.lsc);
|
r.gentab(get_evpath(), r.lsc);
|
||||||
ebi('wrap').style.opacity = CLOSEST ? 'unset' : 1;
|
ebi('wrap').style.opacity = CLOSEST ? 'unset' : 1;
|
||||||
|
if (cb)
|
||||||
|
cb();
|
||||||
}, 1);
|
}, 1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -8226,7 +8245,12 @@ var settheme = (function () {
|
||||||
freshen();
|
freshen();
|
||||||
};
|
};
|
||||||
|
|
||||||
freshen();
|
var m = /[?&]theme=([0-9]+)/.exec(sloc0);
|
||||||
|
if (m)
|
||||||
|
r.go(parseInt(m[1]));
|
||||||
|
else
|
||||||
|
freshen();
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
@ -9437,14 +9461,3 @@ function reload_browser() {
|
||||||
msel.render();
|
msel.render();
|
||||||
}
|
}
|
||||||
treectl.hydrate();
|
treectl.hydrate();
|
||||||
|
|
||||||
if (!fullui && (window.ui_nombar || /[?&]nombar\b/.exec(sloc0))) ebi('ops').style.display = 'none';
|
|
||||||
if (!fullui && (window.ui_noacci || /[?&]noacci\b/.exec(sloc0))) ebi('acc_info').style.display = 'none';
|
|
||||||
if (!fullui && (window.ui_nosrvi || /[?&]nosrvi\b/.exec(sloc0))) ebi('srv_info').style.display = 'none';
|
|
||||||
if (!fullui && (window.ui_nocpla || /[?&]nocpla\b/.exec(sloc0))) ebi('goh').style.display = 'none';
|
|
||||||
if (!fullui && (window.ui_nolbar || /[?&]nolbar\b/.exec(sloc0))) ebi('wfp').style.display = 'none';
|
|
||||||
if (!fullui && (window.ui_noctxb || /[?&]noctxb\b/.exec(sloc0))) ebi('wtoggle').style.display = 'none';
|
|
||||||
if (!fullui && (window.ui_norepl || /[?&]norepl\b/.exec(sloc0))) ebi('repl').style.display = 'none';
|
|
||||||
|
|
||||||
var m = /[?&]theme=([0-9]+)/.exec(sloc0);
|
|
||||||
if (m) settheme.go(parseInt(m[1]));
|
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ class Cfg(Namespace):
|
||||||
ex = "hash_mt hsortn qdel safe_dedup scan_pr_r scan_pr_s scan_st_r srch_time tail_fd tail_rate th_spec_p u2abort u2j u2sz unp_who"
|
ex = "hash_mt hsortn qdel safe_dedup scan_pr_r scan_pr_s scan_st_r srch_time tail_fd tail_rate th_spec_p u2abort u2j u2sz unp_who"
|
||||||
ka.update(**{k: 1 for k in ex.split()})
|
ka.update(**{k: 1 for k in ex.split()})
|
||||||
|
|
||||||
ex = "ac_convt au_vol dl_list du_iwho mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who ver_iwho zip_who"
|
ex = "ac_convt au_vol dl_list du_iwho mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt th_qv ups_who ver_iwho zip_who"
|
||||||
ka.update(**{k: 9 for k in ex.split()})
|
ka.update(**{k: 9 for k in ex.split()})
|
||||||
|
|
||||||
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue