mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
v0.11.18
This commit is contained in:
parent
0a8e759fe6
commit
10362aa02e
|
@ -1,8 +1,8 @@
|
||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
VERSION = (0, 11, 17)
|
VERSION = (0, 11, 18)
|
||||||
CODENAME = "the grid"
|
CODENAME = "the grid"
|
||||||
BUILD_DT = (2021, 6, 17)
|
BUILD_DT = (2021, 6, 18)
|
||||||
|
|
||||||
S_VERSION = ".".join(map(str, VERSION))
|
S_VERSION = ".".join(map(str, VERSION))
|
||||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||||
|
|
|
@ -68,6 +68,7 @@ class MpWorker(object):
|
||||||
|
|
||||||
# self.logw("work: [{}]".format(d[0]))
|
# self.logw("work: [{}]".format(d[0]))
|
||||||
if dest == "shutdown":
|
if dest == "shutdown":
|
||||||
|
self.httpsrv.shutdown()
|
||||||
self.logw("ok bye")
|
self.logw("ok bye")
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
return
|
return
|
||||||
|
|
|
@ -25,6 +25,7 @@ class BrokerThr(object):
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
# self.log("broker", "shutting down")
|
# self.log("broker", "shutting down")
|
||||||
|
self.httpsrv.shutdown()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def put(self, want_retval, dest, *args):
|
def put(self, want_retval, dest, *args):
|
||||||
|
|
|
@ -256,10 +256,11 @@ class HttpCli(object):
|
||||||
if self.is_rclone:
|
if self.is_rclone:
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
cmap = {"pw": "cppwd"}
|
||||||
kv = {
|
kv = {
|
||||||
k: v
|
k: v
|
||||||
for k, v in self.uparam.items()
|
for k, v in self.uparam.items()
|
||||||
if k not in rm and self.cookies.get(k) != v
|
if k not in rm and self.cookies.get(cmap.get(k, k)) != v
|
||||||
}
|
}
|
||||||
kv.update(add)
|
kv.update(add)
|
||||||
if not kv:
|
if not kv:
|
||||||
|
@ -581,10 +582,17 @@ class HttpCli(object):
|
||||||
try:
|
try:
|
||||||
dst = os.path.join(vfs.realpath, rem)
|
dst = os.path.join(vfs.realpath, rem)
|
||||||
os.makedirs(fsenc(dst))
|
os.makedirs(fsenc(dst))
|
||||||
except:
|
except OSError as ex:
|
||||||
if not os.path.isdir(fsenc(dst)):
|
if ex.errno == 13:
|
||||||
|
raise Pebkac(500, "the server OS denied write-access")
|
||||||
|
|
||||||
|
if ex.errno == 17:
|
||||||
raise Pebkac(400, "some file got your folder name")
|
raise Pebkac(400, "some file got your folder name")
|
||||||
|
|
||||||
|
raise Pebkac(500, min_ex())
|
||||||
|
except:
|
||||||
|
raise Pebkac(500, min_ex())
|
||||||
|
|
||||||
x = self.conn.hsrv.broker.put(True, "up2k.handle_json", body)
|
x = self.conn.hsrv.broker.put(True, "up2k.handle_json", body)
|
||||||
ret = x.get()
|
ret = x.get()
|
||||||
if sub:
|
if sub:
|
||||||
|
@ -769,8 +777,13 @@ class HttpCli(object):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
os.mkdir(fsenc(fn))
|
os.mkdir(fsenc(fn))
|
||||||
|
except OSError as ex:
|
||||||
|
if ex.errno == 13:
|
||||||
|
raise Pebkac(500, "the server OS denied write-access")
|
||||||
|
|
||||||
|
raise Pebkac(500, "mkdir failed:\n" + min_ex())
|
||||||
except:
|
except:
|
||||||
raise Pebkac(500, "mkdir failed, check the logs")
|
raise Pebkac(500, min_ex())
|
||||||
|
|
||||||
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
vpath = "{}/{}".format(self.vpath, sanitized).lstrip("/")
|
||||||
self.redirect(vpath)
|
self.redirect(vpath)
|
||||||
|
@ -1187,7 +1200,7 @@ class HttpCli(object):
|
||||||
#
|
#
|
||||||
# send reply
|
# send reply
|
||||||
|
|
||||||
if not is_compressed:
|
if not is_compressed and "cache" not in self.uparam:
|
||||||
self.out_headers.update(NO_CACHE)
|
self.out_headers.update(NO_CACHE)
|
||||||
|
|
||||||
self.out_headers["Accept-Ranges"] = "bytes"
|
self.out_headers["Accept-Ranges"] = "bytes"
|
||||||
|
|
|
@ -43,6 +43,7 @@ class HttpConn(object):
|
||||||
self.ico = Ico(self.args)
|
self.ico = Ico(self.args)
|
||||||
|
|
||||||
self.t0 = time.time()
|
self.t0 = time.time()
|
||||||
|
self.stopping = False
|
||||||
self.nbyte = 0
|
self.nbyte = 0
|
||||||
self.workload = 0
|
self.workload = 0
|
||||||
self.u2idx = None
|
self.u2idx = None
|
||||||
|
@ -50,6 +51,14 @@ class HttpConn(object):
|
||||||
self.lf_url = re.compile(self.args.lf_url) if self.args.lf_url else None
|
self.lf_url = re.compile(self.args.lf_url) if self.args.lf_url else None
|
||||||
self.set_rproxy()
|
self.set_rproxy()
|
||||||
|
|
||||||
|
def shutdown(self):
|
||||||
|
self.stopping = True
|
||||||
|
try:
|
||||||
|
self.s.shutdown(socket.SHUT_RDWR)
|
||||||
|
self.s.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
def set_rproxy(self, ip=None):
|
def set_rproxy(self, ip=None):
|
||||||
if ip is None:
|
if ip is None:
|
||||||
color = 36
|
color = 36
|
||||||
|
@ -174,7 +183,7 @@ class HttpConn(object):
|
||||||
if not self.sr:
|
if not self.sr:
|
||||||
self.sr = Unrecv(self.s)
|
self.sr = Unrecv(self.s)
|
||||||
|
|
||||||
while True:
|
while not self.stopping:
|
||||||
if self.is_mp:
|
if self.is_mp:
|
||||||
self.workload += 50
|
self.workload += 50
|
||||||
if self.workload >= 2 ** 31:
|
if self.workload >= 2 ** 31:
|
||||||
|
|
|
@ -80,7 +80,14 @@ class HttpSrv(object):
|
||||||
return len(self.clients)
|
return len(self.clients)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
self.log("ok bye")
|
clients = list(self.clients.keys())
|
||||||
|
for cli in clients:
|
||||||
|
try:
|
||||||
|
cli.shutdown()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
self.log("httpsrv-n", "ok bye")
|
||||||
|
|
||||||
def thr_client(self, sck, addr):
|
def thr_client(self, sck, addr):
|
||||||
"""thread managing one tcp client"""
|
"""thread managing one tcp client"""
|
||||||
|
@ -100,25 +107,35 @@ class HttpSrv(object):
|
||||||
thr.daemon = True
|
thr.daemon = True
|
||||||
thr.start()
|
thr.start()
|
||||||
|
|
||||||
|
fno = sck.fileno()
|
||||||
try:
|
try:
|
||||||
if self.args.log_conn:
|
if self.args.log_conn:
|
||||||
self.log("%s %s" % addr, "|%sC-crun" % ("-" * 6,), c="1;30")
|
self.log("%s %s" % addr, "|%sC-crun" % ("-" * 6,), c="1;30")
|
||||||
|
|
||||||
cli.run()
|
cli.run()
|
||||||
|
|
||||||
|
except (OSError, socket.error) as ex:
|
||||||
|
if ex.errno not in [10038, 10054, 107, 57, 9]:
|
||||||
|
self.log(
|
||||||
|
"%s %s" % addr,
|
||||||
|
"run({}): {}".format(fno, ex),
|
||||||
|
c=6,
|
||||||
|
)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
sck = cli.s
|
sck = cli.s
|
||||||
if self.args.log_conn:
|
if self.args.log_conn:
|
||||||
self.log("%s %s" % addr, "|%sC-cdone" % ("-" * 7,), c="1;30")
|
self.log("%s %s" % addr, "|%sC-cdone" % ("-" * 7,), c="1;30")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
fno = sck.fileno()
|
||||||
sck.shutdown(socket.SHUT_RDWR)
|
sck.shutdown(socket.SHUT_RDWR)
|
||||||
sck.close()
|
sck.close()
|
||||||
except (OSError, socket.error) as ex:
|
except (OSError, socket.error) as ex:
|
||||||
if not MACOS:
|
if not MACOS:
|
||||||
self.log(
|
self.log(
|
||||||
"%s %s" % addr,
|
"%s %s" % addr,
|
||||||
"shut({}): {}".format(sck.fileno(), ex),
|
"shut({}): {}".format(fno, ex),
|
||||||
c="1;30",
|
c="1;30",
|
||||||
)
|
)
|
||||||
if ex.errno not in [10038, 10054, 107, 57, 9]:
|
if ex.errno not in [10038, 10054, 107, 57, 9]:
|
||||||
|
|
|
@ -16,6 +16,7 @@ if not PY2:
|
||||||
|
|
||||||
def have_ff(cmd):
|
def have_ff(cmd):
|
||||||
if PY2:
|
if PY2:
|
||||||
|
print("# checking {}".format(cmd))
|
||||||
cmd = (cmd + " -version").encode("ascii").split(b" ")
|
cmd = (cmd + " -version").encode("ascii").split(b" ")
|
||||||
try:
|
try:
|
||||||
sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE).communicate()
|
sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE).communicate()
|
||||||
|
|
|
@ -21,6 +21,7 @@ class TcpSrv(object):
|
||||||
self.log = hub.log
|
self.log = hub.log
|
||||||
|
|
||||||
self.num_clients = Counter()
|
self.num_clients = Counter()
|
||||||
|
self.stopping = False
|
||||||
|
|
||||||
ip = "127.0.0.1"
|
ip = "127.0.0.1"
|
||||||
eps = {ip: "local only"}
|
eps = {ip: "local only"}
|
||||||
|
@ -67,7 +68,7 @@ class TcpSrv(object):
|
||||||
ip, port = srv.getsockname()
|
ip, port = srv.getsockname()
|
||||||
self.log("tcpsrv", "listening @ {0}:{1}".format(ip, port))
|
self.log("tcpsrv", "listening @ {0}:{1}".format(ip, port))
|
||||||
|
|
||||||
while True:
|
while not self.stopping:
|
||||||
if self.args.log_conn:
|
if self.args.log_conn:
|
||||||
self.log("tcpsrv", "|%sC-ncli" % ("-" * 1,), c="1;30")
|
self.log("tcpsrv", "|%sC-ncli" % ("-" * 1,), c="1;30")
|
||||||
|
|
||||||
|
@ -80,6 +81,9 @@ class TcpSrv(object):
|
||||||
|
|
||||||
ready, _, _ = select.select(self.srv, [], [])
|
ready, _, _ = select.select(self.srv, [], [])
|
||||||
for srv in ready:
|
for srv in ready:
|
||||||
|
if self.stopping:
|
||||||
|
break
|
||||||
|
|
||||||
sck, addr = srv.accept()
|
sck, addr = srv.accept()
|
||||||
sip, sport = srv.getsockname()
|
sip, sport = srv.getsockname()
|
||||||
if self.args.log_conn:
|
if self.args.log_conn:
|
||||||
|
@ -95,6 +99,13 @@ class TcpSrv(object):
|
||||||
self.hub.broker.put(False, "httpconn", sck, addr)
|
self.hub.broker.put(False, "httpconn", sck, addr)
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
|
self.stopping = True
|
||||||
|
try:
|
||||||
|
for srv in self.srv:
|
||||||
|
srv.close()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
self.log("tcpsrv", "ok bye")
|
self.log("tcpsrv", "ok bye")
|
||||||
|
|
||||||
def detect_interfaces(self, listen_ips):
|
def detect_interfaces(self, listen_ips):
|
||||||
|
|
|
@ -16,7 +16,7 @@ import traceback
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
from copy import deepcopy
|
from copy import deepcopy
|
||||||
|
|
||||||
from .__init__ import WINDOWS, ANYWIN
|
from .__init__ import WINDOWS, ANYWIN, PY2
|
||||||
from .util import (
|
from .util import (
|
||||||
Pebkac,
|
Pebkac,
|
||||||
Queue,
|
Queue,
|
||||||
|
@ -134,7 +134,7 @@ class Up2k(object):
|
||||||
def get_state(self):
|
def get_state(self):
|
||||||
mtpq = 0
|
mtpq = 0
|
||||||
q = "select count(w) from mt where k = 't:mtp'"
|
q = "select count(w) from mt where k = 't:mtp'"
|
||||||
got_lock = self.mutex.acquire(timeout=0.5)
|
got_lock = False if PY2 else self.mutex.acquire(timeout=0.5)
|
||||||
if got_lock:
|
if got_lock:
|
||||||
for cur in self.cur.values():
|
for cur in self.cur.values():
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -25,6 +25,35 @@ html, body {
|
||||||
body {
|
body {
|
||||||
padding-bottom: 5em;
|
padding-bottom: 5em;
|
||||||
}
|
}
|
||||||
|
#tt {
|
||||||
|
position: fixed;
|
||||||
|
max-width: 34em;
|
||||||
|
background: #222;
|
||||||
|
border: 0 solid #555;
|
||||||
|
overflow: hidden;
|
||||||
|
margin-top: 1em;
|
||||||
|
padding: 0 1em;
|
||||||
|
height: 0;
|
||||||
|
opacity: .1;
|
||||||
|
transition: opacity 0.14s, height 0.14s, padding 0.14s;
|
||||||
|
box-shadow: 0 .2em .5em #222;
|
||||||
|
border-radius: .4em;
|
||||||
|
z-index: 9001;
|
||||||
|
}
|
||||||
|
#tt.show {
|
||||||
|
padding: 1em;
|
||||||
|
height: auto;
|
||||||
|
border-width: .2em 0;
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
#tt code {
|
||||||
|
background: #3c3c3c;
|
||||||
|
padding: .2em .3em;
|
||||||
|
border-top: 1px solid #777;
|
||||||
|
border-radius: .3em;
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
line-height: 2em;
|
||||||
|
}
|
||||||
#path,
|
#path,
|
||||||
#path * {
|
#path * {
|
||||||
font-size: 1em;
|
font-size: 1em;
|
||||||
|
@ -189,6 +218,14 @@ a, #files tbody div a:last-child {
|
||||||
color: #720;
|
color: #720;
|
||||||
text-shadow: 0 0 .3em #b80;
|
text-shadow: 0 0 .3em #b80;
|
||||||
}
|
}
|
||||||
|
#ggrid a.play,
|
||||||
|
html.light #ggrid a.play {
|
||||||
|
color: #fff;
|
||||||
|
background: #750;
|
||||||
|
border-color: #c90;
|
||||||
|
border-top: 1px solid #da4;
|
||||||
|
box-shadow: 0 .1em 1.2em #b83;
|
||||||
|
}
|
||||||
#files tbody tr.sel td,
|
#files tbody tr.sel td,
|
||||||
#ggrid a.sel,
|
#ggrid a.sel,
|
||||||
html.light #ggrid a.sel {
|
html.light #ggrid a.sel {
|
||||||
|
@ -210,11 +247,17 @@ html.light #ggrid a.sel {
|
||||||
box-shadow: 0 .1em 1.2em #b36;
|
box-shadow: 0 .1em 1.2em #b36;
|
||||||
transition: all 0.2s cubic-bezier(.2, 2.2, .5, 1); /* https://cubic-bezier.com/#.4,2,.7,1 */
|
transition: all 0.2s cubic-bezier(.2, 2.2, .5, 1); /* https://cubic-bezier.com/#.4,2,.7,1 */
|
||||||
}
|
}
|
||||||
#ggrid a.sel img {
|
#ggrid a.sel img,
|
||||||
|
#ggrid a.play img {
|
||||||
opacity: .7;
|
opacity: .7;
|
||||||
box-shadow: 0 0 1em #b36;
|
|
||||||
filter: contrast(130%) brightness(107%);
|
filter: contrast(130%) brightness(107%);
|
||||||
}
|
}
|
||||||
|
#ggrid a.sel img {
|
||||||
|
box-shadow: 0 0 1em #b36;
|
||||||
|
}
|
||||||
|
#ggrid a.play img {
|
||||||
|
box-shadow: 0 0 1em #b83;
|
||||||
|
}
|
||||||
#files tr.sel a {
|
#files tr.sel a {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
@ -739,7 +782,7 @@ input.eq_gain {
|
||||||
.opwide>div {
|
.opwide>div {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
border-left: .2em solid #444;
|
border-left: .2em solid #4c4c4c;
|
||||||
margin-left: .5em;
|
margin-left: .5em;
|
||||||
padding-left: .5em;
|
padding-left: .5em;
|
||||||
}
|
}
|
||||||
|
@ -758,31 +801,6 @@ input.eq_gain {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border-bottom: 1px solid #555;
|
border-bottom: 1px solid #555;
|
||||||
}
|
}
|
||||||
#opdesc {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#ops:hover #opdesc {
|
|
||||||
display: block;
|
|
||||||
background: linear-gradient(0deg,#555, #4c4c4c 80%, #444);
|
|
||||||
box-shadow: 0 .3em 1em #222;
|
|
||||||
padding: 1em;
|
|
||||||
border-radius: .3em;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 3;
|
|
||||||
top: 6em;
|
|
||||||
right: 1.5em;
|
|
||||||
}
|
|
||||||
#ops:hover #opdesc.off {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
#opdesc code {
|
|
||||||
background: #3c3c3c;
|
|
||||||
padding: .2em .3em;
|
|
||||||
border-top: 1px solid #777;
|
|
||||||
border-radius: .3em;
|
|
||||||
font-family: monospace, monospace;
|
|
||||||
line-height: 2em;
|
|
||||||
}
|
|
||||||
#thumbs {
|
#thumbs {
|
||||||
opacity: .3;
|
opacity: .3;
|
||||||
}
|
}
|
||||||
|
@ -889,6 +907,15 @@ html.light {
|
||||||
background: #eee;
|
background: #eee;
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
}
|
}
|
||||||
|
html.light #tt {
|
||||||
|
background: #fff;
|
||||||
|
border-color: #888;
|
||||||
|
box-shadow: 0 .3em 1em rgba(0,0,0,0.4);
|
||||||
|
}
|
||||||
|
html.light #tt code {
|
||||||
|
background: #060;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
html.light #ops,
|
html.light #ops,
|
||||||
html.light .opbox,
|
html.light .opbox,
|
||||||
html.light #srch_form {
|
html.light #srch_form {
|
||||||
|
@ -972,6 +999,9 @@ html.light #files tr.play td:nth-child(2n) {
|
||||||
html.light #files tbody a.play {
|
html.light #files tbody a.play {
|
||||||
color: #c0f;
|
color: #c0f;
|
||||||
}
|
}
|
||||||
|
html.light #files tbody a.play.act {
|
||||||
|
color: #90c;
|
||||||
|
}
|
||||||
html.light #files tr.play td {
|
html.light #files tr.play td {
|
||||||
background: #fc5;
|
background: #fc5;
|
||||||
border-color: #eb1;
|
border-color: #eb1;
|
||||||
|
@ -1026,7 +1056,7 @@ html.light input[type="checkbox"] + label {
|
||||||
color: #333;
|
color: #333;
|
||||||
}
|
}
|
||||||
html.light .opwide>div {
|
html.light .opwide>div {
|
||||||
border-color: #ddd;
|
border-color: #ccc;
|
||||||
}
|
}
|
||||||
html.light .opview input[type="text"] {
|
html.light .opview input[type="text"] {
|
||||||
background: #fff;
|
background: #fff;
|
||||||
|
@ -1034,14 +1064,6 @@ html.light .opview input[type="text"] {
|
||||||
box-shadow: 0 0 2px #888;
|
box-shadow: 0 0 2px #888;
|
||||||
border-color: #38d;
|
border-color: #38d;
|
||||||
}
|
}
|
||||||
html.light #ops:hover #opdesc {
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: 0 .3em 1em #ccc;
|
|
||||||
}
|
|
||||||
html.light #opdesc code {
|
|
||||||
background: #060;
|
|
||||||
color: #fff;
|
|
||||||
}
|
|
||||||
html.light #u2tab a>span,
|
html.light #u2tab a>span,
|
||||||
html.light #files td div span {
|
html.light #files td div span {
|
||||||
color: #000;
|
color: #000;
|
||||||
|
@ -1051,9 +1073,6 @@ html.light #path {
|
||||||
text-shadow: none;
|
text-shadow: none;
|
||||||
box-shadow: 0 0 .3em #bbb;
|
box-shadow: 0 0 .3em #bbb;
|
||||||
}
|
}
|
||||||
html.light #path a {
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
html.light #path a:not(:last-child)::after {
|
html.light #path a:not(:last-child)::after {
|
||||||
border-color: #ccc;
|
border-color: #ccc;
|
||||||
background: none;
|
background: none;
|
||||||
|
@ -1062,7 +1081,7 @@ html.light #path a:not(:last-child)::after {
|
||||||
}
|
}
|
||||||
html.light #path a:hover {
|
html.light #path a:hover {
|
||||||
background: none;
|
background: none;
|
||||||
color: #60a;
|
color: #90d;
|
||||||
}
|
}
|
||||||
html.light #files tbody div a {
|
html.light #files tbody div a {
|
||||||
color: #d38;
|
color: #d38;
|
||||||
|
|
|
@ -15,19 +15,19 @@
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="ops">
|
<div id="ops">
|
||||||
<a href="#" data-dest="" data-desc="close submenu">---</a>
|
<a href="#" data-dest="" tt="close submenu">---</a>
|
||||||
{%- if have_up2k_idx %}
|
{%- if have_up2k_idx %}
|
||||||
<a href="#" data-perm="read" data-dest="search" data-desc="search for files by attributes, path/name, music tags, or any combination of those.<br /><br /><code>foo bar</code> = must contain both foo and bar,<br /><code>foo -bar</code> = must contain foo but not bar,<br /><code>^yana .opus$</code> = must start with yana and have the opus extension">🔎</a>
|
<a href="#" data-perm="read" data-dest="search" tt="search for files by attributes, path/name, music tags, or any combination of those.<br /><br /><code>foo bar</code> = must contain both foo and bar,<br /><code>foo -bar</code> = must contain foo but not bar,<br /><code>^yana .opus$</code> = must start with yana and have the opus extension">🔎</a>
|
||||||
<a href="#" data-dest="up2k" data-desc="up2k: upload files (if you have write-access) or toggle into the search-mode and drag files onto the search button to see if they exist somewhere on the server">🚀</a>
|
<a href="#" data-dest="up2k" tt="up2k: upload files (if you have write-access) or toggle into the search-mode and drag files onto the search button to see if they exist somewhere on the server">🚀</a>
|
||||||
{%- else %}
|
{%- else %}
|
||||||
<a href="#" data-perm="write" data-dest="up2k" data-desc="up2k: upload files with resume support (close your browser and drop the same files in later)">🚀</a>
|
<a href="#" data-perm="write" data-dest="up2k" tt="up2k: upload files with resume support (close your browser and drop the same files in later)">🚀</a>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<a href="#" data-perm="write" data-dest="bup" data-desc="bup: basic uploader, even supports netscape 4.0">🎈</a>
|
<a href="#" data-perm="write" data-dest="bup" tt="bup: basic uploader, even supports netscape 4.0">🎈</a>
|
||||||
<a href="#" data-perm="write" data-dest="mkdir" data-desc="mkdir: create a new directory">📂</a>
|
<a href="#" data-perm="write" data-dest="mkdir" tt="mkdir: create a new directory">📂</a>
|
||||||
<a href="#" data-perm="read write" data-dest="new_md" data-desc="new-md: create a new markdown document">📝</a>
|
<a href="#" data-perm="read write" data-dest="new_md" tt="new-md: create a new markdown document">📝</a>
|
||||||
<a href="#" data-perm="write" data-dest="msg" data-desc="msg: send a message to the server log">📟</a>
|
<a href="#" data-perm="write" data-dest="msg" tt="msg: send a message to the server log">📟</a>
|
||||||
<a href="#" data-dest="player" data-desc="media player options">🎺</a>
|
<a href="#" data-dest="player" tt="media player options">🎺</a>
|
||||||
<a href="#" data-dest="cfg" data-desc="configuration options">⚙️</a>
|
<a href="#" data-dest="cfg" tt="configuration options">⚙️</a>
|
||||||
<div id="opdesc"></div>
|
<div id="opdesc"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -48,10 +48,10 @@
|
||||||
<div>
|
<div>
|
||||||
<h3>switches</h3>
|
<h3>switches</h3>
|
||||||
<div>
|
<div>
|
||||||
<a id="tooltips" class="tgl btn" href="#">ℹ️ tooltips</a>
|
<a id="tooltips" class="tgl btn" href="#" tt="◔ ◡ ◔">ℹ️ tooltips</a>
|
||||||
<a id="lightmode" class="tgl btn" href="#">☀️ lightmode</a>
|
<a id="lightmode" class="tgl btn" href="#">☀️ lightmode</a>
|
||||||
<a id="griden" class="tgl btn" href="#">田 the grid</a>
|
<a id="griden" class="tgl btn" href="#" tt="toggle icons or list-view$NHotkey: G">田 the grid</a>
|
||||||
<a id="thumbs" class="tgl btn" href="#">🖼️ thumbs</a>
|
<a id="thumbs" class="tgl btn" href="#" tt="in icon view, toggle icons or thumbnails$NHotkey: T">🖼️ thumbs</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{%- if have_zip %}
|
{%- if have_zip %}
|
||||||
|
@ -62,7 +62,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h1 id="path">
|
<h1 id="path">
|
||||||
<a href="#" id="entree">🌲</a>
|
<a href="#" id="entree" tt="show directory tree$NHotkey: B">🌲</a>
|
||||||
{%- for n in vpnodes %}
|
{%- for n in vpnodes %}
|
||||||
<a href="/{{ n[0] }}">{{ n[1] }}</a>
|
<a href="/{{ n[0] }}">{{ n[1] }}</a>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -70,10 +70,10 @@
|
||||||
|
|
||||||
<div id="tree">
|
<div id="tree">
|
||||||
<div id="treeh">
|
<div id="treeh">
|
||||||
<a href="#" id="detree">🍞...</a>
|
<a href="#" id="detree" tt="show breadcrumbs$NHotkey: B">🍞...</a>
|
||||||
<a href="#" class="btn" step="2" id="twobytwo">+</a>
|
<a href="#" class="btn" step="2" id="twobytwo">+</a>
|
||||||
<a href="#" class="btn" step="-2" id="twig">–</a>
|
<a href="#" class="btn" step="-2" id="twig">–</a>
|
||||||
<a href="#" class="tgl btn" id="dyntree">a</a>
|
<a href="#" class="tgl btn" id="dyntree" tt="autogrow as tree expands">a</a>
|
||||||
</div>
|
</div>
|
||||||
<ul id="treeul"></ul>
|
<ul id="treeul"></ul>
|
||||||
<div id="thx_ff"> </div>
|
<div id="thx_ff"> </div>
|
||||||
|
|
|
@ -11,17 +11,17 @@ function dbg(msg) {
|
||||||
ebi('widget').innerHTML = (
|
ebi('widget').innerHTML = (
|
||||||
'<div id="wtoggle">' +
|
'<div id="wtoggle">' +
|
||||||
'<span id="wzip"><a' +
|
'<span id="wzip"><a' +
|
||||||
' href="#" id="selall">sel.<br />all</a><a' +
|
' href="#" id="selall" tt="select all files">sel.<br />all</a><a' +
|
||||||
' href="#" id="selinv">sel.<br />inv.</a><a' +
|
' href="#" id="selinv" tt="invert selection">sel.<br />inv.</a><a' +
|
||||||
' href="#" id="selzip">zip</a>' +
|
' href="#" id="selzip" tt="download selection as archive">zip</a>' +
|
||||||
'</span><span id="wnp"><a' +
|
'</span><span id="wnp"><a' +
|
||||||
' href="#" id="npirc">📋irc</a><a' +
|
' href="#" id="npirc" tt="copy irc-formatted track info">📋irc</a><a' +
|
||||||
' href="#" id="nptxt">📋txt</a>' +
|
' href="#" id="nptxt" tt="copy plaintext track info">📋txt</a>' +
|
||||||
'</span><a' +
|
'</span><a' +
|
||||||
' href="#" id="wtico">♫</a>' +
|
' href="#" id="wtico">♫</a>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div id="widgeti">' +
|
'<div id="widgeti">' +
|
||||||
' <div id="pctl"><a href="#" id="bprev">⏮</a><a href="#" id="bplay">▶</a><a href="#" id="bnext">⏭</a></div>' +
|
' <div id="pctl"><a href="#" id="bprev" tt="previous track$NHotkey: J">⏮</a><a href="#" id="bplay" tt="play/pause$NHotkey: P">▶</a><a href="#" id="bnext" tt="next track$NHotkey: L">⏭</a></div>' +
|
||||||
' <canvas id="pvol" width="288" height="38"></canvas>' +
|
' <canvas id="pvol" width="288" height="38"></canvas>' +
|
||||||
' <canvas id="barpos"></canvas>' +
|
' <canvas id="barpos"></canvas>' +
|
||||||
' <canvas id="barbuf"></canvas>' +
|
' <canvas id="barbuf"></canvas>' +
|
||||||
|
@ -44,15 +44,35 @@ var have_webp = null;
|
||||||
|
|
||||||
var mpl = (function () {
|
var mpl = (function () {
|
||||||
ebi('op_player').innerHTML = (
|
ebi('op_player').innerHTML = (
|
||||||
|
'<div><h3>switches</h3><div>' +
|
||||||
|
'<a href="#" class="tgl btn" id="au_preload" tt="start loading the next song near the end for gapless playback">preload</a>' +
|
||||||
|
'<a href="#" class="tgl btn" id="au_npclip" tt="show buttons for clipboarding the currently playing song">/np clip</a>' +
|
||||||
|
'</div></div>' +
|
||||||
|
|
||||||
'<div><h3>playback mode</h3><div id="pb_mode">' +
|
'<div><h3>playback mode</h3><div id="pb_mode">' +
|
||||||
'<a href="#" class="tgl btn">🔁 loop-folder</a>' +
|
'<a href="#" class="tgl btn" tt="loop the open folder">🔁 loop-folder</a>' +
|
||||||
'<a href="#" class="tgl btn">📂 next-folder</a>' +
|
'<a href="#" class="tgl btn" tt="load the next folder and continue">📂 next-folder</a>' +
|
||||||
'</div></div>' +
|
'</div></div>' +
|
||||||
|
|
||||||
'<div><h3>audio equalizer</h3><div id="audio_eq"></div></div>');
|
'<div><h3>audio equalizer</h3><div id="audio_eq"></div></div>');
|
||||||
|
|
||||||
var r = {
|
var r = {
|
||||||
"pb_mode": sread('pb_mode') || 'loop-folder'
|
"pb_mode": sread('pb_mode') || 'loop-folder',
|
||||||
|
"preload": bcfg_get('au_preload', true),
|
||||||
|
"clip": bcfg_get('au_npclip', false)
|
||||||
|
};
|
||||||
|
|
||||||
|
ebi('au_preload').onclick = function (e) {
|
||||||
|
ev(e);
|
||||||
|
r.preload = !r.preload;
|
||||||
|
bcfg_set('au_preload', r.preload);
|
||||||
|
};
|
||||||
|
|
||||||
|
ebi('au_npclip').onclick = function (e) {
|
||||||
|
ev(e);
|
||||||
|
r.clip = !r.clip;
|
||||||
|
bcfg_set('au_npclip', r.clip);
|
||||||
|
clmod(ebi('wtoggle'), 'np', r.clip && mp.au);
|
||||||
};
|
};
|
||||||
|
|
||||||
function draw_pb_mode() {
|
function draw_pb_mode() {
|
||||||
|
@ -80,7 +100,9 @@ function MPlayer() {
|
||||||
this.id = Date.now();
|
this.id = Date.now();
|
||||||
this.au = null;
|
this.au = null;
|
||||||
this.au_native = null;
|
this.au_native = null;
|
||||||
|
this.au_native2 = null;
|
||||||
this.au_ogvjs = null;
|
this.au_ogvjs = null;
|
||||||
|
this.au_ogvjs2 = null;
|
||||||
this.tracks = {};
|
this.tracks = {};
|
||||||
this.order = [];
|
this.order = [];
|
||||||
|
|
||||||
|
@ -135,7 +157,30 @@ function MPlayer() {
|
||||||
}
|
}
|
||||||
this.order = order;
|
this.order = order;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.preload = function (url) {
|
||||||
|
var au = null;
|
||||||
|
if (need_ogv_for(url)) {
|
||||||
|
au = mp.au_ogvjs2;
|
||||||
|
if (!au && window['OGVPlayer']) {
|
||||||
|
au = new OGVPlayer();
|
||||||
|
au.preload = "auto";
|
||||||
|
this.au_ogvjs2 = au;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
au = mp.au_native2;
|
||||||
|
if (!au) {
|
||||||
|
au = new Audio();
|
||||||
|
au.preload = "auto";
|
||||||
|
this.au_native2 = au;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (au) {
|
||||||
|
au.src = url + (url.indexOf('?') < 0 ? '?cache' : '&cache');
|
||||||
|
}
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
addcrc();
|
addcrc();
|
||||||
var mp = new MPlayer();
|
var mp = new MPlayer();
|
||||||
makeSortable(ebi('files'), mp.read_order.bind(mp));
|
makeSortable(ebi('files'), mp.read_order.bind(mp));
|
||||||
|
@ -236,12 +281,12 @@ function canvas_cfg(can) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function glossy_grad(can, hsl) {
|
function glossy_grad(can, h, s, l) {
|
||||||
var g = can.ctx.createLinearGradient(0, 0, 0, can.h),
|
var g = can.ctx.createLinearGradient(0, 0, 0, can.h),
|
||||||
s = [0, 0.49, 0.50, 1];
|
p = [0, 0.49, 0.50, 1];
|
||||||
|
|
||||||
for (var a = 0; a < hsl.length; a++)
|
for (var a = 0; a < p.length; a++)
|
||||||
g.addColorStop(s[a], 'hsl(' + hsl[a] + ')');
|
g.addColorStop(p[a], 'hsl(' + h + ',' + s[a] + '%,' + l[a] + '%)');
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
@ -266,16 +311,12 @@ var pbar = (function () {
|
||||||
|
|
||||||
var bc = r.buf,
|
var bc = r.buf,
|
||||||
bctx = bc.ctx,
|
bctx = bc.ctx,
|
||||||
sm = bc.w * 1.0 / mp.au.duration;
|
sm = bc.w * 1.0 / mp.au.duration,
|
||||||
|
gk = bc.h + '' + light;
|
||||||
|
|
||||||
if (gradh != bc.h) {
|
if (gradh != gk) {
|
||||||
gradh = bc.h;
|
gradh = gk;
|
||||||
grad = glossy_grad(bc, [
|
grad = glossy_grad(bc, 85, [35, 40, 37, 35], light ? [45, 56, 50, 45] : [42, 51, 47, 42]);
|
||||||
'85,35%,42%',
|
|
||||||
'85,40%,49%',
|
|
||||||
'85,37%,47%',
|
|
||||||
'85,35%,42%'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
bctx.fillStyle = grad;
|
bctx.fillStyle = grad;
|
||||||
bctx.clearRect(0, 0, bc.w, bc.h);
|
bctx.clearRect(0, 0, bc.w, bc.h);
|
||||||
|
@ -297,12 +338,11 @@ var pbar = (function () {
|
||||||
sm = bc.w * 1.0 / mp.au.duration;
|
sm = bc.w * 1.0 / mp.au.duration;
|
||||||
|
|
||||||
pctx.clearRect(0, 0, pc.w, pc.h);
|
pctx.clearRect(0, 0, pc.w, pc.h);
|
||||||
pctx.fillStyle = 'rgba(204,255,128,0.15)';
|
pctx.fillStyle = light ? 'rgba(0,64,0,0.15)' : 'rgba(204,255,128,0.15)';
|
||||||
for (var p = 1, mins = mp.au.duration / 10; p <= mins; p++)
|
for (var p = 1, mins = mp.au.duration / 10; p <= mins; p++)
|
||||||
pctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
|
pctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
|
||||||
|
|
||||||
pctx.fillStyle = '#9b7';
|
pctx.fillStyle = light ? 'rgba(0,64,0,0.5)' : 'rgba(192,255,96,0.5)';
|
||||||
pctx.fillStyle = 'rgba(192,255,96,0.5)';
|
|
||||||
for (var p = 1, mins = mp.au.duration / 60; p <= mins; p++)
|
for (var p = 1, mins = mp.au.duration / 60; p <= mins; p++)
|
||||||
pctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
|
pctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
|
||||||
|
|
||||||
|
@ -349,20 +389,11 @@ var vbar = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.draw = function () {
|
r.draw = function () {
|
||||||
if (gradh != h) {
|
var gh = h + '' + light;
|
||||||
gradh = h;
|
if (gradh != gh) {
|
||||||
grad1 = glossy_grad(r.can, [
|
gradh = gh;
|
||||||
'50,45%,42%',
|
grad1 = glossy_grad(r.can, 50, light ? [50, 55, 52, 48] : [45, 52, 47, 43], light ? [54, 60, 52, 47] : [42, 51, 47, 42]);
|
||||||
'50,50%,49%',
|
grad2 = glossy_grad(r.can, 205, [10, 15, 13, 10], [16, 20, 18, 16]);
|
||||||
'50,47%,47%',
|
|
||||||
'50,45%,42%'
|
|
||||||
]);
|
|
||||||
grad2 = glossy_grad(r.can, [
|
|
||||||
'205,10%,16%',
|
|
||||||
'205,15%,20%',
|
|
||||||
'205,13%,18%',
|
|
||||||
'205,10%,16%'
|
|
||||||
]);
|
|
||||||
}
|
}
|
||||||
ctx.fillStyle = grad2; ctx.fillRect(0, 0, w, h);
|
ctx.fillStyle = grad2; ctx.fillRect(0, 0, w, h);
|
||||||
ctx.fillStyle = grad1; ctx.fillRect(0, 0, w * mp.vol, h);
|
ctx.fillStyle = grad1; ctx.fillRect(0, 0, w * mp.vol, h);
|
||||||
|
@ -430,6 +461,8 @@ function seek_au_sec(seek) {
|
||||||
// ogv.js breaks on .play() during playback
|
// ogv.js breaks on .play() during playback
|
||||||
if (mp.au === mp.au_native)
|
if (mp.au === mp.au_native)
|
||||||
mp.au.play();
|
mp.au.play();
|
||||||
|
|
||||||
|
mpui.progress_updater();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -443,6 +476,14 @@ function song_skip(n) {
|
||||||
else
|
else
|
||||||
play(mp.order[n == -1 ? mp.order.length - 1 : 0]);
|
play(mp.order[n == -1 ? mp.order.length - 1 : 0]);
|
||||||
}
|
}
|
||||||
|
function next_song(e) {
|
||||||
|
ev(e);
|
||||||
|
return song_skip(1);
|
||||||
|
}
|
||||||
|
function prev_song(e) {
|
||||||
|
ev(e);
|
||||||
|
return song_skip(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function playpause(e) {
|
function playpause(e) {
|
||||||
|
@ -452,6 +493,8 @@ function playpause(e) {
|
||||||
mp.au.play();
|
mp.au.play();
|
||||||
else
|
else
|
||||||
mp.au.pause();
|
mp.au.pause();
|
||||||
|
|
||||||
|
mpui.progress_updater();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
play(0);
|
play(0);
|
||||||
|
@ -461,14 +504,8 @@ function playpause(e) {
|
||||||
// hook up the widget buttons
|
// hook up the widget buttons
|
||||||
(function () {
|
(function () {
|
||||||
ebi('bplay').onclick = playpause;
|
ebi('bplay').onclick = playpause;
|
||||||
ebi('bprev').onclick = function (e) {
|
ebi('bprev').onclick = prev_song;
|
||||||
ev(e);
|
ebi('bnext').onclick = next_song;
|
||||||
song_skip(-1);
|
|
||||||
};
|
|
||||||
ebi('bnext').onclick = function (e) {
|
|
||||||
ev(e);
|
|
||||||
song_skip(1);
|
|
||||||
};
|
|
||||||
ebi('barpos').onclick = function (e) {
|
ebi('barpos').onclick = function (e) {
|
||||||
if (!mp.au) {
|
if (!mp.au) {
|
||||||
return play(0);
|
return play(0);
|
||||||
|
@ -483,42 +520,54 @@ function playpause(e) {
|
||||||
|
|
||||||
|
|
||||||
// periodic tasks
|
// periodic tasks
|
||||||
(function () {
|
var mpui = (function () {
|
||||||
var nth = 0,
|
var r = {},
|
||||||
last_skip_url = '';
|
nth = 0,
|
||||||
|
timeout = null,
|
||||||
|
preloaded = null;
|
||||||
|
|
||||||
|
r.progress_updater = function () {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
|
||||||
var progress_updater = function () {
|
|
||||||
if (!mp.au) {
|
if (!mp.au) {
|
||||||
widget.paused(true);
|
widget.paused(true);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// indicate playback state in ui
|
|
||||||
widget.paused(mp.au.paused);
|
|
||||||
|
|
||||||
// draw current position in song
|
// indicate playback state in ui
|
||||||
if (!mp.au.paused)
|
widget.paused(mp.au.paused);
|
||||||
pbar.drawpos();
|
|
||||||
|
|
||||||
// occasionally draw buffered regions
|
// draw current position in song
|
||||||
if (++nth == 10) {
|
if (!mp.au.paused)
|
||||||
pbar.drawbuf();
|
pbar.drawpos();
|
||||||
nth = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// switch to next track if approaching the end
|
// occasionally draw buffered regions
|
||||||
if (last_skip_url != mp.au.src) {
|
if (++nth == 5) {
|
||||||
var pos = mp.au.currentTime,
|
pbar.drawbuf();
|
||||||
len = mp.au.duration;
|
nth = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (pos > 0 && pos > len - 0.1) {
|
// preload next song
|
||||||
last_skip_url = mp.au.src;
|
if (mpl.preload && preloaded != mp.au.src) {
|
||||||
song_skip(1);
|
var pos = mp.au.currentTime,
|
||||||
|
len = mp.au.duration;
|
||||||
|
|
||||||
|
if (pos > 0 && pos > len - 10) {
|
||||||
|
preloaded = mp.au.src;
|
||||||
|
try {
|
||||||
|
mp.preload(ebi(mp.order[mp.order.indexOf(mp.au.tid) + 1]).href);
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
console.log("preload failed", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setTimeout(progress_updater, 100);
|
|
||||||
|
if (!mp.au.paused)
|
||||||
|
timeout = setTimeout(r.progress_updater, 100);
|
||||||
};
|
};
|
||||||
progress_updater();
|
r.progress_updater();
|
||||||
|
return r;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
@ -545,6 +594,11 @@ try {
|
||||||
catch (ex) { }
|
catch (ex) { }
|
||||||
|
|
||||||
|
|
||||||
|
function need_ogv_for(url) {
|
||||||
|
return need_ogv && /\.(ogg|opus)$/i.test(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var audio_eq = (function () {
|
var audio_eq = (function () {
|
||||||
var r = {
|
var r = {
|
||||||
"en": false,
|
"en": false,
|
||||||
|
@ -708,7 +762,7 @@ var audio_eq = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
var html = ['<table><tr><td rowspan="4">',
|
var html = ['<table><tr><td rowspan="4">',
|
||||||
'<a id="au_eq" class="tgl btn" href="#">enable</a></td>'],
|
'<a id="au_eq" class="tgl btn" href="#" tt="enables the equalizer and gain control">enable</a></td>'],
|
||||||
h2 = [], h3 = [], h4 = [];
|
h2 = [], h3 = [], h4 = [];
|
||||||
|
|
||||||
var vs = [];
|
var vs = [];
|
||||||
|
@ -772,7 +826,7 @@ function play(tid, seek, call_depth) {
|
||||||
tn = 0;
|
tn = 0;
|
||||||
}
|
}
|
||||||
else if (mpl.pb_mode == 'next-folder') {
|
else if (mpl.pb_mode == 'next-folder') {
|
||||||
treectl.ls_cb = function () { song_skip(1); };
|
treectl.ls_cb = next_song;
|
||||||
return tree_neigh(1);
|
return tree_neigh(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -782,7 +836,7 @@ function play(tid, seek, call_depth) {
|
||||||
tn = mp.order.length - 1;
|
tn = mp.order.length - 1;
|
||||||
}
|
}
|
||||||
else if (mpl.pb_mode == 'next-folder') {
|
else if (mpl.pb_mode == 'next-folder') {
|
||||||
treectl.ls_cb = function () { song_skip(-1); };
|
treectl.ls_cb = prev_song;
|
||||||
return tree_neigh(-1);
|
return tree_neigh(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -798,7 +852,7 @@ function play(tid, seek, call_depth) {
|
||||||
var attempt_play = true;
|
var attempt_play = true;
|
||||||
|
|
||||||
var url = mp.tracks[tid];
|
var url = mp.tracks[tid];
|
||||||
if (need_ogv && /\.(ogg|opus)$/i.test(url)) {
|
if (need_ogv_for(url)) {
|
||||||
if (mp.au_ogvjs) {
|
if (mp.au_ogvjs) {
|
||||||
mp.au = mp.au_ogvjs;
|
mp.au = mp.au_ogvjs;
|
||||||
}
|
}
|
||||||
|
@ -806,7 +860,8 @@ function play(tid, seek, call_depth) {
|
||||||
mp.au = mp.au_ogvjs = new OGVPlayer();
|
mp.au = mp.au_ogvjs = new OGVPlayer();
|
||||||
attempt_play = false;
|
attempt_play = false;
|
||||||
mp.au.addEventListener('error', evau_error, true);
|
mp.au.addEventListener('error', evau_error, true);
|
||||||
mp.au.addEventListener('progress', pbar.drawpos, false);
|
mp.au.addEventListener('progress', pbar.drawpos);
|
||||||
|
mp.au.addEventListener('ended', next_song);
|
||||||
widget.open();
|
widget.open();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -826,7 +881,8 @@ function play(tid, seek, call_depth) {
|
||||||
if (!mp.au_native) {
|
if (!mp.au_native) {
|
||||||
mp.au = mp.au_native = new Audio();
|
mp.au = mp.au_native = new Audio();
|
||||||
mp.au.addEventListener('error', evau_error, true);
|
mp.au.addEventListener('error', evau_error, true);
|
||||||
mp.au.addEventListener('progress', pbar.drawpos, false);
|
mp.au.addEventListener('progress', pbar.drawpos);
|
||||||
|
mp.au.addEventListener('ended', next_song);
|
||||||
widget.open();
|
widget.open();
|
||||||
}
|
}
|
||||||
mp.au = mp.au_native;
|
mp.au = mp.au_native;
|
||||||
|
@ -835,7 +891,7 @@ function play(tid, seek, call_depth) {
|
||||||
audio_eq.apply();
|
audio_eq.apply();
|
||||||
|
|
||||||
mp.au.tid = tid;
|
mp.au.tid = tid;
|
||||||
mp.au.src = url;
|
mp.au.src = url + (url.indexOf('?') < 0 ? '?cache' : '&cache');
|
||||||
mp.au.volume = mp.expvol();
|
mp.au.volume = mp.expvol();
|
||||||
var oid = 'a' + tid;
|
var oid = 'a' + tid;
|
||||||
setclass(oid, 'play act');
|
setclass(oid, 'play act');
|
||||||
|
@ -844,7 +900,9 @@ function play(tid, seek, call_depth) {
|
||||||
clmod(trs[a], 'play');
|
clmod(trs[a], 'play');
|
||||||
}
|
}
|
||||||
ebi(oid).parentElement.parentElement.className += ' play';
|
ebi(oid).parentElement.parentElement.className += ' play';
|
||||||
clmod(ebi('wtoggle'), 'np', 1);
|
clmod(ebi('wtoggle'), 'np', mpl.clip);
|
||||||
|
if (window.thegrid)
|
||||||
|
thegrid.loadsel();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (attempt_play)
|
if (attempt_play)
|
||||||
|
@ -868,6 +926,7 @@ function play(tid, seek, call_depth) {
|
||||||
o.setAttribute('id', oid);
|
o.setAttribute('id', oid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mpui.progress_updater();
|
||||||
pbar.drawbuf();
|
pbar.drawbuf();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -875,7 +934,7 @@ function play(tid, seek, call_depth) {
|
||||||
alert('playback failed: ' + ex);
|
alert('playback failed: ' + ex);
|
||||||
}
|
}
|
||||||
setclass(oid, 'play');
|
setclass(oid, 'play');
|
||||||
setTimeout('song_skip(1));', 500);
|
setTimeout(next_song, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -949,6 +1008,8 @@ function autoplay_blocked(seek) {
|
||||||
mp.au.play();
|
mp.au.play();
|
||||||
if (seek)
|
if (seek)
|
||||||
seek_au_sec(seek);
|
seek_au_sec(seek);
|
||||||
|
else
|
||||||
|
mpui.progress_updater();
|
||||||
};
|
};
|
||||||
na.onclick = unblocked;
|
na.onclick = unblocked;
|
||||||
}
|
}
|
||||||
|
@ -982,9 +1043,9 @@ var thegrid = (function () {
|
||||||
gfiles.style.display = 'none';
|
gfiles.style.display = 'none';
|
||||||
gfiles.innerHTML = (
|
gfiles.innerHTML = (
|
||||||
'<div id="ghead">' +
|
'<div id="ghead">' +
|
||||||
'<a href="#" class="tgl btn" id="gridsel">multiselect</a> zoom ' +
|
'<a href="#" class="tgl btn" id="gridsel" tt="enable file selection; ctrl-click a file to override$NHotkey: S">multiselect</a> zoom ' +
|
||||||
'<a href="#" class="btn" z="-1.2">–</a> ' +
|
'<a href="#" class="btn" z="-1.2" tt="Hotkey: A">–</a> ' +
|
||||||
'<a href="#" class="btn" z="1.2">+</a> sort by: ' +
|
'<a href="#" class="btn" z="1.2" tt="Hotkey: D">+</a> sort by: ' +
|
||||||
'<a href="#" s="href">name</a>, ' +
|
'<a href="#" s="href">name</a>, ' +
|
||||||
'<a href="#" s="sz">size</a>, ' +
|
'<a href="#" s="sz">size</a>, ' +
|
||||||
'<a href="#" s="ts">date</a>, ' +
|
'<a href="#" s="ts">date</a>, ' +
|
||||||
|
@ -1007,9 +1068,7 @@ var thegrid = (function () {
|
||||||
ev(e);
|
ev(e);
|
||||||
r.thumbs = !r.thumbs;
|
r.thumbs = !r.thumbs;
|
||||||
bcfg_set('thumbs', r.thumbs);
|
bcfg_set('thumbs', r.thumbs);
|
||||||
if (r.en) {
|
r.setdirty();
|
||||||
loadgrid();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ebi('griden').onclick = function (e) {
|
ebi('griden').onclick = function (e) {
|
||||||
|
@ -1097,6 +1156,9 @@ var thegrid = (function () {
|
||||||
}
|
}
|
||||||
|
|
||||||
r.loadsel = function () {
|
r.loadsel = function () {
|
||||||
|
if (r.dirty)
|
||||||
|
return;
|
||||||
|
|
||||||
var ths = QSA('#ggrid>a'),
|
var ths = QSA('#ggrid>a'),
|
||||||
have_sel = !!QS('#files tr.sel');
|
have_sel = !!QS('#files tr.sel');
|
||||||
|
|
||||||
|
@ -1115,6 +1177,9 @@ var thegrid = (function () {
|
||||||
if (have_webp === null)
|
if (have_webp === null)
|
||||||
return setTimeout(loadgrid, 50);
|
return setTimeout(loadgrid, 50);
|
||||||
|
|
||||||
|
lfiles.style.display = 'none';
|
||||||
|
gfiles.style.display = 'block';
|
||||||
|
|
||||||
if (!r.dirty)
|
if (!r.dirty)
|
||||||
return r.loadsel();
|
return r.loadsel();
|
||||||
|
|
||||||
|
@ -1156,9 +1221,8 @@ var thegrid = (function () {
|
||||||
html.push('<a href="' + href + '" ref="' + ref + '"><img src="' +
|
html.push('<a href="' + href + '" ref="' + ref + '"><img src="' +
|
||||||
ihref + '" /><span' + ac + '>' + ao.innerHTML + '</span></a>');
|
ihref + '" /><span' + ac + '>' + ao.innerHTML + '</span></a>');
|
||||||
}
|
}
|
||||||
lfiles.style.display = 'none';
|
|
||||||
gfiles.style.display = 'block';
|
|
||||||
ebi('ggrid').innerHTML = html.join('\n');
|
ebi('ggrid').innerHTML = html.join('\n');
|
||||||
|
r.dirty = false;
|
||||||
r.bagit();
|
r.bagit();
|
||||||
r.loadsel();
|
r.loadsel();
|
||||||
}
|
}
|
||||||
|
@ -1201,7 +1265,10 @@ var thegrid = (function () {
|
||||||
function tree_neigh(n) {
|
function tree_neigh(n) {
|
||||||
var links = QSA('#treeul li>a+a');
|
var links = QSA('#treeul li>a+a');
|
||||||
if (!links.length) {
|
if (!links.length) {
|
||||||
alert('switch to the tree for that');
|
treectl.dir_cb = function () {
|
||||||
|
tree_neigh(n);
|
||||||
|
};
|
||||||
|
treectl.entree();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var act = -1;
|
var act = -1;
|
||||||
|
@ -1227,7 +1294,8 @@ function tree_neigh(n) {
|
||||||
function tree_up() {
|
function tree_up() {
|
||||||
var act = QS('#treeul a.hl');
|
var act = QS('#treeul a.hl');
|
||||||
if (!act) {
|
if (!act) {
|
||||||
alert('switch to the tree for that');
|
treectl.dir_cb = tree_up;
|
||||||
|
treectl.entree();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (act.previousSibling.textContent == '-')
|
if (act.previousSibling.textContent == '-')
|
||||||
|
@ -1255,7 +1323,7 @@ document.onkeydown = function (e) {
|
||||||
if (n !== 0)
|
if (n !== 0)
|
||||||
return song_skip(n);
|
return song_skip(n);
|
||||||
|
|
||||||
if (k == 'KeyM')
|
if (k == 'KeyP')
|
||||||
return playpause();
|
return playpause();
|
||||||
|
|
||||||
n = k == 'KeyU' ? -10 : k == 'KeyO' ? 10 : 0;
|
n = k == 'KeyU' ? -10 : k == 'KeyO' ? 10 : 0;
|
||||||
|
@ -1266,9 +1334,13 @@ document.onkeydown = function (e) {
|
||||||
if (n !== 0)
|
if (n !== 0)
|
||||||
return tree_neigh(n);
|
return tree_neigh(n);
|
||||||
|
|
||||||
if (k == 'KeyP')
|
if (k == 'KeyM')
|
||||||
return tree_up();
|
return tree_up();
|
||||||
|
|
||||||
|
if (k == 'KeyB')
|
||||||
|
//return treectl.hidden ? treectl.show() : treectl.hide();
|
||||||
|
return treectl.hidden ? treectl.entree() : treectl.detree();
|
||||||
|
|
||||||
if (k == 'KeyG')
|
if (k == 'KeyG')
|
||||||
return ebi('griden').click();
|
return ebi('griden').click();
|
||||||
|
|
||||||
|
@ -1318,6 +1390,7 @@ document.onkeydown = function (e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
var trs = [],
|
var trs = [],
|
||||||
|
orig_url = null,
|
||||||
orig_html = null;
|
orig_html = null;
|
||||||
|
|
||||||
for (var a = 0; a < sconf.length; a++) {
|
for (var a = 0; a < sconf.length; a++) {
|
||||||
|
@ -1470,17 +1543,7 @@ document.onkeydown = function (e) {
|
||||||
if (ofiles.getAttribute('ts') > this.ts)
|
if (ofiles.getAttribute('ts') > this.ts)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!oldcfg.length) {
|
treectl.hide();
|
||||||
oldcfg = [
|
|
||||||
ebi('path').style.display,
|
|
||||||
ebi('tree').style.display,
|
|
||||||
ebi('wrap').style.marginLeft
|
|
||||||
];
|
|
||||||
ebi('path').style.display = 'none';
|
|
||||||
ebi('tree').style.display = 'none';
|
|
||||||
ebi('wrap').style.marginLeft = '0';
|
|
||||||
treectl.hidden = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
var html = mk_files_header(tagord);
|
var html = mk_files_header(tagord);
|
||||||
html.push('<tbody>');
|
html.push('<tbody>');
|
||||||
|
@ -1516,25 +1579,23 @@ document.onkeydown = function (e) {
|
||||||
html.push('</td></tr>');
|
html.push('</td></tr>');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!orig_html)
|
if (!orig_html || orig_url != get_evpath()) {
|
||||||
orig_html = ebi('files').innerHTML;
|
orig_html = ebi('files').innerHTML;
|
||||||
|
orig_url = get_evpath();
|
||||||
|
}
|
||||||
|
|
||||||
ofiles.innerHTML = html.join('\n');
|
ofiles.innerHTML = html.join('\n');
|
||||||
ofiles.setAttribute("ts", this.ts);
|
ofiles.setAttribute("ts", this.ts);
|
||||||
filecols.set_style();
|
|
||||||
mukey.render();
|
mukey.render();
|
||||||
reload_browser();
|
reload_browser();
|
||||||
|
filecols.set_style(['File Name']);
|
||||||
|
|
||||||
ebi('unsearch').onclick = unsearch;
|
ebi('unsearch').onclick = unsearch;
|
||||||
}
|
}
|
||||||
|
|
||||||
function unsearch(e) {
|
function unsearch(e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
ebi('path').style.display = oldcfg[0];
|
treectl.show();
|
||||||
ebi('tree').style.display = oldcfg[1];
|
|
||||||
ebi('wrap').style.marginLeft = oldcfg[2];
|
|
||||||
treectl.hidden = false;
|
|
||||||
oldcfg = [];
|
|
||||||
ebi('files').innerHTML = orig_html;
|
ebi('files').innerHTML = orig_html;
|
||||||
orig_html = null;
|
orig_html = null;
|
||||||
msel.render();
|
msel.render();
|
||||||
|
@ -1545,8 +1606,9 @@ document.onkeydown = function (e) {
|
||||||
|
|
||||||
var treectl = (function () {
|
var treectl = (function () {
|
||||||
var treectl = {
|
var treectl = {
|
||||||
"hidden": false,
|
"hidden": true,
|
||||||
"ls_cb": null
|
"ls_cb": null,
|
||||||
|
"dir_cb": null
|
||||||
},
|
},
|
||||||
entreed = false,
|
entreed = false,
|
||||||
fixedpos = false,
|
fixedpos = false,
|
||||||
|
@ -1557,28 +1619,42 @@ var treectl = (function () {
|
||||||
|
|
||||||
treesz = Math.min(Math.max(treesz, 4), 50);
|
treesz = Math.min(Math.max(treesz, 4), 50);
|
||||||
|
|
||||||
function entree(e) {
|
treectl.entree = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
entreed = true;
|
entreed = true;
|
||||||
ebi('path').style.display = 'none';
|
|
||||||
|
|
||||||
var tree = ebi('tree');
|
|
||||||
tree.style.display = 'block';
|
|
||||||
|
|
||||||
swrite('entreed', 'tree');
|
swrite('entreed', 'tree');
|
||||||
|
|
||||||
get_tree("", get_evpath(), true);
|
get_tree("", get_evpath(), true);
|
||||||
|
treectl.show();
|
||||||
|
}
|
||||||
|
|
||||||
|
treectl.show = function () {
|
||||||
|
treectl.hidden = false;
|
||||||
|
if (!entreed) {
|
||||||
|
ebi('path').style.display = 'inline-block';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ebi('path').style.display = 'none';
|
||||||
|
ebi('tree').style.display = 'block';
|
||||||
window.addEventListener('scroll', onscroll);
|
window.addEventListener('scroll', onscroll);
|
||||||
window.addEventListener('resize', onresize);
|
window.addEventListener('resize', onresize);
|
||||||
onresize();
|
onresize();
|
||||||
}
|
};
|
||||||
|
|
||||||
function detree(e) {
|
treectl.detree = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
entreed = false;
|
entreed = false;
|
||||||
ebi('tree').style.display = 'none';
|
|
||||||
ebi('path').style.display = 'inline-block';
|
|
||||||
ebi('wrap').style.marginLeft = '0';
|
|
||||||
swrite('entreed', 'na');
|
swrite('entreed', 'na');
|
||||||
|
|
||||||
|
treectl.hide();
|
||||||
|
ebi('path').style.display = 'inline-block';
|
||||||
|
}
|
||||||
|
|
||||||
|
treectl.hide = function () {
|
||||||
|
treectl.hidden = true;
|
||||||
|
ebi('path').style.display = 'none';
|
||||||
|
ebi('tree').style.display = 'none';
|
||||||
|
ebi('wrap').style.marginLeft = '0';
|
||||||
window.removeEventListener('resize', onresize);
|
window.removeEventListener('resize', onresize);
|
||||||
window.removeEventListener('scroll', onscroll);
|
window.removeEventListener('scroll', onscroll);
|
||||||
}
|
}
|
||||||
|
@ -1714,6 +1790,12 @@ var treectl = (function () {
|
||||||
despin('#tree');
|
despin('#tree');
|
||||||
reload_tree();
|
reload_tree();
|
||||||
onresize();
|
onresize();
|
||||||
|
|
||||||
|
var fun = treectl.dir_cb;
|
||||||
|
if (fun) {
|
||||||
|
treectl.dir_cb = null;
|
||||||
|
fun();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function reload_tree() {
|
function reload_tree() {
|
||||||
|
@ -1901,13 +1983,13 @@ var treectl = (function () {
|
||||||
onresize();
|
onresize();
|
||||||
}
|
}
|
||||||
|
|
||||||
ebi('entree').onclick = entree;
|
ebi('entree').onclick = treectl.entree;
|
||||||
ebi('detree').onclick = detree;
|
ebi('detree').onclick = treectl.detree;
|
||||||
ebi('dyntree').onclick = dyntree;
|
ebi('dyntree').onclick = dyntree;
|
||||||
ebi('twig').onclick = scaletree;
|
ebi('twig').onclick = scaletree;
|
||||||
ebi('twobytwo').onclick = scaletree;
|
ebi('twobytwo').onclick = scaletree;
|
||||||
if (sread('entreed') == 'tree')
|
if (sread('entreed') == 'tree')
|
||||||
entree();
|
treectl.entree();
|
||||||
|
|
||||||
window.onpopstate = function (e) {
|
window.onpopstate = function (e) {
|
||||||
console.log("h-pop " + e.state);
|
console.log("h-pop " + e.state);
|
||||||
|
@ -2055,9 +2137,12 @@ var filecols = (function () {
|
||||||
toggle(t.textContent);
|
toggle(t.textContent);
|
||||||
}
|
}
|
||||||
|
|
||||||
var set_style = function () {
|
var set_style = function (unhide) {
|
||||||
hidden.sort();
|
hidden.sort();
|
||||||
|
|
||||||
|
if (!unhide)
|
||||||
|
unhide = [];
|
||||||
|
|
||||||
var html = [],
|
var html = [],
|
||||||
hcols = ebi('hcols');
|
hcols = ebi('hcols');
|
||||||
|
|
||||||
|
@ -2082,7 +2167,7 @@ var filecols = (function () {
|
||||||
var name = span[0].textContent,
|
var name = span[0].textContent,
|
||||||
cls = false;
|
cls = false;
|
||||||
|
|
||||||
if (has(hidden, name)) {
|
if (has(hidden, name) && !has(unhide, name)) {
|
||||||
ohidden.push(a);
|
ohidden.push(a);
|
||||||
cls = true;
|
cls = true;
|
||||||
}
|
}
|
||||||
|
@ -2254,34 +2339,15 @@ function addcrc() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var light;
|
||||||
(function () {
|
(function () {
|
||||||
var tt = bcfg_get('tooltips', true);
|
light = bcfg_get('lightmode', false);
|
||||||
|
|
||||||
function set_tooltip(e) {
|
|
||||||
ev(e);
|
|
||||||
var o = ebi('opdesc');
|
|
||||||
o.innerHTML = this.getAttribute('data-desc');
|
|
||||||
o.setAttribute('class', tt ? '' : 'off');
|
|
||||||
}
|
|
||||||
|
|
||||||
var btns = QSA('#ops, #ops>a');
|
|
||||||
for (var a = 0; a < btns.length; a++) {
|
|
||||||
btns[a].onmouseenter = set_tooltip;
|
|
||||||
}
|
|
||||||
|
|
||||||
ebi('tooltips').onclick = function (e) {
|
|
||||||
ev(e);
|
|
||||||
tt = !tt;
|
|
||||||
bcfg_set('tooltips', tt);
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
|
||||||
(function () {
|
|
||||||
var light = bcfg_get('lightmode', false);
|
|
||||||
|
|
||||||
function freshen() {
|
function freshen() {
|
||||||
document.documentElement.setAttribute("class", light ? "light" : "");
|
document.documentElement.setAttribute("class", light ? "light" : "");
|
||||||
|
pbar.drawbuf();
|
||||||
|
pbar.drawpos();
|
||||||
|
vbar.draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
ebi('lightmode').onclick = function (e) {
|
ebi('lightmode').onclick = function (e) {
|
||||||
|
@ -2300,24 +2366,35 @@ var arcfmt = (function () {
|
||||||
return { "render": function () { } };
|
return { "render": function () { } };
|
||||||
|
|
||||||
var html = [],
|
var html = [],
|
||||||
arcfmts = ["tar", "zip", "zip_dos", "zip_crc"],
|
fmts = [
|
||||||
arcv = ["tar", "zip=utf8", "zip", "zip=crc"];
|
["tar", "tar", "plain gnutar file"],
|
||||||
|
["zip", "zip=utf8", "zip with utf8 filenames (maybe wonky on windows 7 and older)"],
|
||||||
|
["zip_dos", "zip", "zip with traditional cp437 filenames, for really old software"],
|
||||||
|
["zip_crc", "zip=crc", "cp437 with crc32 computed early for truly ancient software$N(takes longer to process before download can start)"]
|
||||||
|
];
|
||||||
|
|
||||||
for (var a = 0; a < arcfmts.length; a++) {
|
for (var a = 0; a < fmts.length; a++) {
|
||||||
var k = arcfmts[a];
|
var k = fmts[a][0];
|
||||||
html.push(
|
html.push(
|
||||||
'<span><input type="radio" name="arcfmt" value="' + k + '" id="arcfmt_' + k + '">' +
|
'<span><input type="radio" name="arcfmt" value="' + k + '" id="arcfmt_' + k + '" tt="' + fmts[a][2] + '">' +
|
||||||
'<label for="arcfmt_' + k + '">' + k + '</label></span>');
|
'<label for="arcfmt_' + k + '" tt="' + fmts[a][2] + '">' + k + '</label></span>');
|
||||||
}
|
}
|
||||||
ebi('arc_fmt').innerHTML = html.join('\n');
|
ebi('arc_fmt').innerHTML = html.join('\n');
|
||||||
|
|
||||||
var fmt = sread("arc_fmt") || "zip";
|
var fmt = sread("arc_fmt");
|
||||||
|
if (!ebi('arcfmt_' + fmt))
|
||||||
|
fmt = "zip";
|
||||||
|
|
||||||
ebi('arcfmt_' + fmt).checked = true;
|
ebi('arcfmt_' + fmt).checked = true;
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var arg = arcv[arcfmts.indexOf(fmt)],
|
var arg = null,
|
||||||
tds = QSA('#files tbody td:first-child a');
|
tds = QSA('#files tbody td:first-child a');
|
||||||
|
|
||||||
|
for (var a = 0; a < fmts.length; a++)
|
||||||
|
if (fmts[a][0] == fmt)
|
||||||
|
arg = fmts[a][1];
|
||||||
|
|
||||||
for (var a = 0, aa = tds.length; a < aa; a++) {
|
for (var a = 0, aa = tds.length; a < aa; a++) {
|
||||||
var o = tds[a], txt = o.textContent, href = o.getAttribute('href');
|
var o = tds[a], txt = o.textContent, href = o.getAttribute('href');
|
||||||
if (txt != 'tar' && txt != 'zip')
|
if (txt != 'tar' && txt != 'zip')
|
||||||
|
|
|
@ -1278,31 +1278,11 @@ function up2k_init(subtle) {
|
||||||
window.addEventListener('resize', onresize);
|
window.addEventListener('resize', onresize);
|
||||||
onresize();
|
onresize();
|
||||||
|
|
||||||
function desc_show(e) {
|
var o = QSA('#u2conf *[tt]');
|
||||||
var cfg = sread('tooltips');
|
|
||||||
if (cfg !== null && cfg != '1')
|
|
||||||
return;
|
|
||||||
|
|
||||||
var msg = this.getAttribute('alt'),
|
|
||||||
cdesc = ebi('u2cdesc');
|
|
||||||
|
|
||||||
cdesc.innerHTML = msg.replace(/\$N/g, "<br />");
|
|
||||||
cdesc.setAttribute('class', 'show');
|
|
||||||
}
|
|
||||||
function desc_hide(e) {
|
|
||||||
ebi('u2cdesc').setAttribute('class', '');
|
|
||||||
}
|
|
||||||
var o = QSA('#u2conf *[alt]');
|
|
||||||
for (var a = o.length - 1; a >= 0; a--) {
|
for (var a = o.length - 1; a >= 0; a--) {
|
||||||
o[a].parentNode.getElementsByTagName('input')[0].setAttribute('alt', o[a].getAttribute('alt'));
|
o[a].parentNode.getElementsByTagName('input')[0].setAttribute('tt', o[a].getAttribute('tt'));
|
||||||
}
|
|
||||||
var o = QSA('#u2conf *[alt]');
|
|
||||||
for (var a = 0; a < o.length; a++) {
|
|
||||||
o[a].onfocus = desc_show;
|
|
||||||
o[a].onblur = desc_hide;
|
|
||||||
o[a].onmouseenter = desc_show;
|
|
||||||
o[a].onmouseleave = desc_hide;
|
|
||||||
}
|
}
|
||||||
|
tt.init();
|
||||||
|
|
||||||
function bumpthread(dir) {
|
function bumpthread(dir) {
|
||||||
try {
|
try {
|
||||||
|
@ -1450,5 +1430,7 @@ function warn_uploader_busy(e) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
tt.init();
|
||||||
|
|
||||||
if (QS('#op_up2k.act'))
|
if (QS('#op_up2k.act'))
|
||||||
goto_up2k();
|
goto_up2k();
|
||||||
|
|
|
@ -211,29 +211,6 @@
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
opacity: .2;
|
opacity: .2;
|
||||||
}
|
}
|
||||||
#u2cdesc {
|
|
||||||
position: absolute;
|
|
||||||
width: 34em;
|
|
||||||
left: calc(50% - 15em);
|
|
||||||
background: #222;
|
|
||||||
border: 0 solid #555;
|
|
||||||
text-align: center;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0 -2em;
|
|
||||||
padding: 0 1em;
|
|
||||||
height: 0;
|
|
||||||
opacity: .1;
|
|
||||||
transition: all 0.14s ease-in-out;
|
|
||||||
box-shadow: 0 .2em .5em #222;
|
|
||||||
border-radius: .4em;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
#u2cdesc.show {
|
|
||||||
padding: 1em;
|
|
||||||
height: auto;
|
|
||||||
border-width: .2em 0;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
#u2foot {
|
#u2foot {
|
||||||
color: #fff;
|
color: #fff;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
@ -286,10 +263,6 @@ html.light #u2conf .txtbox.err {
|
||||||
background: #f96;
|
background: #f96;
|
||||||
color: #300;
|
color: #300;
|
||||||
}
|
}
|
||||||
html.light #u2cdesc {
|
|
||||||
background: #fff;
|
|
||||||
border: none;
|
|
||||||
}
|
|
||||||
html.light #op_up2k.srch #u2btn {
|
html.light #op_up2k.srch #u2btn {
|
||||||
border-color: #a80;
|
border-color: #a80;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,20 +39,20 @@
|
||||||
<td><br />parallel uploads:</td>
|
<td><br />parallel uploads:</td>
|
||||||
<td rowspan="2">
|
<td rowspan="2">
|
||||||
<input type="checkbox" id="multitask" />
|
<input type="checkbox" id="multitask" />
|
||||||
<label for="multitask" alt="continue hashing other files while uploading">🏃</label>
|
<label for="multitask" tt="continue hashing other files while uploading">🏃</label>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2">
|
<td rowspan="2">
|
||||||
<input type="checkbox" id="ask_up" />
|
<input type="checkbox" id="ask_up" />
|
||||||
<label for="ask_up" alt="ask for confirmation befofre upload starts">💭</label>
|
<label for="ask_up" tt="ask for confirmation befofre upload starts">💭</label>
|
||||||
</td>
|
</td>
|
||||||
<td rowspan="2">
|
<td rowspan="2">
|
||||||
<input type="checkbox" id="flag_en" />
|
<input type="checkbox" id="flag_en" />
|
||||||
<label for="flag_en" alt="ensure only one tab is uploading at a time $N (other tabs must have this enabled too)">💤</label>
|
<label for="flag_en" tt="ensure only one tab is uploading at a time $N (other tabs must have this enabled too)">💤</label>
|
||||||
</td>
|
</td>
|
||||||
{%- if have_up2k_idx %}
|
{%- if have_up2k_idx %}
|
||||||
<td data-perm="read" rowspan="2">
|
<td data-perm="read" rowspan="2">
|
||||||
<input type="checkbox" id="fsearch" />
|
<input type="checkbox" id="fsearch" />
|
||||||
<label for="fsearch" alt="don't actually upload, instead check if the files already $N exist on the server (will scan all folders you can read)">🔎</label>
|
<label for="fsearch" tt="don't actually upload, instead check if the files already $N exist on the server (will scan all folders you can read)">🔎</label>
|
||||||
</td>
|
</td>
|
||||||
{%- endif %}
|
{%- endif %}
|
||||||
<td data-perm="read" rowspan="2" id="u2btn_cw"></td>
|
<td data-perm="read" rowspan="2" id="u2btn_cw"></td>
|
||||||
|
@ -66,8 +66,6 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div id="u2cdesc"></div>
|
|
||||||
|
|
||||||
<div id="u2notbtn"></div>
|
<div id="u2notbtn"></div>
|
||||||
|
|
||||||
<div id="u2btn_ct">
|
<div id="u2btn_ct">
|
||||||
|
@ -80,11 +78,11 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="u2cards">
|
<div id="u2cards">
|
||||||
<a href="#" act="ok">ok <span>0</span></a><a
|
<a href="#" act="ok" tt="completed successfully">ok <span>0</span></a><a
|
||||||
href="#" act="ng">ng <span>0</span></a><a
|
href="#" act="ng" tt="failed / rejected / not-found">ng <span>0</span></a><a
|
||||||
href="#" act="done">done <span>0</span></a><a
|
href="#" act="done" tt="ok and ng combined">done <span>0</span></a><a
|
||||||
href="#" act="bz" class="act">busy <span>0</span></a><a
|
href="#" act="bz" tt="hashing or uploading" class="act">busy <span>0</span></a><a
|
||||||
href="#" act="q">que <span>0</span></a>
|
href="#" act="q" tt="idle, pending">que <span>0</span></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table id="u2tab">
|
<table id="u2tab">
|
||||||
|
@ -92,7 +90,7 @@
|
||||||
<tr>
|
<tr>
|
||||||
<td>filename</td>
|
<td>filename</td>
|
||||||
<td>status</td>
|
<td>status</td>
|
||||||
<td>progress<a href="#" id="u2cleanup">cleanup</a></td>
|
<td>progress<a href="#" id="u2cleanup" tt="remove completed uploads$N(makes it possible to upload a file after searching for it)">cleanup</a></td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody></tbody>
|
<tbody></tbody>
|
||||||
|
|
|
@ -528,3 +528,63 @@ function hist_replace(url) {
|
||||||
console.log("h-repl " + url);
|
console.log("h-repl " + url);
|
||||||
history.replaceState(url, url, url);
|
history.replaceState(url, url, url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var tt = (function () {
|
||||||
|
var r = {
|
||||||
|
"tt": mknod("div"),
|
||||||
|
"en": bcfg_get('tooltips', true),
|
||||||
|
};
|
||||||
|
|
||||||
|
r.tt.setAttribute('id', 'tt');
|
||||||
|
document.body.appendChild(r.tt);
|
||||||
|
|
||||||
|
function show() {
|
||||||
|
var cfg = sread('tooltips');
|
||||||
|
if (cfg !== null && cfg != '1')
|
||||||
|
return;
|
||||||
|
|
||||||
|
var msg = this.getAttribute('tt');
|
||||||
|
if (!msg)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var pos = this.getBoundingClientRect(),
|
||||||
|
left = pos.left < window.innerWidth / 2,
|
||||||
|
top = pos.top < window.innerHeight / 2;
|
||||||
|
|
||||||
|
r.tt.style.top = top ? pos.bottom + 'px' : 'auto';
|
||||||
|
r.tt.style.bottom = top ? 'auto' : (window.innerHeight - pos.top) + 'px';
|
||||||
|
r.tt.style.left = left ? pos.left + 'px' : 'auto';
|
||||||
|
r.tt.style.right = left ? 'auto' : (window.innerWidth - pos.right) + 'px';
|
||||||
|
|
||||||
|
r.tt.innerHTML = msg.replace(/\$N/g, "<br />");
|
||||||
|
clmod(r.tt, 'show', 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
clmod(r.tt, 'show');
|
||||||
|
}
|
||||||
|
|
||||||
|
r.init = function () {
|
||||||
|
var _show = r.en ? show : null,
|
||||||
|
_hide = r.en ? hide : null;
|
||||||
|
|
||||||
|
var o = QSA('*[tt]');
|
||||||
|
for (var a = o.length - 1; a >= 0; a--) {
|
||||||
|
o[a].onfocus = _show;
|
||||||
|
o[a].onblur = _hide;
|
||||||
|
o[a].onmouseenter = _show;
|
||||||
|
o[a].onmouseleave = _hide;
|
||||||
|
}
|
||||||
|
hide();
|
||||||
|
};
|
||||||
|
|
||||||
|
ebi('tooltips').onclick = function (e) {
|
||||||
|
ev(e);
|
||||||
|
r.en = !r.en;
|
||||||
|
bcfg_set('tooltips', r.en);
|
||||||
|
r.init();
|
||||||
|
};
|
||||||
|
|
||||||
|
return r;
|
||||||
|
})();
|
||||||
|
|
|
@ -92,20 +92,34 @@ chmod 755 \
|
||||||
copyparty-extras/copyparty-*/{scripts,bin}/*
|
copyparty-extras/copyparty-*/{scripts,bin}/*
|
||||||
|
|
||||||
|
|
||||||
# extract and repack the sfx with less features enabled
|
# extract the sfx
|
||||||
( cd copyparty-extras/sfx-full/
|
( cd copyparty-extras/sfx-full/
|
||||||
./copyparty-sfx.py -h
|
./copyparty-sfx.py -h
|
||||||
cd ../copyparty-*/
|
|
||||||
./scripts/make-sfx.sh re no-ogv no-cm
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
# put new sfx into copyparty-extras/sfx-lite/,
|
repack() {
|
||||||
# fuse client into copyparty-extras/,
|
|
||||||
|
# do the repack
|
||||||
|
(cd copyparty-extras/copyparty-*/
|
||||||
|
./scripts/make-sfx.sh $2
|
||||||
|
)
|
||||||
|
|
||||||
|
# put new sfx into copyparty-extras/$name/,
|
||||||
|
( cd copyparty-extras/
|
||||||
|
mv copyparty-*/dist/* $1/
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
repack sfx-full "re gz no-sh"
|
||||||
|
repack sfx-lite "re no-ogv no-cm"
|
||||||
|
repack sfx-lite "re no-ogv no-cm gz no-sh"
|
||||||
|
|
||||||
|
|
||||||
|
# move fuse client into copyparty-extras/,
|
||||||
# copy lite-sfx.py to ./copyparty,
|
# copy lite-sfx.py to ./copyparty,
|
||||||
# delete extracted source code
|
# delete extracted source code
|
||||||
( cd copyparty-extras/
|
( cd copyparty-extras/
|
||||||
mv copyparty-*/dist/* sfx-lite/
|
|
||||||
mv copyparty-*/bin/copyparty-fuse.py .
|
mv copyparty-*/bin/copyparty-fuse.py .
|
||||||
cp -pv sfx-lite/copyparty-sfx.py ../copyparty
|
cp -pv sfx-lite/copyparty-sfx.py ../copyparty
|
||||||
rm -rf copyparty-{0..9}*.*.*{0..9}
|
rm -rf copyparty-{0..9}*.*.*{0..9}
|
||||||
|
@ -119,6 +133,7 @@ true
|
||||||
|
|
||||||
|
|
||||||
# create the bundle
|
# create the bundle
|
||||||
|
printf '\n\n'
|
||||||
fn=copyparty-$(date +%Y-%m%d-%H%M%S).tgz
|
fn=copyparty-$(date +%Y-%m%d-%H%M%S).tgz
|
||||||
tar -czvf "$od/$fn" *
|
tar -czvf "$od/$fn" *
|
||||||
cd "$od"
|
cd "$od"
|
||||||
|
|
|
@ -11,6 +11,10 @@ echo
|
||||||
# `re` does a repack of an sfx which you already executed once
|
# `re` does a repack of an sfx which you already executed once
|
||||||
# (grabs files from the sfx-created tempdir), overrides `clean`
|
# (grabs files from the sfx-created tempdir), overrides `clean`
|
||||||
#
|
#
|
||||||
|
# `gz` creates a gzip-compressed python sfx instead of bzip2
|
||||||
|
#
|
||||||
|
# `no-sh` makes just the python sfx, skips the sh/unix sfx
|
||||||
|
#
|
||||||
# `no-ogv` saves ~500k by removing the opus/vorbis audio codecs
|
# `no-ogv` saves ~500k by removing the opus/vorbis audio codecs
|
||||||
# (only affects apple devices; everything else has native support)
|
# (only affects apple devices; everything else has native support)
|
||||||
#
|
#
|
||||||
|
|
105
scripts/test/race.py
Normal file
105
scripts/test/race.py
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
import http.client
|
||||||
|
|
||||||
|
|
||||||
|
class Conn(object):
|
||||||
|
def __init__(self, ip, port):
|
||||||
|
self.s = http.client.HTTPConnection(ip, port, timeout=260)
|
||||||
|
self.st = []
|
||||||
|
|
||||||
|
def get(self, vpath):
|
||||||
|
self.st = [time.time()]
|
||||||
|
|
||||||
|
self.s.request("GET", vpath)
|
||||||
|
self.st.append(time.time())
|
||||||
|
|
||||||
|
ret = self.s.getresponse()
|
||||||
|
self.st.append(time.time())
|
||||||
|
|
||||||
|
if ret.status < 200 or ret.status >= 400:
|
||||||
|
raise Exception(ret.status)
|
||||||
|
|
||||||
|
ret = ret.read()
|
||||||
|
self.st.append(time.time())
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
def get_json(self, vpath):
|
||||||
|
ret = self.get(vpath)
|
||||||
|
return json.loads(ret)
|
||||||
|
|
||||||
|
|
||||||
|
class CState(threading.Thread):
|
||||||
|
def __init__(self, cs):
|
||||||
|
threading.Thread.__init__(self)
|
||||||
|
self.daemon = True
|
||||||
|
self.cs = cs
|
||||||
|
self.start()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
colors = [5, 1, 3, 2, 7]
|
||||||
|
remotes = []
|
||||||
|
remotes_ok = False
|
||||||
|
while True:
|
||||||
|
time.sleep(0.001)
|
||||||
|
if not remotes_ok:
|
||||||
|
remotes = []
|
||||||
|
remotes_ok = True
|
||||||
|
for conn in self.cs:
|
||||||
|
try:
|
||||||
|
remotes.append(conn.s.sock.getsockname()[1])
|
||||||
|
except:
|
||||||
|
remotes.append("?")
|
||||||
|
remotes_ok = False
|
||||||
|
|
||||||
|
m = []
|
||||||
|
for conn, remote in zip(self.cs, remotes):
|
||||||
|
stage = len(conn.st)
|
||||||
|
m.append(f"\033[3{colors[stage]}m{remote}")
|
||||||
|
|
||||||
|
m = " ".join(m)
|
||||||
|
print(f"{m}\033[0m\n\033[A", end="")
|
||||||
|
|
||||||
|
|
||||||
|
def allget(cs, urls):
|
||||||
|
thrs = []
|
||||||
|
for c, url in zip(cs, urls):
|
||||||
|
t = threading.Thread(target=c.get, args=(url,))
|
||||||
|
t.start()
|
||||||
|
thrs.append(t)
|
||||||
|
|
||||||
|
for t in thrs:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
os.system("")
|
||||||
|
|
||||||
|
ip, port = sys.argv[1].split(":")
|
||||||
|
port = int(port)
|
||||||
|
|
||||||
|
cs = []
|
||||||
|
for _ in range(64):
|
||||||
|
cs.append(Conn(ip, 3923))
|
||||||
|
|
||||||
|
CState(cs)
|
||||||
|
|
||||||
|
urlbase = "/doujin/c95"
|
||||||
|
j = cs[0].get_json(f"{urlbase}?ls")
|
||||||
|
urls = []
|
||||||
|
for d in j["dirs"]:
|
||||||
|
urls.append(f"{urlbase}/{d['href']}?th=w")
|
||||||
|
|
||||||
|
for n in range(100):
|
||||||
|
print(n)
|
||||||
|
allget(cs, urls)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in a new issue