Compare commits

..

62 Commits

Author SHA1 Message Date
ed
231a03bcfd v0.13.13 2021-09-03 21:21:17 +02:00
ed
bc85723657 more intense compressino 2021-09-03 21:20:40 +02:00
ed
be32b743c6 repl: select default text on load 2021-09-03 20:48:41 +02:00
ed
83c9843059 make-sfx: correct version number on repack 2021-09-03 20:38:41 +02:00
ed
11cf43626d make-sfx: fix no-dd css modifier 2021-09-03 20:38:14 +02:00
ed
a6dc5e2ce3 add some missing preventdefaults 2021-09-03 20:37:30 +02:00
ed
38593a0394 move column hider buttons above the header 2021-09-03 20:19:17 +02:00
ed
95309afeea fix file-list jumping around during uploads 2021-09-03 20:17:44 +02:00
ed
c2bf6fe2a3 add basic authentication 2021-09-03 20:15:24 +02:00
ed
99ac324fbd tweaks 2021-09-02 19:06:08 +02:00
ed
5562de330f slightly smaller jpeg thumbnails 2021-09-02 18:51:15 +02:00
ed
95014236ac js-repl presets 2021-09-02 18:50:47 +02:00
ed
6aa7386138 modals: onDisplay callback 2021-09-02 18:46:51 +02:00
ed
3226a1f588 crashpage: show recent console messages 2021-09-02 18:45:42 +02:00
ed
b4cf890cd8 emphasis 2021-09-02 18:42:53 +02:00
ed
ce09e323af ok/cancel buttons in platform-defined order 2021-09-02 18:42:12 +02:00
ed
941aedb177 v0.13.12 2021-09-01 23:48:01 +02:00
ed
87a0d502a3 crashpage: add useragent 2021-09-01 23:32:27 +02:00
ed
cab7c1b0b8 browser-icons: centered play button 2021-09-01 22:35:27 +02:00
ed
d5892341b6 prevent vertical toast overflow 2021-09-01 22:34:48 +02:00
ed
646557a43e crashpage: better localstore dump 2021-09-01 22:34:04 +02:00
ed
ed8d34ab43 dont try to play audio if js crashed 2021-09-01 22:28:15 +02:00
ed
5e34463c77 support massive cut/paste ops 2021-09-01 22:27:39 +02:00
ed
1b14eb7959 fix thumbnail-zoom hotkeys 2021-09-01 22:26:18 +02:00
ed
ed48c2d0ed v0.13.11 2021-08-30 22:32:16 +02:00
ed
26fe84b660 smaller sfx 2021-08-30 22:27:10 +02:00
ed
5938230270 more tray ui nitpicks 2021-08-30 22:25:07 +02:00
ed
1a33a047fa fix listening on single interface 2021-08-30 21:39:44 +02:00
ed
43a8bcefb9 v0.13.10 2021-08-30 03:02:11 +02:00
ed
2e740e513f cheap performance fix 2021-08-30 02:38:48 +02:00
ed
8a21a86b61 better iOS error-handling 2021-08-30 02:29:38 +02:00
ed
f600116205 login returns to volume listing 2021-08-30 01:55:24 +02:00
ed
1c03705de8 upload filedrops in alphabetical order 2021-08-30 01:50:12 +02:00
ed
f7e461fac6 add humantime 2021-08-30 01:16:20 +02:00
ed
03ce6c97ff better crash-handler ui 2021-08-30 01:15:37 +02:00
ed
ffd9e76e07 select all text in modal.prompt 2021-08-30 01:11:00 +02:00
ed
fc49cb1e67 add js repl 2021-08-30 01:09:27 +02:00
ed
f5712d9f25 v0.13.9 2021-08-29 02:24:09 +02:00
ed
161d57bdda v0.13.8 2021-08-29 01:38:06 +02:00
ed
bae0d440bf upgrade ogvjs to 1.8.4 2021-08-29 01:11:44 +02:00
ed
fff052dde1 explain the magic 2021-08-29 00:11:06 +02:00
ed
73b06eaa02 coerce iOS into playing opus in the background 2021-08-29 00:05:14 +02:00
ed
08a8ebed17 minor cleanup 2021-08-28 22:40:59 +02:00
ed
74d07426b3 make tray tab smaller 2021-08-28 22:37:39 +02:00
ed
69a2bba99a fix ogv.js crashing iOS 2021-08-28 22:35:47 +02:00
ed
4d685d78ee v0.13.7 2021-08-28 04:55:06 +02:00
ed
5845ec3f49 nevermind, nailed it 2021-08-28 04:08:22 +02:00
ed
13373426fe alright fine apple you win 2021-08-28 03:44:07 +02:00
ed
8e55551a06 positioning fixes 2021-08-28 03:27:14 +02:00
ed
12a3f0ac31 update the filetype icons example 2021-08-28 02:56:07 +02:00
ed
18e33edc88 hide tooltips on scroll 2021-08-28 02:46:06 +02:00
ed
c72c5ad4ee make the ellipsis more visible 2021-08-28 02:38:31 +02:00
ed
0fbc81ab2f missed some 2021-08-28 02:37:28 +02:00
ed
af0a34cf82 improve iphone fix 2021-08-28 02:11:40 +02:00
ed
b4590c5398 horizontally centered tooltips 2021-08-28 01:49:21 +02:00
ed
f787a66230 that was dumb 2021-08-28 01:47:36 +02:00
ed
b21a99fd62 only tooltip the ellipsed thumbnails 2021-08-28 01:25:27 +02:00
ed
eb16306cde misc cleanup 2021-08-28 00:03:30 +02:00
ed
7bc23687e3 this kinda broke ellipsing, hopefully not too expensive 2021-08-28 00:02:59 +02:00
ed
e1eaa057f2 optimize clmod 2021-08-27 23:58:23 +02:00
ed
97c264ca3e snappy taps 2021-08-27 23:57:46 +02:00
ed
cf848ab1f7 add ellipsing of thumbnail filename, fixes #3 (+ clamp zoom level) 2021-08-27 23:50:09 +02:00
23 changed files with 790 additions and 260 deletions

View File

@@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (0, 13, 6)
VERSION = (0, 13, 13)
CODENAME = "future-proof"
BUILD_DT = (2021, 8, 27)
BUILD_DT = (2021, 9, 3)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -7,6 +7,7 @@ import gzip
import time
import copy
import json
import base64
import string
import socket
import ctypes
@@ -192,7 +193,21 @@ class HttpCli(object):
self.cookies = cookies
self.vpath = unquotep(vpath) # not query, so + means +
pwd = uparam.get("pw")
pwd = None
ba = self.headers.get("authorization")
if ba:
try:
ba = ba.split(" ")[1].encode("ascii")
ba = base64.b64decode(ba).decode("utf-8")
# try "pwd", "x:pwd", "pwd:x"
for ba in [ba] + ba.split(":", 1)[::-1]:
if self.asrv.iacct.get(ba):
pwd = ba
break
except:
pass
pwd = uparam.get("pw") or pwd
self.uname = self.asrv.iacct.get(pwd, "*")
self.rvol = self.asrv.vfs.aread[self.uname]
self.wvol = self.asrv.vfs.awrite[self.uname]
@@ -873,7 +888,7 @@ class HttpCli(object):
self.parser.drop()
ck, msg = self.get_pwd_cookie(pwd)
html = self.j2("msg", h1=msg, h2='<a href="/">ack</a>', redir="/")
html = self.j2("msg", h1=msg, h2='<a href="/?h">ack</a>', redir="/?h")
self.reply(html.encode("utf-8"), headers={"Set-Cookie": ck})
return True

View File

@@ -177,7 +177,7 @@ class TcpSrv(object):
eps = self.ips_linux()
if "0.0.0.0" not in listen_ips:
eps = {k: v for k, v in eps if k in listen_ips}
eps = {k: v for k, v in eps.items() if k in listen_ips}
default_route = None
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

View File

@@ -270,13 +270,14 @@ class ThumbSrv(object):
fmts += ["RGBA", "LA"]
args["method"] = 6
else:
pass # default q = 75
# default q = 75
args["progressive"] = True
if im.mode not in fmts:
# print("conv {}".format(im.mode))
im = im.convert("RGB")
im.save(tpath, quality=40, method=6)
im.save(tpath, **args)
def conv_ffmpeg(self, abspath, tpath):
ret, _ = ffprobe(abspath)

View File

@@ -1,5 +1,6 @@
:root {
--grid-sz: 10em;
--grid-ln: 3;
}
@font-face {
font-family: 'scp';
@@ -203,6 +204,9 @@ a, #files tbody div a:last-child {
color: #f4c;
border-bottom: 1px solid rgba(255,68,204,0.6);
}
#repl {
padding: .33em;
}
#files tbody a.play {
color: #e70;
padding: .2em;
@@ -212,8 +216,8 @@ a, #files tbody div a:last-child {
color: #720;
text-shadow: 0 0 .3em #b80;
}
#ggrid a.play,
html.light #ggrid a.play {
#ggrid>a.play,
html.light #ggrid>a.play {
color: #fff;
background: #750;
border-color: #c90;
@@ -221,36 +225,38 @@ html.light #ggrid a.play {
box-shadow: 0 .1em 1.2em #b83;
}
#files tbody tr.sel td,
#ggrid a.sel,
html.light #ggrid a.sel {
#ggrid>a.sel,
#ggrid>a[tt].sel,
html.light #ggrid>a.sel,
html.light #ggrid>a[tt].sel {
color: #fff;
background: #925;
border-color: #c37;
}
#files tbody tr.sel:hover td,
#files tbody tr.sel:focus td,
#ggrid a.sel:hover,
html.light #ggrid a.sel:hover {
#ggrid>a.sel:hover,
html.light #ggrid>a.sel:hover {
color: #fff;
background: #d39;
border-color: #d48;
text-shadow: 1px 1px 0 #804;
}
#ggrid a.sel,
html.light #ggrid a.sel {
#ggrid>a.sel,
html.light #ggrid>a.sel {
border-top: 1px solid #d48;
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 */
}
#ggrid a.sel img,
#ggrid a.play img {
#ggrid>a.sel img,
#ggrid>a.play img {
opacity: .7;
filter: contrast(130%) brightness(107%);
}
#ggrid a.sel img {
#ggrid>a.sel img {
box-shadow: 0 0 1em #b36;
}
#ggrid a.play img {
#ggrid>a.play img {
box-shadow: 0 0 1em #b83;
}
#files tr.sel a {
@@ -314,7 +320,7 @@ html.light #ggrid a.sel {
}
#widget {
position: fixed;
font-size: 1.5em;
font-size: 1.4em;
left: 0;
right: 0;
bottom: -6em;
@@ -337,16 +343,19 @@ html.light #ggrid a.sel {
}
#wtgrid,
#wtico {
cursor: url(/.cpr/dd/4.png), pointer;
animation: cursor 500ms;
position: relative;
top: -.06em;
font-size: .9em;
top: -.04em;
}
#wtgrid {
font-size: .8em;
font-size: .75em;
padding: .1em;
top: -.12em;
}
#wtgrid:hover,
#wtico {
cursor: url(/.cpr/dd/4.png), pointer;
animation: cursor 500ms;
}
#wtico:hover {
animation: cursor 500ms infinite;
}
@@ -363,7 +372,8 @@ html.light #ggrid a.sel {
#wtoggle {
position: absolute;
white-space: nowrap;
top: -1.2em;
font-size: .8em;
top: -1em;
right: 0;
height: 1em;
font-size: 2em;
@@ -373,23 +383,25 @@ html.light #ggrid a.sel {
background: #3c3c3c;
box-shadow: 0 0 .5em #222;
border-radius: .3em 0 0 0;
padding: .2em .2em;
padding: 0 0 0 .1em;
color: #fff;
}
#wzip, #wnp {
#wfm, #wzip, #wnp {
display: none;
margin-right: .3em;
padding-right: .3em;
}
#wzip, #wnp {
margin-right: .2em;
padding-right: .2em;
border-right: .1em solid #555;
}
#wnp a {
position: relative;
font-size: .47em;
margin: 0 .1em;
top: -.4em;
#wfm.act+#wzip,
#wfm.act+#wzip+#wnp {
margin-left: .2em;
padding-left: .2em;
border-left: .1em solid #555;
}
#wnp a+a {
margin-left: .33em;
#wfm.act {
display: inline-block;
}
#wtoggle,
#wtoggle * {
@@ -403,17 +415,22 @@ html.light #ggrid a.sel {
display: none;
}
#wfm a,
#wnp a,
#wzip a {
font-size: .5em;
padding: 0 .3em;
margin: -.3em .2em;
margin: -.3em .1em;
position: relative;
display: inline-block;
}
#wfm span {
#wfm span,
#wnp span {
font-size: .6em;
display: block;
}
#wnp span {
font-size: .7em;
}
#wfm a:not(.en) {
opacity: .3;
color: #f6c;
@@ -430,7 +447,7 @@ html.light #wfm a:not(.en) {
}
#wzip a {
font-size: .4em;
margin: -.3em .3em;
margin: -.3em .1em;
}
#wtoggle.sel #wzip #selzip {
top: -.6em;
@@ -692,10 +709,10 @@ input.eq_gain {
position: sticky;
z-index: 1;
top: 0;
height: 2.2em;
line-height: 2.2em;
border-bottom: 1px solid #555;
overflow: hidden;
height: 2.2em;
line-height: 2.2em;
border-bottom: 1px solid #555;
overflow: hidden;
}
#thx_ff {
padding: 5em 0;
@@ -798,8 +815,6 @@ input.eq_gain {
width: 1em;
border-radius: .2em;
margin: -1.2em auto 0 auto;
top: 2em;
position: relative;
background: #444;
}
#files th span {
@@ -867,10 +882,12 @@ input.eq_gain {
background: #3c3c3c;
border: 1px solid #444;
border-radius: .3em;
padding: .5em;
padding: .2em .5em;
line-height: 2.3em;
margin: 0 1.5em 1em .4em;
position: sticky;
top: -.3em;
z-index: 1;
}
html.light #ghead {
background: #f7f7f7;
@@ -880,10 +897,22 @@ html.light #ghead {
position: relative;
top: 0;
}
#ghead>span {
white-space: pre;
padding-left: .3em;
}
#ggrid {
padding-top: .5em;
}
#ggrid a {
#ggrid>a>span {
overflow: hidden;
display: block;
display: -webkit-box;
-webkit-line-clamp: var(--grid-ln);
-webkit-box-orient: vertical;
padding-top: .3em;
}
#ggrid>a {
display: inline-block;
width: 10em;
width: var(--grid-sz);
@@ -897,7 +926,10 @@ html.light #ghead {
padding: .3em;
margin: .5em;
}
#ggrid a img {
#ggrid>a[tt] {
background: linear-gradient(135deg, #383838 95%, #555 95%);
}
#ggrid>a img {
border-radius: .2em;
max-width: 10em;
max-width: var(--grid-sz);
@@ -906,27 +938,33 @@ html.light #ghead {
margin: 0 auto;
display: block;
}
#ggrid a span {
padding: .2em .3em;
display: block;
}
#ggrid span.dir:before {
#ggrid>a.dir:before {
content: '📂';
line-height: 0;
font-size: 2em;
margin: -.7em .1em -.5em -.3em;
}
#ggrid a:hover {
#ggrid>a:before {
display: block;
position: absolute;
padding: .3em 0;
margin: -.4em;
text-shadow: 0 0 .1em #000;
background: linear-gradient(135deg,rgba(255,255,255,0) 50%,rgba(255,255,255,0.2));
border-radius: .3em;
font-size: 2em;
}
#ggrid>a:hover {
background: #444;
border-color: #555;
color: #fd9;
}
html.light #ggrid a {
html.light #ggrid>a {
background: #f7f7f7;
border-color: #ddd;
box-shadow: 0 .1em .2em #ddd;
}
html.light #ggrid a:hover {
html.light #ggrid>a[tt] {
background: linear-gradient(135deg, #f7f7f7 95%, #ccc 95%);
}
html.light #ggrid>a:hover {
background: #fff;
border-color: #ccc;
color: #015;
@@ -1305,11 +1343,11 @@ html.light #tree::-webkit-scrollbar {
opacity: 1;
}
.full-image {
display: inline-block;
position: relative;
width: 100%;
height: 100%;
text-align: center;
display: inline-block;
position: relative;
width: 100%;
height: 100%;
text-align: center;
}
.full-image figure {
display: inline;
@@ -1504,6 +1542,7 @@ html.light #bbox-overlay figcaption a {
#op_up2k {
padding: 0 1em 1em 1em;
min-height: 60em;
}
#u2form {
position: absolute;
@@ -1633,6 +1672,7 @@ html.light #bbox-overlay figcaption a {
white-space: nowrap;
text-align: center;
overflow: hidden;
min-width: 24em;
}
#u2cards.w {
width: 44em;

View File

@@ -113,6 +113,8 @@
<div id="epi" class="logue">{{ logues[1] }}</div>
<h2><a href="/?h">control-panel</a></h2>
<a href="#" id="repl">π</a>
</div>

View File

@@ -32,7 +32,7 @@ ebi('widget').innerHTML = (
'<div id="wtoggle">' +
'<span id="wfm"><a' +
' href="#" id="fren" tt="rename selected item$NHotkey: F2">✎<span>name</span></a><a' +
' href="#" id="fdel" tt="delete selected items$NHotkey: ctrl-K">⌫<span>delete</span></a><a' +
' href="#" id="fdel" tt="delete selected items$NHotkey: ctrl-K">⌫<span>del.</span></a><a' +
' href="#" id="fcut" tt="cut selected items &lt;small&gt;(then paste somewhere else)&lt;/small&gt;$NHotkey: ctrl-X">✂<span>cut</span></a><a' +
' href="#" id="fpst" tt="paste a previously cut/copied selection$NHotkey: ctrl-V">📋<span>paste</span></a>' +
'</span><span id="wzip"><a' +
@@ -40,8 +40,8 @@ ebi('widget').innerHTML = (
' href="#" id="selinv" tt="invert selection">sel.<br />inv.</a><a' +
' href="#" id="selzip" tt="download selection as archive">zip</a>' +
'</span><span id="wnp"><a' +
' href="#" id="npirc" tt="copy irc-formatted track info">📋irc</a><a' +
' href="#" id="nptxt" tt="copy plaintext track info">📋txt</a>' +
' href="#" id="npirc" tt="copy irc-formatted track info">📋<span>irc</span></a><a' +
' href="#" id="nptxt" tt="copy plaintext track info">📋<span>txt</span></a>' +
'</span><a' +
' href="#" id="wtgrid" tt="toggle grid/list view$NHotkey: G">田</a><a' +
' href="#" id="wtico">♫</a>' +
@@ -284,7 +284,7 @@ var mpl = (function () {
r.os_ctl = !r.os_ctl && have_mctl;
bcfg_set('au_os_ctl', r.os_ctl);
if (!have_mctl)
toast.err(5, 'need firefox 82+ or chrome 73+');
toast.err(5, 'need firefox 82+ or chrome 73+\n(or iOS 15+ supposedly)');
};
ebi('au_osd_cv').onclick = function (e) {
@@ -399,6 +399,7 @@ function MPlayer() {
r.au_native2 = null;
r.au_ogvjs = null;
r.au_ogvjs2 = null;
r.loading = false;
r.tracks = {};
r.order = [];
@@ -422,18 +423,14 @@ function MPlayer() {
}
}
r.vol = sread('vol');
if (r.vol !== null)
r.vol = parseFloat(r.vol);
else
r.vol = 0.5;
r.vol = clamp(fcfg_get('vol', 0.5), 0, 1);
r.expvol = function (v) {
return 0.5 * v + 0.5 * v * v;
};
r.setvol = function (vol) {
r.vol = Math.max(Math.min(vol, 1), 0);
r.vol = clamp(vol, 0, 1);
swrite('vol', vol);
r.stopfade(true);
@@ -680,7 +677,7 @@ var pbar = (function () {
bctx.clearRect(0, 0, bc.w, bc.h);
if (!mp.au)
if (!mp.au || mp.loading)
return;
var sm = bc.w * 1.0 / mp.au.duration,
@@ -702,25 +699,26 @@ var pbar = (function () {
r.drawpos = function () {
var bc = r.buf,
pc = r.pos,
pctx = pc.ctx;
pctx = pc.ctx,
apos, adur;
pctx.clearRect(0, 0, pc.w, pc.h);
if (!mp.au || isNaN(mp.au.duration) || isNaN(mp.au.currentTime))
if (!mp.au || mp.loading || isNaN(adur = mp.au.duration) || isNaN(apos = mp.au.currentTime) || apos < 0 || adur < apos)
return; // not-init || unsupp-codec
var sm = bc.w * 1.0 / mp.au.duration;
var sm = bc.w * 1.0 / adur;
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 = adur / 10; p <= mins; p++)
pctx.fillRect(Math.floor(sm * p * 10), 0, 2, pc.h);
pctx.fillStyle = light ? 'rgba(0,64,0,0.5)' : 'rgba(192,255,96,0.5)';
for (var p = 1, mins = mp.au.duration / 60; p <= mins; p++)
for (var p = 1, mins = adur / 60; p <= mins; p++)
pctx.fillRect(Math.floor(sm * p * 60), 0, 2, pc.h);
var w = 8,
x = sm * mp.au.currentTime;
x = sm * apos;
pctx.fillStyle = '#573'; pctx.fillRect((x - w / 2) - 1, 0, w + 2, pc.h);
pctx.fillStyle = '#dfc'; pctx.fillRect((x - w / 2), 0, 8, pc.h);
@@ -731,8 +729,8 @@ var pbar = (function () {
pctx.font = '1em sans-serif';
var m = pctx.measureText.bind(pctx),
t1 = s2ms(mp.au.duration),
t2 = s2ms(mp.au.currentTime),
t1 = s2ms(adur),
t2 = s2ms(apos),
yt = pc.h / 3 * 2.1,
xt1 = pc.w - (m(t1).width + 12),
xt2 = x < pc.w / 2 ? (x + 12) : (Math.min(pc.w - m(t1 + ":88").width, x - 12) - m(t2).width);
@@ -965,7 +963,7 @@ var mpui = (function () {
}
// preload next song
if (mpl.preload && preloaded != mp.au.src) {
if (mpl.preload && !mp.loading && preloaded != mp.au.src) {
var pos = mp.au.currentTime,
len = mp.au.duration;
@@ -1021,6 +1019,21 @@ function need_ogv_for(url) {
}
function start_sinegen() {
var af = 'data:audio/wav;base64,UklGRlaxAgBXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguNzYuMTAwAGRhdGEQsQIAAAB',
body = 'iArcE8AYCCeEKggzaDeQOmA/0D/QPmQ/kDtsNggzhCgMJ8Qa4BGMCAQCe/Un7EPn+9h/1fvMm8hzxaPAM8AzwZ/Ac8SXyfvMf9f32D/lI+539//9';
while (af.length < 235304)
af += body;
var au = new Audio(af.slice(0, 235304));
au.onplay = au.pause.bind(au);
au.volume = 0.5;
au.play();
return au;
}
var audio_eq = (function () {
var r = {
"en": false,
@@ -1239,6 +1252,9 @@ function play(tid, is_ev, seek, call_depth) {
if (mp.order.length == 0)
return console.log('no audio found wait what');
if (crashed)
return;
mp.stopfade(true);
var tn = tid;
@@ -1280,17 +1296,33 @@ function play(tid, is_ev, seek, call_depth) {
var url = mp.tracks[tid];
if (need_ogv_for(url)) {
var m = /.* Version\/([0-9]+)\.[0-9\.]+ Mobile\/[^ ]+ Safari\/[0-9\.]+$/.exec(navigator.userAgent),
safari = m ? parseInt(m[1]) : 99;
if (mp.au_ogvjs) {
mp.au = mp.au_ogvjs;
}
else if (window['OGVPlayer']) {
mp.au = mp.au_ogvjs = new OGVPlayer();
mp.loading = true;
try {
mp.au = mp.au_ogvjs = new OGVPlayer();
}
catch (ex) {
return toast.err(30, 'your browser cannot play ogg/vorbis/opus\n\n' + ex +
'\n\n<a href="#" onclick="new OGVPlayer();">click here</a> for a full crash report');
}
attempt_play = is_ev;
mp.au.addEventListener('error', evau_error, true);
mp.au.addEventListener('progress', pbar.drawpos);
mp.au.addEventListener('ended', next_song);
mp.au.onerror = evau_error;
mp.au.onprogress = pbar.drawpos;
mp.au.onended = next_song;
mp.au.onloadedmetadata = mp.au.onloadeddata = function () {
mp.loading = false;
};
widget.open();
}
else if (safari < 14) {
return toast.err(0, 'because this is an apple device,\nsafari 14 or newer is required to play ogg/vorbis/opus files\n\nyou are using safari ' + safari + '\n(every iOS browser is actually safari)');
}
else {
if (call_depth !== undefined)
return toast.err(0, 'failed to load ogv.js:\ncannot play ogg/opus in this browser\n(try a non-apple device)');
@@ -1308,18 +1340,26 @@ function play(tid, is_ev, seek, call_depth) {
else {
if (!mp.au_native) {
mp.au = mp.au_native = new Audio();
mp.au.addEventListener('error', evau_error, true);
mp.au.addEventListener('progress', pbar.drawpos);
mp.au.addEventListener('ended', next_song);
mp.au.onerror = evau_error;
mp.au.onprogress = pbar.drawpos;
mp.au.onended = next_song;
widget.open();
}
mp.au = mp.au_native;
mp.loading = false;
}
audio_eq.apply();
url += (url.indexOf('?') < 0 ? '?cache' : '&cache');
if (mp.au.src == url)
mp.au.currentTime = 0;
else {
mp.loading = mp.au == mp.au_ogvjs;
mp.au.src = url;
}
mp.au.tid = tid;
mp.au.src = url + (url.indexOf('?') < 0 ? '?cache' : '&cache');
mp.au.volume = mp.expvol(mp.vol);
var oid = 'a' + tid;
setclass(oid, 'play act');
@@ -1435,9 +1475,16 @@ function autoplay_blocked(seek) {
go.textContent = 'Play "' + fn + '"';
go.onclick = function (e) {
unblocked(e);
// chrome 91 may permanently taint on a failed play()
// depending on win10 settings or something? idk
mp.au_native = mp.au_ogvjs = null;
if (mp.au !== mp.au_ogvjs)
// chrome 91 may permanently taint on a failed play()
// depending on win10 settings or something? idk
mp.au_native = null;
else
// iOS browsers allow playing ogg/vorbis/opus in the background
// if there is an <audio> tag which at some point played audio
if (!mp.sinegen)
mp.sinegen = start_sinegen();
play(tid, true, seek);
mp.fade_in();
};
@@ -1674,7 +1721,7 @@ var fileman = (function () {
bcut.style.display = have_mv && has(perms, 'move') ? '' : 'none';
bpst.style.display = have_mv && has(perms, 'write') ? '' : 'none';
bpst.setAttribute('tt', 'paste ' + r.clip.length + ' items$NHotkey: ctrl-V');
ebi('wfm').style.display = QS('#wfm a.en:not([display])') ? '' : 'none';
clmod(ebi('wfm'), 'act', QS('#wfm a.en:not([style])'));
};
r.rename = function (e) {
@@ -1741,7 +1788,7 @@ var fileman = (function () {
html = html.concat([
'<button id="rn_cancel" tt="abort and close this window">❌ cancel</button>',
'<button id="rn_apply">✅ apply rename</button>',
'<button id="rn_apply">✅ APPLY RENAME</button>',
'<a id="rn_adv" class="tgl btn" href="#" tt="batch / metadata / pattern renaming">advanced</a>',
'<a id="rn_case" class="tgl btn" href="#" tt="case-sensitive regex">case</a>',
'</div>',
@@ -1755,6 +1802,7 @@ var fileman = (function () {
'</table></div>'
]);
var cheap = f.length > 500;
if (sel.length == 1)
html.push(
'<div><table id="rn_f">\n' +
@@ -1767,8 +1815,9 @@ var fileman = (function () {
for (var a = 0; a < f.length; a++)
html.push(
'<tr><td>' +
'<button class="rn_dec" n="' + a + '">decode</button>',
'<button class="rn_reset" n="' + a + '">↺ reset</button></td>',
(cheap ? '</td>' :
'<button class="rn_dec" n="' + a + '">decode</button>' +
'<button class="rn_reset" n="' + a + '">↺ reset</button></td>') +
'<td><input type="text" id="rn_new" n="' + a + '" /></td>' +
'<td><input type="text" id="rn_old" n="' + a + '" readonly /></td></tr>');
}
@@ -1789,23 +1838,26 @@ var fileman = (function () {
f[a].inew = QS('#rn_new' + k);
f[a].inew.value = f[a].iold.value = f[a].ofn;
(function (a) {
f[a].inew.onkeydown = function (e) {
rn_ok(a, true);
if (!cheap)
(function (a) {
f[a].inew.onkeydown = function (e) {
rn_ok(a, true);
if (e.key == 'Escape')
return rn_cancel();
if (e.key == 'Escape')
return rn_cancel();
if (e.key == 'Enter')
return rn_apply();
};
QS('.rn_dec' + k).onclick = function () {
f[a].inew.value = uricom_dec(f[a].inew.value)[0];
};
QS('.rn_reset' + k).onclick = function () {
rn_reset(a);
};
})(a);
if (e.key == 'Enter')
return rn_apply();
};
QS('.rn_dec' + k).onclick = function (e) {
ev(e);
f[a].inew.value = uricom_dec(f[a].inew.value)[0];
};
QS('.rn_reset' + k).onclick = function (e) {
ev(e);
rn_reset(a);
};
})(a);
}
rn_reset(0);
tt.att(rui);
@@ -1828,18 +1880,21 @@ var fileman = (function () {
f[n].inew.focus();
f[n].inew.setSelectionRange(0, f[n].inew.value.lastIndexOf('.'), "forward");
}
function rn_cancel() {
function rn_cancel(e) {
ev(e);
rui.parentNode.removeChild(rui);
}
ebi('rn_cancel').onclick = rn_cancel;
ebi('rn_apply').onclick = rn_apply;
ebi('rn_adv').onclick = function () {
ebi('rn_adv').onclick = function (e) {
ev(e);
adv = !adv;
bcfg_set('rn_adv', adv);
sadv();
};
ebi('rn_case').onclick = function () {
ebi('rn_case').onclick = function (e) {
ev(e);
cs = !cs;
bcfg_set('rn_case', cs);
};
@@ -1866,7 +1921,8 @@ var fileman = (function () {
ipre.appendChild(o);
}
}
inew.onclick = function () {
inew.onclick = function (e) {
ev(e);
modal.prompt('provide a name for your new preset', ifmt.value, function (name) {
if (!name)
return toast.warn(3, 'aborted');
@@ -1877,7 +1933,8 @@ var fileman = (function () {
ipre.value = name;
});
};
idel.onclick = function () {
idel.onclick = function (e) {
ev(e);
delete presets[ipre.value];
jwrite('rn_pre', presets);
spresets();
@@ -1935,7 +1992,8 @@ var fileman = (function () {
}
};
function rn_apply() {
function rn_apply(e) {
ev(e);
while (f.length && (!f[0].ok || f[0].ofn == f[0].inew.value))
f.shift();
@@ -2040,9 +2098,18 @@ var fileman = (function () {
clmod(els[a], 'fcut', 1);
}, 1);
toast.inf(1.5, 'cut ' + sel.length + ' items');
jwrite('fman_clip', vps);
r.tx(1);
try {
vps = JSON.stringify(vps);
if (vps.length > 1024 * 1024)
throw 'a';
swrite('fman_clip', vps);
r.tx(1);
toast.inf(1.5, 'cut ' + sel.length + ' items');
}
catch (ex) {
toast.warn(30, 'cut ' + sel.length + ' items\n\nbut: only <b>this</b> browser-tab can paste them\n(since the selection is so absolutely massive)');
}
};
r.paste = function (e) {
@@ -2153,14 +2220,16 @@ var thegrid = (function () {
gfiles.style.display = 'none';
gfiles.innerHTML = (
'<div id="ghead">' +
'<a href="#" class="tgl btn" id="gridsel" tt="enable file selection; ctrl-click a file to override$NHotkey: S">multiselect</a> &nbsp; zoom ' +
'<a href="#" class="tgl btn" id="gridsel" tt="enable file selection; ctrl-click a file to override$NHotkey: S">multiselect</a> <span>zoom: ' +
'<a href="#" class="btn" z="-1.2" tt="Hotkey: shift-A">&ndash;</a> ' +
'<a href="#" class="btn" z="1.2" tt="Hotkey: shift-D">+</a> &nbsp; sort by: ' +
'<a href="#" class="btn" z="1.2" tt="Hotkey: shift-D">+</a></span> <span>chop: ' +
'<a href="#" class="btn" l="-1" tt="truncate filenames more (show less)">&ndash;</a> ' +
'<a href="#" class="btn" l="1" tt="truncate filenames less (show more)">+</a></span> <span>sort by: ' +
'<a href="#" s="href">name</a>, ' +
'<a href="#" s="sz">size</a>, ' +
'<a href="#" s="ts">date</a>, ' +
'<a href="#" s="ext">type</a>' +
'</div>' +
'</span></div>' +
'<div id="ggrid"></div>'
);
lfiles.parentNode.insertBefore(gfiles, lfiles);
@@ -2169,7 +2238,8 @@ var thegrid = (function () {
'thumbs': bcfg_get('thumbs', true),
'en': bcfg_get('griden', false),
'sel': bcfg_get('gridsel', false),
'sz': fcfg_get('gridsz', 10),
'sz': clamp(fcfg_get('gridsz', 10), 4, 40),
'ln': clamp(icfg_get('gridln', 3), 1, 7),
'isdirty': true,
'bbox': null
};
@@ -2189,8 +2259,7 @@ var thegrid = (function () {
loadgrid();
}
else {
lfiles.style.display = '';
gfiles.style.display = 'none';
ungrid();
}
pbar.onresize();
vbar.onresize();
@@ -2199,11 +2268,15 @@ var thegrid = (function () {
var btnclick = function (e) {
ev(e);
var s = this.getAttribute('s'),
z = this.getAttribute('z');
z = this.getAttribute('z'),
l = this.getAttribute('l');
if (z)
return setsz(z > 0 ? r.sz * z : r.sz / (-z));
if (l)
return setln(parseInt(l));
var t = lfiles.tHead.rows[0].cells;
for (var a = 0; a < t.length; a++)
if (t[a].getAttribute('name') == s) {
@@ -2214,7 +2287,7 @@ var thegrid = (function () {
r.setdirty();
};
var links = QSA('#ghead>a');
var links = QSA('#ghead a');
for (var a = 0; a < links.length; a++)
links[a].onclick = btnclick;
@@ -2227,19 +2300,35 @@ var thegrid = (function () {
r.setvis = function (vis) {
(r.en ? gfiles : lfiles).style.display = vis ? '' : 'none';
}
};
r.setdirty = function () {
r.dirty = true;
if (r.en) {
loadgrid();
}
};
function setln(v) {
if (v) {
r.ln += v;
if (r.ln < 1) r.ln = 1;
if (r.ln > 7) r.ln = v < 0 ? 7 : 99;
swrite('gridln', r.ln);
setTimeout(r.tippen, 20);
}
try {
document.documentElement.style.setProperty('--grid-ln', r.ln);
}
catch (ex) { }
}
setln();
function setsz(v) {
if (v !== undefined) {
r.sz = v;
r.sz = clamp(v, 4, 40);
swrite('gridsz', r.sz);
setTimeout(r.tippen, 20);
}
try {
document.documentElement.style.setProperty('--grid-sz', r.sz + 'em');
@@ -2297,14 +2386,57 @@ var thegrid = (function () {
var ths = QSA('#ggrid>a');
for (var a = 0, aa = ths.length; a < aa; a++) {
var tr = ebi(ths[a].getAttribute('ref')).closest('tr');
ths[a].setAttribute('class', tr.getAttribute('class'));
var tr = ebi(ths[a].getAttribute('ref')).closest('tr'),
cl = tr.getAttribute('class') || '';
if (ths[a].getAttribute('href').endsWith('/'))
cl += ' dir';
ths[a].setAttribute('class', cl);
}
var uns = QS('#ggrid a[ref="unsearch"]');
if (uns)
uns.onclick = function () {
uns.onclick = function (e) {
ev(e);
ebi('unsearch').click();
};
};
r.tippen = function () {
var els = QSA('#ggrid>a>span'),
aa = els.length;
if (!aa)
return;
var cs = window.getComputedStyle(els[0]),
fs = parseFloat(cs.lineHeight),
pad = parseFloat(cs.paddingTop),
pels = [],
todo = [];
for (var a = 0; a < aa; a++) {
var vis = Math.round((els[a].offsetHeight - pad) / fs),
all = Math.round((els[a].scrollHeight - pad) / fs),
par = els[a].parentNode;
pels.push(par);
todo.push(vis < all ? par.getAttribute('ttt') : null);
}
for (var a = 0; a < todo.length; a++) {
if (todo[a])
pels[a].setAttribute('tt', todo[a]);
else
pels[a].removeAttribute('tt');
}
tt.att(ebi('ggrid'));
};
function ungrid() {
lfiles.style.display = '';
gfiles.style.display = 'none';
}
function loadgrid() {
@@ -2322,6 +2454,7 @@ var thegrid = (function () {
for (var a = 0, aa = files.length; a < aa; a++) {
var ao = files[a],
href = esc(ao.getAttribute('href')),
name = uricom_dec(vsplit(href)[1])[0],
ref = ao.getAttribute('id'),
isdir = href.split('?')[0].slice(-1)[0] == '/',
ac = isdir ? ' class="dir"' : '',
@@ -2354,7 +2487,8 @@ var thegrid = (function () {
ihref = '/.cpr/ico/' + ihref.slice(0, -1);
}
html.push('<a href="' + href + '" ref="' + ref + '"><img src="' +
html.push('<a href="' + href + '" ref="' + ref +
'"' + ac + ' ttt="' + esc(name) + '"><img src="' +
ihref + '" /><span' + ac + '>' + ao.innerHTML + '</span></a>');
}
ebi('ggrid').innerHTML = html.join('\n');
@@ -2366,6 +2500,7 @@ var thegrid = (function () {
r.dirty = false;
r.bagit();
r.loadsel();
setTimeout(r.tippen, 20);
}
r.bagit = function () {
@@ -2584,10 +2719,10 @@ document.onkeydown = function (e) {
return ebi('gridsel').click();
if (k == 'KeyA')
return QSA('#ghead>a[z]')[0].click();
return QSA('#ghead a[z]')[0].click();
if (k == 'KeyD')
return QSA('#ghead>a[z]')[1].click();
return QSA('#ghead a[z]')[1].click();
}
};
@@ -2872,9 +3007,7 @@ var treectl = (function () {
prev_winh = null,
dyn = bcfg_get('dyntree', true),
dots = bcfg_get('dotfiles', false),
treesz = icfg_get('treesz', 16);
treesz = Math.min(Math.max(treesz, 4), 50);
treesz = clamp(icfg_get('treesz', 16), 4, 50);
treectl.entree = function (e) {
ev(e);
@@ -3461,6 +3594,7 @@ var filecols = (function () {
if (ttv) {
th.setAttribute("tt", ttv);
th.setAttribute("ttd", "u");
th.setAttribute("ttm", "12");
}
}
};
@@ -4024,6 +4158,7 @@ var unpost = (function () {
}
ct.onclick = function (e) {
ev(e);
var tgt = e.target.closest('a[me]');
if (!tgt)
return;
@@ -4065,7 +4200,8 @@ var unpost = (function () {
tfilt = setTimeout(r.load, 250);
};
ebi('unpost_nofilt').onclick = function () {
ebi('unpost_nofilt').onclick = function (e) {
ev(e);
filt.value = '';
r.load();
};

View File

@@ -8,6 +8,14 @@ html, body {
font-family: sans-serif;
line-height: 1.5em;
}
#repl {
position: absolute;
top: 0;
right: .2em;
border: none;
color: inherit;
background: none;
}
#mtw {
display: none;
}
@@ -506,6 +514,9 @@ blink {
border-bottom: .07em solid #4ac;
padding: 0 .3em;
}
#repl {
display: none;
}
#toc>ul {
border-left: .1em solid #84c4dd;
}

View File

@@ -45,6 +45,7 @@
</div>
<div id="mp"></div>
</div>
<a href="#" id="repl">π</a>
{%- if edit %}
<div id="helpbox">

View File

@@ -22,6 +22,15 @@ html, body {
bottom: auto;
top: 1.4em;
}
#repl {
position: absolute;
top: 0;
right: .5em;
border: none;
color: inherit;
background: none;
text-decoration: none;
}
#mn {
font-weight: normal;
margin: 1.3em 0 .7em 1em;

View File

@@ -21,6 +21,7 @@
<textarea id="mt" style="display:none" autocomplete="off">{{ md }}</textarea>
</div>
</div>
<a href="#" id="repl">π</a>
<script>
var last_modified = {{ lastmod }};

View File

@@ -11,6 +11,7 @@ html {
background: #333;
font-family: sans-serif;
text-shadow: 1px 1px 0px #000;
touch-action: manipulation;
}
html, body {
margin: 0;
@@ -25,4 +26,4 @@ pre {
}
a {
color: #fc5;
}
}

View File

@@ -3,6 +3,9 @@ html, body, #wrap {
background: #f7f7f7;
font-family: sans-serif;
}
html {
touch-action: manipulation;
}
#wrap {
max-width: 40em;
margin: 2em auto;
@@ -26,6 +29,12 @@ a {
border-radius: .2em;
padding: .2em .8em;
}
#repl {
border: none;
background: none;
color: inherit;
padding: 0;
}
table {
border-collapse: collapse;
}
@@ -73,4 +82,4 @@ html.dark input {
}
html.dark .num {
border-color: #777;
}
}

View File

@@ -7,6 +7,7 @@
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=0.8">
<link rel="stylesheet" media="screen" href="/.cpr/splash.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="/.cpr/ui.css?_={{ ts }}">
</head>
<body>
@@ -66,11 +67,13 @@
</form>
</ul>
</div>
<a href="#" id="repl">π</a>
<script>
if (localStorage.getItem('lightmode') != 1)
document.documentElement.setAttribute("class", "dark");
</script>
<script src="/.cpr/util.js?_={{ ts }}"></script>
</body>
</html>
</html>

View File

@@ -1,6 +1,11 @@
html {
touch-action: manipulation;
}
#tt, #toast {
position: fixed;
max-width: 34em;
max-width: min(34em, 90%);
max-width: min(34em, calc(100% - 7em));
background: #222;
border: 0 solid #777;
box-shadow: 0 .2em .5em #222;
@@ -8,8 +13,9 @@
z-index: 9001;
}
#tt {
max-width: min(34em, calc(100% - 3.3em));
overflow: hidden;
margin-top: 1em;
margin: .7em 0;
padding: 0 1.3em;
height: 0;
opacity: .1;
@@ -20,7 +26,9 @@
right: -1em;
line-height: 1.5em;
padding: 1em 1.3em;
margin-left: 3em;
border-width: .4em 0;
overflow-wrap: break-word;
transform: translateX(100%);
transition:
transform .4s cubic-bezier(.2, 1.2, .5, 1),
@@ -28,7 +36,14 @@
text-shadow: 1px 1px 0 #000;
color: #fff;
}
#toastc {
#toast a {
color: inherit;
text-shadow: inherit;
background: rgba(0, 0, 0, 0.4);
border-radius: .3em;
padding: .2em .3em;
}
#toast a#toastc {
display: inline-block;
position: absolute;
overflow: hidden;
@@ -37,7 +52,7 @@
opacity: 0;
padding: .3em 0;
margin: -.3em 0 0 0;
line-height: 1.5em;
line-height: 1.3em;
color: #000;
border: none;
outline: none;
@@ -45,6 +60,15 @@
border-radius: .5em 0 0 .5em;
transition: left .3s, width .3s, padding .3s, opacity .3s;
}
#toastb {
max-height: 70vh;
overflow-y: auto;
}
#toast.scroll #toastb {
overflow-y: scroll;
margin-right: -1.2em;
padding-right: .7em;
}
#toast pre {
margin: 0;
}
@@ -101,6 +125,7 @@
padding: 1.5em 2em;
border-width: .5em 0;
}
#modalc code,
#tt code {
background: #3c3c3c;
padding: .1em .3em;
@@ -119,6 +144,7 @@ html.light #tt,
html.light #toast {
box-shadow: 0 .3em 1em rgba(0,0,0,0.4);
}
#modalc code,
html.light #tt code {
background: #060;
color: #fff;
@@ -201,6 +227,8 @@ html.light #tt em {
}
#modali {
display: block;
background: #fff;
color: #000;
width: calc(100% - 1.25em);
margin: 1em -.1em 0 -.1em;
padding: .5em;
@@ -210,4 +238,7 @@ html.light #tt em {
}
#modali:focus {
border-color: #06d;
}
#repl_pre {
max-width: 24em;
}

View File

@@ -800,6 +800,12 @@ function up2k_init(subtle) {
});
}
good_files.sort(function (a, b) {
a = a[1];
b = b[1];
return a < b ? -1 : a > b ? 1 : 0;
});
var msg = ['{0} these {1} files?<ul>'.format(fsearch ? 'search' : 'upload', good_files.length)];
for (var a = 0, aa = Math.min(20, good_files.length); a < aa; a++)
msg.push('<li>' + esc(good_files[a][1]) + '</li>');
@@ -906,7 +912,7 @@ function up2k_init(subtle) {
td = (now - (etaref || now)) / 1000.0;
etaref = now;
//ebi('acc_info').innerHTML = f2f(st.time.busy, 1) + ' ' + f2f(now / 1000, 1);
//ebi('acc_info').innerHTML = humantime(st.time.busy) + ' ' + f2f(now / 1000, 1);
if (!nhash)
ebi('u2etah').innerHTML = 'Done ({0}, {1} files)'.format(humansize(st.bytes.hashed), pvis.ctr["ok"] + pvis.ctr["ng"]);
@@ -954,14 +960,8 @@ function up2k_init(subtle) {
if (etaskip)
continue;
if (eta < 60 * 60 * 24)
try {
eta = /.*(..:..:..).*/.exec(new Date(eta * 1000).toUTCString())[1];
}
catch (ex) { }
ebi(t[a][0]).innerHTML = '{0}, {1}/s, {2}'.format(
humansize(rem), humansize(bps, 1), eta);
humansize(rem), humansize(bps, 1), humantime(eta));
}
if (++etaskip > 2)
etaskip = 0;
@@ -1852,7 +1852,7 @@ function up2k_init(subtle) {
flag = up2k_flagbus();
}
catch (ex) {
console.log("flag error: " + ex.toString());
toast.err(5, "not supported on your browser:\n" + ex);
tgl_flag_en();
}
}
@@ -1880,21 +1880,18 @@ function up2k_init(subtle) {
};
ebi('nthread').onkeydown = bumpthread2;
ebi('nthread').addEventListener('input', bumpthread, false);
ebi('multitask').addEventListener('click', tgl_multitask, false);
ebi('ask_up').addEventListener('click', tgl_ask_up, false);
ebi('flag_en').addEventListener('click', tgl_flag_en, false);
ebi('u2turbo').addEventListener('click', tgl_turbo, false);
ebi('u2tdate').addEventListener('click', tgl_datechk, false);
ebi('nthread').oninput = bumpthread;
ebi('multitask').onclick = tgl_multitask;
ebi('ask_up').onclick = tgl_ask_up;
ebi('flag_en').onclick = tgl_flag_en;
ebi('u2turbo').onclick = tgl_turbo;
ebi('u2tdate').onclick = tgl_datechk;
var o = ebi('fsearch');
if (o)
o.addEventListener('click', tgl_fsearch, false);
var nodes = ebi('u2conf').getElementsByTagName('a');
for (var a = nodes.length - 1; a >= 0; a--)
nodes[a].addEventListener('touchend', nop, false);
ebi('u2etas').onclick = function () {
ebi('u2etas').onclick = function (e) {
ev(e);
clmod(ebi('u2etas'), 'o', 't');
};

View File

@@ -8,7 +8,8 @@ if (!window['console'])
var is_touch = 'ontouchstart' in window,
IPHONE = /iPhone|iPad|iPod/i.test(navigator.userAgent),
ANDROID = /android/i.test(navigator.userAgent);
ANDROID = /android/i.test(navigator.userAgent),
WINDOWS = navigator.platform ? navigator.platform == 'Win32' : /Windows/.test(navigator.userAgent);
var ebi = document.getElementById.bind(document),
@@ -28,6 +29,35 @@ function esc(txt) {
}[c];
});
}
window.onunhandledrejection = function (e) {
console.log("REJ: " + e.reason);
};
try {
console.hist = [];
var hook = function (t) {
var orig = console[t].bind(console),
cfun = function () {
console.hist.push(Date.now() + ' ' + t + ': ' + Array.from(arguments).join(', '));
if (console.hist.length > 100)
console.hist = console.hist.slice(50);
orig.apply(console, arguments);
};
console['std' + t] = orig;
console[t] = cfun;
};
hook('log');
console.log('log-capture ok');
hook('debug');
hook('warn');
hook('error');
}
catch (ex) {
if (console.stdlog)
console.log = console.stdlog;
console.log(ex);
}
var crashed = false, ignexd = {};
function vis_exh(msg, url, lineNo, columnNo, error) {
if ((msg + '').indexOf('ResizeObserver') !== -1)
@@ -39,22 +69,59 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
crashed = true;
window.onerror = undefined;
var html = ['<h1>you hit a bug!</h1><p style="font-size:1.3em;margin:0">try to <a href="#" onclick="localStorage.clear();location.reload();">reset copyparty settings</a> if you are stuck here, or <a href="#" onclick="ignex();">ignore this</a> / <a href="#" onclick="ignex(true);">ignore all</a></p><p>please send me a screenshot arigathanks gozaimuch: <code>ed/irc.rizon.net</code> or <code>ed#2644</code><br />&nbsp; (and if you can, press F12 and include the "Console" tab in the screenshot too)</p><p>',
esc(url + ' @' + lineNo + ':' + columnNo), '<br />' + esc(String(msg)) + '</p>'];
var html = [
'<h1>you hit a bug!</h1>',
'<p style="font-size:1.3em;margin:0">try to <a href="#" onclick="localStorage.clear();location.reload();">reset copyparty settings</a> if you are stuck here, or <a href="#" onclick="ignex();">ignore this</a> / <a href="#" onclick="ignex(true);">ignore all</a></p>',
'<p style="color:#fff">please send me a screenshot arigathanks gozaimuch: <code>ed/irc.rizon.net</code> or <code>ed#2644</code></p>',
'<p class="b">' + esc(url + ' @' + lineNo + ':' + columnNo), '<br />' + esc(String(msg)) + '</p>',
'<p><b>UA:</b> ' + esc(navigator.userAgent + '')
];
try {
var ua = '',
ad = navigator.userAgentData,
adb = ad.brands;
for (var a = 0; a < adb.length; a++)
if (!/Not.*A.*Brand/.exec(adb[a].brand))
ua += adb[a].brand + '/' + adb[a].version + ', ';
ua += ad.platform;
html.push('<br /><b>UAD:</b> ' + esc(ua.slice(0, 100)));
}
catch (e) { }
html.push('</p>');
try {
if (error) {
var find = ['desc', 'stack', 'trace'];
for (var a = 0; a < find.length; a++)
if (String(error[find[a]]) !== 'undefined')
html.push('<h3>' + find[a] + '</h3>' +
esc(String(error[find[a]])).replace(/\n/g, '<br />\n'));
html.push('<p class="b"><b>' + find[a] + ':</b><br />' +
esc(String(error[find[a]])).replace(/\n/g, '<br />\n') + '</p>');
}
ignexd[ekey] = true;
html.push('<h3>localStore</h3>' + esc(JSON.stringify(localStorage)));
var ls = jcp(localStorage);
if (ls.fman_clip)
ls.fman_clip = ls.fman_clip.length + ' items';
var lsk = Object.keys(ls);
lsk.sort();
html.push('<p class="b">');
for (var a = 0; a < lsk.length; a++)
html.push(' <b>' + esc(lsk[a]) + '</b> <code>' + esc(ls[lsk[a]]) + '</code> ');
html.push('</p>');
}
catch (e) { }
if (console.hist.length) {
html.push('<p class="b"><b>console:</b><ul><li>' + Date.now() + ' @</li>');
for (var a = console.hist.length - 1, aa = Math.max(0, console.hist.length - 20); a >= aa; a--)
html.push('<li>' + esc(console.hist[a]) + '</li>');
html.push('</ul>')
}
try {
var exbox = ebi('exbox');
if (!exbox) {
@@ -63,10 +130,19 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
document.body.appendChild(exbox);
var s = mknod('style');
s.innerHTML = '#exbox{background:#333;color:#ddd;font-family:sans-serif;font-size:0.8em;padding:0 1em 1em 1em;z-index:80386;position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%} #exbox h1{margin:.5em 1em 0 0;padding:0} #exbox h3{border-top:1px solid #999;margin:1em 0 0 0} #exbox a{text-decoration:underline;color:#fc0} #exbox code{color:#bf7;background:#222;padding:.1em;margin:.2em;font-size:1.1em;font-family:monospace,monospace} #exbox *{line-height:1.5em}';
s.innerHTML = (
'#exbox{background:#333;color:#ddd;font-family:sans-serif;font-size:0.8em;padding:0 1em 1em 1em;z-index:80386;position:fixed;top:0;left:0;right:0;bottom:0;width:100%;height:100%;overflow:auto;width:calc(100% - 2em)} ' +
'#exbox,#exbox *{line-height:1.5em;overflow-wrap:break-word} ' +
'#exbox code{color:#bf7;background:#222;padding:.1em;margin:.2em;font-size:1.1em;font-family:monospace,monospace} ' +
'#exbox a{text-decoration:underline;color:#fc0} ' +
'#exbox h1{margin:.5em 1em 0 0;padding:0} ' +
'#exbox p.b{border-top:1px solid #999;margin:1em 0 0 0;font-size:1em} ' +
'#exbox ul, #exbox li {margin:0 0 0 .5em;padding:0} ' +
'#exbox b{color:#fff}'
);
document.head.appendChild(s);
}
exbox.innerHTML = html.join('\n');
exbox.innerHTML = html.join('\n').replace(/https?:\/\/[^ \/]+\//g, '/').replace(/js\?_=[a-zA-Z]{4}/g, 'js');
exbox.style.display = 'block';
}
catch (e) {
@@ -179,17 +255,26 @@ function crc32(str) {
function clmod(el, cls, add) {
if (el.classList) {
var have = el.classList.contains(cls);
if (add == 't')
add = el.classList.contains(cls) ? 0 : 1;
add = !have;
return el.classList[add ? 'add' : 'remove'](cls);
if (add != have)
el.classList[add ? 'add' : 'remove'](cls);
return;
}
var re = new RegExp('\\s*\\b' + cls + '\\s*\\b', 'g');
if (add == 't')
add = !re.test(el.className);
var re = new RegExp('\\s*\\b' + cls + '\\s*\\b', 'g'),
n1 = el.className;
el.className = el.className.replace(re, ' ') + (add ? ' ' + cls : '');
if (add == 't')
add = !re.test(n1);
var n2 = n1.replace(re, ' ') + (add ? ' ' + cls : '');
if (n1 != n2)
el.className = n2;
}
@@ -420,6 +505,24 @@ function humansize(b, terse) {
}
function humantime(v) {
if (v >= 60 * 60 * 24)
return v;
try {
return /.*(..:..:..).*/.exec(new Date(v * 1000).toUTCString())[1];
}
catch (ex) {
return v;
}
}
function clamp(v, a, b) {
return Math.min(Math.max(v, a), b);
}
function has(haystack, needle) {
for (var a = 0; a < haystack.length; a++)
if (haystack[a] == needle)
@@ -547,6 +650,9 @@ var timer = (function () {
};
function doevents() {
if (crashed)
return;
if (Date.now() - r.last < 69)
return;
@@ -578,6 +684,8 @@ var tt = (function () {
r.skip = false;
return;
}
if (QS('body.bbox-open'))
return;
var cfg = sread('tooltips');
if (cfg !== null && cfg != '1')
@@ -590,28 +698,39 @@ var tt = (function () {
r.el = this;
var pos = this.getBoundingClientRect(),
dir = this.getAttribute('ttd') || '',
left = pos.left < window.innerWidth / 2,
margin = parseFloat(this.getAttribute('ttm') || 0),
top = pos.top < window.innerHeight / 2,
big = this.className.indexOf(' ttb') !== -1;
if (dir.indexOf('u') + 1) top = false;
if (dir.indexOf('d') + 1) top = true;
if (dir.indexOf('l') + 1) left = false;
if (dir.indexOf('r') + 1) left = true;
clmod(r.tt, 'b', big);
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.style.left = '0';
r.tt.style.top = '0';
r.tt.innerHTML = msg.replace(/\$N/g, "<br />");
r.el.addEventListener('mouseleave', r.hide);
window.addEventListener('scroll', r.hide);
clmod(r.tt, 'show', 1);
var tw = r.tt.offsetWidth,
x = pos.left + (pos.right - pos.left) / 2 - tw / 2;
if (x + tw >= window.innerWidth - 24)
x = window.innerWidth - tw - 24;
if (x < 0)
x = 12;
r.tt.style.left = x + 'px';
r.tt.style.top = top ? (margin + pos.bottom) + 'px' : 'auto';
r.tt.style.bottom = top ? 'auto' : (margin + window.innerHeight - pos.top) + 'px';
};
r.hide = function (e) {
ev(e);
window.removeEventListener('scroll', r.hide);
clmod(r.tt, 'show');
if (r.el)
r.el.removeEventListener('mouseleave', r.hide);
@@ -619,13 +738,23 @@ var tt = (function () {
if (is_touch && IPHONE) {
var f1 = r.show,
f2 = r.hide;
f2 = r.hide,
q = [];
// if an onclick-handler creates a new timer,
// iOS 13.1.2 delays the entire handler by up to 401ms,
// win by using a shared timer instead
timer.add(function () {
while (q.length && Date.now() >= q[0][0])
q.shift()[1]();
});
r.show = function () {
setTimeout(f1.bind(this), 301);
q.push([Date.now() + 100, f1.bind(this)]);
};
r.hide = function () {
setTimeout(f2.bind(this), 301);
q.push([Date.now() + 100, f2.bind(this)]);
};
}
@@ -676,6 +805,7 @@ function lf2br(txt) {
var toast = (function () {
var r = {},
te = null,
scrolling = false,
obj = mknod('div');
obj.setAttribute('id', 'toast');
@@ -683,8 +813,30 @@ var toast = (function () {
r.visible = false;
r.txt = null;
function scrollchk() {
if (scrolling)
return;
var tb = ebi('toastb'),
vis = tb.offsetHeight,
all = tb.scrollHeight;
if (8 + vis >= all)
return;
clmod(obj, 'scroll', 1);
scrolling = true;
}
function unscroll() {
timer.rm(scrollchk);
clmod(obj, 'scroll');
scrolling = false;
}
r.hide = function (e) {
ev(e);
unscroll();
clearTimeout(te);
clmod(obj, 'vis');
r.visible = false;
@@ -695,11 +847,12 @@ var toast = (function () {
if (ms)
te = setTimeout(r.hide, ms * 1000);
obj.innerHTML = '<a href="#" id="toastc">x</a>' + lf2br(txt);
obj.innerHTML = '<a href="#" id="toastc">x</a><div id="toastb">' + lf2br(txt) + '</div>';
obj.className = cl;
ms += obj.offsetWidth;
obj.className += ' vis';
ebi('toastc').onclick = r.hide;
timer.add(scrollchk);
r.visible = true;
r.txt = txt;
};
@@ -725,8 +878,12 @@ var modal = (function () {
var r = {},
q = [],
o = null,
cb_up = null,
cb_ok = null,
cb_ng = null;
cb_ng = null,
prim = '<a href="#" id="modal-ok">OK</a>',
sec = '<a href="#" id="modal-ng">Cancel</a>',
ok_cancel = WINDOWS ? prim + sec : sec + prim;
r.busy = false;
@@ -745,9 +902,17 @@ var modal = (function () {
a = ebi('modal-ok');
a.onclick = ok;
(ebi('modali') || a).focus();
var inp = ebi('modali');
(inp || a).focus();
if (inp)
setTimeout(function () {
inp.setSelectionRange(0, inp.value.length, "forward");
}, 0);
document.addEventListener('focus', onfocus);
timer.add(onfocus);
if (cb_up)
setTimeout(cb_up, 1);
};
r.hide = function () {
@@ -802,41 +967,44 @@ var modal = (function () {
q.shift()();
}
r.alert = function (html, cb) {
r.alert = function (html, cb, fun) {
q.push(function () {
_alert(lf2br(html), cb);
_alert(lf2br(html), cb, fun);
});
next();
};
function _alert(html, cb) {
function _alert(html, cb, fun) {
cb_ok = cb_ng = cb;
cb_up = fun;
html += '<div id="modalb"><a href="#" id="modal-ok">OK</a></div>';
r.show(html);
}
r.confirm = function (html, cok, cng) {
r.confirm = function (html, cok, cng, fun) {
q.push(function () {
_confirm(lf2br(html), cok, cng);
_confirm(lf2br(html), cok, cng, fun);
});
next();
}
function _confirm(html, cok, cng) {
function _confirm(html, cok, cng, fun) {
cb_ok = cok;
cb_ng = cng === undefined ? cok : null;
html += '<div id="modalb"><a href="#" id="modal-ok">OK</a><a href="#" id="modal-ng">Cancel</a></div>';
cb_up = fun;
html += '<div id="modalb">' + ok_cancel + '</div>';
r.show(html);
}
r.prompt = function (html, v, cok, cng) {
r.prompt = function (html, v, cok, cng, fun) {
q.push(function () {
_prompt(lf2br(html), v, cok, cng);
_prompt(lf2br(html), v, cok, cng, fun);
});
next();
}
function _prompt(html, v, cok, cng) {
function _prompt(html, v, cok, cng, fun) {
cb_ok = cok;
cb_ng = cng === undefined ? cok : null;
html += '<input id="modali" type="text" /><div id="modalb"><a href="#" id="modal-ok">OK</a><a href="#" id="modal-ng">Cancel</a></div>';
cb_up = fun;
html += '<input id="modali" type="text" /><div id="modalb">' + ok_cancel + '</div>';
r.show(html);
ebi('modali').value = v || '';
@@ -855,3 +1023,84 @@ function winpopup(txt) {
body: 'msg=' + uricom_enc(Date.now() + ', ' + txt)
});
}
var last_repl = null;
function repl_load() {
var ipre = ebi('repl_pre'),
tb = ebi('modali');
function getpres() {
var o, ret = jread("repl_pre", []);
if (!ret.length)
ret = [
'var v=Object.keys(localStorage); v.sort(); JSON.stringify(v)',
'console.hist.slice(-10).join("\\n")'
];
ipre.innerHTML = '<option value=""></option>';
for (var a = 0; a < ret.length; a++) {
o = mknod('option');
o.setAttribute('value', ret[a]);
o.textContent = ret[a];
ipre.appendChild(o);
}
last_repl = ipre.value = (last_repl || (ret.length ? ret.slice(-1)[0] : ''));
return ret;
}
ebi('repl_pdel').onclick = function (e) {
var val = ipre.value,
pres = getpres();
apop(pres, val);
jwrite('repl_pre', pres);
getpres();
};
ebi('repl_pnew').onclick = function (e) {
var val = tb.value,
pres = getpres();
apop(pres, ipre.value);
pres.push(val);
jwrite('repl_pre', pres);
getpres();
ipre.value = val;
};
ipre.oninput = ipre.onchange = function () {
tb.value = last_repl = ipre.value;
};
tb.oninput = function () {
last_repl = this.value;
};
getpres();
tb.value = last_repl;
setTimeout(function () {
tb.setSelectionRange(0, tb.value.length, "forward");
}, 10);
}
function repl(e) {
ev(e);
var html = [
'<p>js repl (prefix with <code>,</code> to allow raise)</p>',
'<p><select id="repl_pre"></select>',
' &nbsp; <button id="repl_pdel">❌ del</button>',
' &nbsp; <button id="repl_pnew">💾 SAVE</button></p>'
];
modal.prompt(html.join(''), '', function (cmd) {
if (!cmd)
return toast.inf(3, 'eval aborted');
if (cmd.startsWith(','))
return modal.alert(esc(eval(cmd.slice(1)) + ''))
try {
modal.alert(esc(eval(cmd) + ''));
}
catch (ex) {
modal.alert('<h6>exception</h6>' + esc(ex + ''));
}
}, undefined, repl_load);
}
if (ebi('repl'))
ebi('repl').onclick = repl;

View File

@@ -1,37 +1,7 @@
/* put filetype icons inline with text
#ggrid>a>span:before,
#ggrid>a>span.dir:before {
display: inline;
line-height: 0;
font-size: 1.7em;
margin: -.7em .1em -.5em -.6em;
}
*/
/* video, alternative 1:
top-left icon, just like the other formats
=======================================================================
/* move folder icons top-left */
#ggrid>a>span.dir:before {
content: initial;
}
#ggrid>a[href$="/"]:before {
content: '📂';
}
/* put filetype icons top-left */
#ggrid>a:before {
display: block;
position: absolute;
padding: .3em 0;
margin: -.4em;
text-shadow: 0 0 .1em #000;
background: linear-gradient(135deg,rgba(255,255,255,0) 50%,rgba(255,255,255,0.2));
border-radius: .3em;
font-size: 2em;
}
/* video */
#ggrid>a:is(
[href$=".mkv"i],
[href$=".mp4"i],
@@ -39,6 +9,40 @@
):before {
content: '📺';
}
*/
/* video, alternative 2:
play-icon in the middle of the thumbnail
=======================================================================
*/
#ggrid>a:is(
[href$=".mkv"i],
[href$=".mp4"i],
[href$=".webm"i],
) {
position: relative;
overflow: hidden;
}
#ggrid>a:is(
[href$=".mkv"i],
[href$=".mp4"i],
[href$=".webm"i],
):before {
content: '▶';
opacity: .8;
margin: 0;
padding: 1em .5em 1em .7em;
border-radius: 9em;
line-height: 0;
color: #fff;
text-shadow: none;
background: rgba(0, 0, 0, 0.7);
left: calc(50% - 1em);
top: calc(50% - 1.4em);
}
/* audio */
@@ -54,6 +58,7 @@
}
/* image */
#ggrid>a:is(
[href$=".jpg"i],

View File

@@ -27,6 +27,9 @@
/* adjust the button area a bit */
#u2conf.has_btn {width: 35em !important; margin: 5em auto}
/* a */
#op_up2k {min-height: 0}
</style>
<a href="#" onclick="this.parentNode.innerHTML='';">show advanced options</a>

View File

@@ -126,6 +126,13 @@ e=6; s=10; d=~/dev/copyparty/srv/aus; n=1; p=0; e=$((e*60)); rm -rf $d; mkdir $d
-v srv/aus:aus:r:ce2dsa:ce2ts:cmtp=fgsfds=bin/mtag/sleep.py
sqlite3 .hist/up2k.db 'select * from mt where k="fgsfds" or k="t:mtp"' | tee /dev/stderr | wc -l
# generate the sine meme
for ((f=420;f<1200;f++)); do sz=$(ffmpeg -y -f lavfi -i sine=frequency=$f:duration=2 -vf volume=0.1 -ac 1 -ar 44100 -f s16le /dev/shm/a.wav 2>/dev/null; base64 -w0 </dev/shm/a.wav | gzip -c | wc -c); printf '%d %d\n' $f $sz; done | tee /dev/stderr | sort -nrk2,2
ffmpeg -y -f lavfi -i sine=frequency=1050:duration=2 -vf volume=0.1 -ac 1 -ar 44100 /dev/shm/a.wav
# play icon calibration pics
for w in 150 170 190 210 230 250; do for h in 130 150 170 190 210; do /c/Program\ Files/ImageMagick-7.0.11-Q16-HDRI/magick.exe convert -size ${w}x${h} xc:brown -fill orange -draw "circle $((w/2)),$((h/2)) $((w/2)),$((h/3))" $w-$h.png; done; done
##
## vscode

View File

@@ -3,7 +3,7 @@ WORKDIR /z
ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \
ver_hashwasm=4.7.0 \
ver_marked=1.1.0 \
ver_ogvjs=1.8.0 \
ver_ogvjs=1.8.4 \
ver_mde=2.14.0 \
ver_codemirror=5.59.3 \
ver_fontawesome=5.13.0 \
@@ -74,23 +74,16 @@ RUN cd hash-wasm \
# build ogvjs
RUN cd ogvjs-$ver_ogvjs \
&& cp -pv \
ogv.js \
ogv-worker-audio.js \
ogv-demuxer-ogg-wasm.js \
ogv-demuxer-ogg-wasm.wasm \
ogv-demuxer-webm-wasm.js \
ogv-demuxer-webm-wasm.wasm \
ogv-decoder-audio-opus-wasm.js \
ogv-decoder-audio-opus-wasm.wasm \
ogv-decoder-audio-vorbis-wasm.js \
ogv-decoder-audio-vorbis-wasm.wasm \
/z/dist
# ogv-demuxer-ogg.js \
# ogv-demuxer-webm.js \
# ogv-decoder-audio-opus.js \
# ogv-decoder-audio-vorbis.js \
# dynamicaudio.swf \
/z/dist \
&& cp -pv \
ogv-es2017.js /z/dist/ogv.js
# build marked

View File

@@ -2,7 +2,7 @@ all: $(addsuffix .gz, $(wildcard *.*))
%.gz: %
#brotli -q 11 $<
pigz -11 -J 34 -I 573 $<
pigz -11 -I 573 $<
# pigz -11 -J 34 -I 100 -F < $< > $@.first

View File

@@ -37,6 +37,8 @@ gtar=$(command -v gtar || command -v gnutar) || true
sed() { gsed "$@"; }
find() { gfind "$@"; }
sort() { gsort "$@"; }
shuf() { gshuf "$@"; }
nproc() { gnproc; }
sha1sum() { shasum "$@"; }
unexpand() { gunexpand "$@"; }
command -v grealpath >/dev/null &&
@@ -144,6 +146,7 @@ tmpdir="$(
}
ver=
[ -z "$repack" ] &&
git describe --tags >/dev/null 2>/dev/null && {
git_ver="$(git describe --tags)"; # v0.5.5-2-gb164aa0
ver="$(printf '%s\n' "$git_ver" | sed -r 's/^v//')";
@@ -224,7 +227,7 @@ done
rm -rf copyparty/web/dd
f=copyparty/web/browser.css
gzip -d "$f"
sed -r 's/(cursor: )url\([^)]+\), (pointer)/\1\2/; /[0-9]+% \{cursor:/d; /animation: cursor/d' <$f >t
sed -r 's/(cursor: ?)url\([^)]+\), ?(pointer)/\1\2/; /[0-9]+% \{cursor:/d; /animation: ?cursor/d' <$f >t
tmv "$f"
}
@@ -262,14 +265,27 @@ done
gzres() {
command -v pigz &&
pk='pigz -11 -I 256' ||
pk='pigz -11 -I 2560' ||
pk='gzip'
echo "$pk"
find | grep -E '\.(js|css)$' | grep -vF /deps/ | while IFS= read -r f; do
np=$(nproc)
echo "$pk #$np"
while IFS=' ' read -r _ f; do
while true; do
na=$(ps auxwww | grep -F "$pk" | wc -l)
[ $na -le $np ] && break
sleep 0.2
done
echo -n .
$pk "$f"
done
$pk "$f" &
done < <(
find -printf '%s %p\n' |
grep -E '\.(js|css)$' |
grep -vF /deps/ |
sort -nr
)
wait
echo
}
@@ -303,7 +319,7 @@ for d in copyparty dep-j2; do find $d -type f; done |
sed -r 's/(.*)\.(.*)/\2 \1/' | LC_ALL=C sort |
sed -r 's/([^ ]*) (.*)/\2.\1/' | grep -vE '/list1?$' > list1
(grep -vE '\.(gz|br)$' list1; grep -E '\.(gz|br)$' list1) >list || true
(grep -vE '\.(gz|br)$' list1; grep -E '\.(gz|br)$' list1 | shuf) >list || true
echo creating tar
args=(--owner=1000 --group=1000)