Compare commits

...

19 Commits

Author SHA1 Message Date
ed
ab09927e7b v0.10.12 2021-04-19 21:58:49 +02:00
ed
779437db67 up2k: more runahead 2021-04-19 21:58:30 +02:00
ed
28cbdb652e v0.10.11 2021-04-19 21:43:08 +02:00
ed
2b2415a7d8 up2k: gotta go faster 2021-04-19 21:29:43 +02:00
ed
746a8208aa v0.10.10 2021-04-19 17:17:07 +02:00
ed
a2a041a98a optimize 2021-04-19 16:54:38 +02:00
ed
10b436e449 browser: add media fragment uris 2021-04-19 16:41:06 +02:00
ed
4d62b34786 browser: add light mode 2021-04-19 15:40:32 +02:00
ed
0546210687 fix up2k progressbars 2021-04-19 13:18:29 +02:00
ed
f8c11faada don't start 2t stuff if there's no backend avail 2021-04-19 13:17:34 +02:00
ed
16d6e9be1f tweaks 2021-04-17 09:24:25 +02:00
ed
aff8185f2e v0.10.9 2021-04-17 01:29:27 +02:00
ed
217d15fe81 up2k: cheap progress bars 2021-04-17 00:57:35 +02:00
ed
171e93c201 up2k: show realtime speeds 2021-04-17 00:01:03 +02:00
ed
acc1d2e9e3 up2k: show some context in the busy-tab 2021-04-16 23:49:57 +02:00
ed
49c2f37154 up2k: replace progressbars with text 2021-04-16 21:23:53 +02:00
ed
69e54497aa yes good 2021-04-14 16:03:15 +02:00
ed
9aa1885669 hide search tab when d2d 2021-04-14 15:23:25 +02:00
ed
4418508513 dodge cpython bug 2021-04-14 14:37:44 +02:00
14 changed files with 735 additions and 173 deletions

10
.vscode/launch.py vendored
View File

@@ -5,6 +5,7 @@
import os
import sys
import shlex
sys.path.insert(0, os.getcwd())
@@ -16,9 +17,16 @@ with open(".vscode/launch.json", "r") as f:
oj = jstyleson.loads(tj)
argv = oj["configurations"][0]["args"]
try:
sargv = " ".join([shlex.quote(x) for x in argv])
print(sys.executable + " -m copyparty " + sargv + "\n")
except:
pass
argv = [os.path.expanduser(x) if x.startswith("~") else x for x in argv]
try:
copyparty(argv)
copyparty(["a"] + argv)
except SystemExit as ex:
if ex.code:
raise

View File

@@ -111,6 +111,8 @@ the browser has the following hotkeys
* `I/K` prev/next folder
* `P` parent folder
you can link a particular timestamp in an audio file by adding it to the URL, such as `&20` / `&20s` / `&1m20` / `&1:20` after the `.../#af-c8960dab`
## zip downloads
@@ -339,7 +341,6 @@ in the `scripts` folder:
roughly sorted by priority
* audio link with timestamp
* separate sqlite table per tag
* audio fingerprinting
* readme.md as epilogue

View File

@@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (0, 10, 8)
VERSION = (0, 10, 12)
CODENAME = "zip it"
BUILD_DT = (2021, 4, 11)
BUILD_DT = (2021, 4, 19)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View File

@@ -111,7 +111,27 @@ class VFS(object):
if rem:
rp += "/" + rem
return fsdec(os.path.realpath(fsenc(rp)))
try:
return fsdec(os.path.realpath(fsenc(rp)))
except:
if not WINDOWS:
raise
# cpython bug introduced in 3.8, still exists in 3.9.1;
# some win7sp1 and win10:20H2 boxes cannot realpath a
# networked drive letter such as b"n:" or b"n:\\"
#
# requirements to trigger:
# * bytestring (not unicode str)
# * just the drive letter (subfolders are ok)
# * networked drive (regular disks and vmhgfs are ok)
# * on an enterprise network (idk, cannot repro with samba)
#
# hits the following exceptions in succession:
# * access denied at L601: "path = _getfinalpathname(path)"
# * "cant concat str to bytes" at L621: "return path + tail"
#
return os.path.realpath(rp)
def ls(self, rem, uname, scandir, lstat=False):
"""return user-readable [fsdir,real,virt] items at vpath"""

View File

@@ -101,17 +101,18 @@ class Up2k(object):
thr.daemon = True
thr.start()
thr = threading.Thread(target=self._tagger)
thr.daemon = True
thr.start()
thr = threading.Thread(target=self._hasher)
thr.daemon = True
thr.start()
thr = threading.Thread(target=self._run_all_mtp)
thr.daemon = True
thr.start()
if self.mtag:
thr = threading.Thread(target=self._tagger)
thr.daemon = True
thr.start()
thr = threading.Thread(target=self._run_all_mtp)
thr.daemon = True
thr.start()
def log(self, msg, c=0):
self.log_func("up2k", msg + "\033[K", c)
@@ -1068,6 +1069,8 @@ class Up2k(object):
with self.mutex:
job = self.registry[ptop].get(wark, None)
if not job:
known = " ".join([x for x in self.registry[ptop].keys()])
self.log("unknown wark [{}], known: {}".format(wark, known))
raise Pebkac(400, "unknown wark")
if chash not in job["need"]:

View File

@@ -284,7 +284,7 @@ a, #files tbody div a:last-child {
line-height: 1em;
}
#wtoggle.sel {
width: 6em;
width: 6.4em;
}
#wtoggle.sel #wzip {
display: inline-block;
@@ -685,3 +685,173 @@ input[type="checkbox"]:checked+label {
font-family: monospace, monospace;
line-height: 2em;
}
html.light {
color: #333;
background: #eee;
text-shadow: none;
}
html.light #ops,
html.light .opbox,
html.light #srch_form {
background: #f7f7f7;
box-shadow: 0 0 .3em #ddd;
border-color: #f7f7f7;
}
html.light #ops a.act {
box-shadow: 0 .2em .2em #ccc;
background: #f7f7f7;
border-color: #07a;
padding-top: .4em;
}
html.light #op_cfg h3 {
border-color: #ccc;
}
html.light .tglbtn,
html.light #tree > a + a {
color: #666;
background: #ddd;
box-shadow: none;
}
html.light .tglbtn:hover,
html.light #tree > a + a:hover {
background: #caf;
}
html.light .tglbtn.on,
html.light #tree > a + a.on {
background: #4a0;
color: #fff;
}
html.light #srv_info {
color: #c83;
text-shadow: 1px 1px 0 #fff;
}
html.light #srv_info span {
color: #000;
}
html.light #treeul a+a {
background: inherit;
color: #06a;
}
html.light #treeul a.hl {
background: #07a;
color: #fff;
}
html.light #tree li {
border-color: #ddd #fff #f7f7f7 #fff;
}
html.light #tree ul {
border-color: #ccc;
}
html.light a,
html.light #ops a,
html.light #files tbody div a:last-child {
color: #06a;
}
html.light #files tbody {
background: #f7f7f7;
}
html.light #files {
box-shadow: 0 0 .3em #ccc;
}
html.light #files thead th {
background: #eee;
}
html.light #files tr+tr td {
border-top: 1px solid #ddd;
}
html.light #files td {
border-bottom: 1px solid #f7f7f7;
}
html.light #files tbody tr:last-child td {
border-bottom: .2em solid #ccc;
}
html.light #files td:nth-child(2n) {
color: #d38;
}
html.light #files tr:hover td {
background: #fff;
}
html.light #files tbody a.play {
color: #c0f;
}
html.light tr.play td {
background: #fc5;
}
html.light tr.play a {
color: #406;
}
html.light #files > thead > tr > th.min span {
background: linear-gradient(90deg, rgba(68,68,68,0), rgba(68,68,68,0.2) 70%, rgba(68,68,68,0.5));
}
html.light #blocked {
background: #eee;
}
html.light #blk_play a,
html.light #blk_abrt a {
background: #fff;
box-shadow: 0 .2em .4em #ddd;
}
html.light #widget a {
color: #fc5;
}
html.light #files tr.sel:hover td {
background: #c37;
}
html.light #files tr.sel td {
color: #fff;
}
html.light #files tr.sel a {
color: #fff;
}
html.light input[type="checkbox"] + label {
color: #333;
}
html.light .opview input[type="text"] {
background: #fff;
color: #333;
box-shadow: 0 0 2px #888;
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 #files td div span {
color: #000;
}
html.light #path {
background: #f7f7f7;
text-shadow: none;
box-shadow: 0 0 .3em #bbb;
}
html.light #path a {
color: #333;
}
html.light #path a:not(:last-child)::after {
border-color: #ccc;
background: none;
border-width: .1em .1em 0 0;
margin: -.2em .3em -.2em -.3em;
}
html.light #path a:hover {
background: none;
color: #60a;
}
html.light #files tbody div a {
color: #d38;
}
html.light #files a:hover,
html.light #files tr.sel a:hover {
color: #000;
background: #fff;
}

View File

@@ -13,8 +13,8 @@
<body>
<div id="ops">
<a href="#" data-dest="" data-desc="close submenu">---</a>
<a href="#" data-perm="read" data-dest="search" data-desc="search for files by attributes, path/name, music tags, or any combination of those.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;foo bar&lt;/code&gt; = must contain both foo and bar,&lt;br /&gt;&lt;code&gt;foo -bar&lt;/code&gt; = must contain foo but not bar,&lt;br /&gt;&lt;code&gt;^yana .opus$&lt;/code&gt; = must start with yana and have the opus extension">🔎</a>
{%- 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.&lt;br /&gt;&lt;br /&gt;&lt;code&gt;foo bar&lt;/code&gt; = must contain both foo and bar,&lt;br /&gt;&lt;code&gt;foo -bar&lt;/code&gt; = must contain foo but not bar,&lt;br /&gt;&lt;code&gt;^yana .opus$&lt;/code&gt; = 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>
{%- 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>
@@ -39,14 +39,17 @@
{%- include 'upload.html' %}
<div id="op_cfg" class="opview opbox">
<h3>key notation</h3>
<div id="key_notation"></div>
<h3>switches</h3>
<div>
<a id="tooltips" class="tglbtn" href="#">tooltips</a>
<a id="lightmode" class="tglbtn" href="#">lightmode</a>
</div>
{%- if have_zip %}
<h3>folder download</h3>
<div id="arc_fmt"></div>
{%- endif %}
<h3>tooltips</h3>
<div><a id="tooltips" class="tglbtn" href="#">enable</a></div>
<h3>key notation</h3>
<div id="key_notation"></div>
</div>
<h1 id="path">
@@ -117,8 +120,8 @@
<a href="#" id="selall">sel.<br />all</a>
<a href="#" id="selinv">sel.<br />inv.</a>
<a href="#" id="selzip">zip</a>
</span>
<a href="#" id="wtico"></a>
</span><a
href="#" id="wtico"></a>
</div>
<div id="widgeti">
<div id="pctl"><a href="#" id="bprev"></a><a href="#" id="bplay"></a><a href="#" id="bnext"></a></div>

View File

@@ -314,8 +314,8 @@ function seek_au_sec(seek) {
mp.au.currentTime = seek;
// ogv.js breaks on .play() during playback
if (mp.au === mp.au_native)
// hack: ogv.js breaks on .play() during playback
mp.au.play();
}
@@ -427,7 +427,7 @@ catch (ex) { }
// plays the tid'th audio file on the page
function play(tid, call_depth) {
function play(tid, seek, call_depth) {
if (mp.order.length == 0)
return alert('no audio found wait what');
@@ -449,7 +449,7 @@ function play(tid, call_depth) {
}
// ogv.js breaks on .play() unless directly user-triggered
var hack_attempt_play = true;
var attempt_play = true;
var url = mp.tracks[tid];
if (need_ogv && /\.(ogg|opus)$/i.test(url)) {
@@ -458,7 +458,7 @@ function play(tid, call_depth) {
}
else if (window['OGVPlayer']) {
mp.au = mp.au_ogvjs = new OGVPlayer();
hack_attempt_play = false;
attempt_play = false;
mp.au.addEventListener('error', evau_error, true);
mp.au.addEventListener('progress', pbar.drawpos, false);
widget.open();
@@ -470,7 +470,7 @@ function play(tid, call_depth) {
show_modal('<h1>loading ogv.js</h1><h2>thanks apple</h2>');
import_js('/.cpr/deps/ogv.js', function () {
play(tid, 1);
play(tid, seek, 1);
});
return;
@@ -498,21 +498,26 @@ function play(tid, call_depth) {
ebi(oid).parentElement.parentElement.className += ' play';
try {
if (hack_attempt_play)
if (attempt_play)
mp.au.play();
if (mp.au.paused)
autoplay_blocked();
autoplay_blocked(seek);
else if (seek) {
seek_au_sec(seek);
}
var o = ebi(oid);
o.setAttribute('id', 'thx_js');
if (window.history && history.replaceState) {
hist_replace(document.location.pathname + '#' + oid);
if (!seek) {
var o = ebi(oid);
o.setAttribute('id', 'thx_js');
if (window.history && history.replaceState) {
hist_replace(document.location.pathname + '#' + oid);
}
else {
document.location.hash = oid;
}
o.setAttribute('id', oid);
}
else {
document.location.hash = oid;
}
o.setAttribute('id', oid);
pbar.drawbuf();
return true;
@@ -576,7 +581,7 @@ function unblocked() {
// show ui to manually start playback of a linked song
function autoplay_blocked() {
function autoplay_blocked(seek) {
show_modal(
'<div id="blk_play"><a href="#" id="blk_go"></a></div>' +
'<div id="blk_abrt"><a href="#" id="blk_na">Cancel<br />(show file list)</a></div>');
@@ -592,6 +597,8 @@ function autoplay_blocked() {
if (e) e.preventDefault();
unblocked();
mp.au.play();
if (seek)
seek_au_sec(seek);
};
na.onclick = unblocked;
}
@@ -600,8 +607,20 @@ function autoplay_blocked() {
// autoplay linked track
(function () {
var v = location.hash;
if (v && v.length == 12 && v.indexOf('#af-') === 0)
play(v.slice(2));
if (v && v.indexOf('#af-') === 0) {
var id = v.slice(2).split('&');
if (id[0].length != 10)
return;
if (id.length == 1)
return play(id[0]);
var m = /^[Tt=0]*([0-9]+[Mm:])?0*([0-9]+)[Ss]?$/.exec(id[1]);
if (!m)
return play(id[0]);
return play(id[0], parseInt(m[1] || 0) * 60 + parseInt(m[2] || 0));
}
})();
@@ -1549,8 +1568,11 @@ function addcrc() {
ebi('unsearch') ? 'div>a:last-child' : 'a'));
for (var a = 0, aa = links.length; a < aa; a++)
if (!links[a].getAttribute('id'))
links[a].setAttribute('id', 'f-' + crc32(links[a].textContent || links[a].innerText));
if (!links[a].getAttribute('id')) {
var crc = crc32(links[a].textContent || links[a].innerText);
crc = ('00000000' + crc).slice(-8);
links[a].setAttribute('id', 'f-' + crc);
}
}
@@ -1577,6 +1599,24 @@ function addcrc() {
})();
(function () {
var light = bcfg_get('lightmode', false);
function freshen() {
document.documentElement.setAttribute("class", light ? "light" : "");
}
ebi('lightmode').onclick = function (e) {
ev(e);
light = !light;
bcfg_set('lightmode', light);
freshen();
};
freshen();
})();
var arcfmt = (function () {
if (!ebi('arc_fmt'))
return { "render": function () { } };

View File

@@ -138,10 +138,10 @@ var md_opt = {
document.documentElement.setAttribute("class", dark ? "dark" : "");
btn.innerHTML = "go " + (dark ? "light" : "dark");
if (window.localStorage)
localStorage.setItem('darkmode', dark ? 1 : 0);
localStorage.setItem('lightmode', dark ? 0 : 1);
};
btn.onclick = toggle;
if (window.localStorage && localStorage.getItem('darkmode') == 1)
if (window.localStorage && localStorage.getItem('lightmode') != 1)
toggle();
})();

View File

@@ -31,12 +31,12 @@ var md_opt = {
var lightswitch = (function () {
var fun = function () {
var dark = !!!document.documentElement.getAttribute("class");
var dark = !document.documentElement.getAttribute("class");
document.documentElement.setAttribute("class", dark ? "dark" : "");
if (window.localStorage)
localStorage.setItem('darkmode', dark ? 1 : 0);
localStorage.setItem('lightmode', dark ? 0 : 1);
};
if (window.localStorage && localStorage.getItem('darkmode') == 1)
if (window.localStorage && localStorage.getItem('lightmode') != 1)
fun();
return fun;

View File

@@ -38,7 +38,7 @@
</div>
<script>
if (window.localStorage && localStorage.getItem('darkmode') == 1)
if (window.localStorage && localStorage.getItem('lightmode') != 1)
document.documentElement.setAttribute("class", "dark");
</script>

View File

@@ -132,6 +132,283 @@ function up2k_flagbus() {
return flag;
}
function U2pvis(act, btns) {
this.act = act;
this.ctr = { "ok": 0, "ng": 0, "bz": 0, "q": 0 };
this.tab = [];
this.head = 0;
this.tail = -1;
this.wsz = 3;
this.addfile = function (entry, sz) {
this.tab.push({
"hn": entry[0],
"ht": entry[1],
"hp": entry[2],
"in": 'q',
"nh": 0, //hashed
"nd": 0, //done
"cb": [], // bytes done in chunk
"bt": sz, // bytes total
"bd": 0, // bytes done
"bd0": 0 // upload start
});
this.ctr["q"]++;
this.drawcard("q");
if (this.act == "q") {
this.addrow(this.tab.length - 1);
}
if (this.act == "bz") {
this.bzw();
}
};
this.is_act = function (card) {
if (this.act == "done")
return card == "ok" || card == "ng";
return this.act == card;
}
this.seth = function (nfile, field, html) {
var fo = this.tab[nfile];
field = ['hn', 'ht', 'hp'][field];
if (fo[field] === html)
return;
fo[field] = html;
if (!this.is_act(fo.in))
return;
var obj = ebi('f{0}{1}'.format(nfile, field.slice(1)));
obj.innerHTML = html;
if (field == 'hp') {
obj.style.color = '';
obj.style.background = '';
}
};
this.setab = function (nfile, nblocks) {
var t = [];
for (var a = 0; a < nblocks; a++)
t.push(0);
this.tab[nfile].cb = t;
};
this.setat = function (nfile, blocktab) {
this.tab[nfile].cb = blocktab;
var bd = 0;
for (var a = 0; a < blocktab.length; a++)
bd += blocktab[a];
this.tab[nfile].bd = bd;
this.tab[nfile].bd0 = bd;
};
this.perc = function (bd, bd0, sz, t0) {
var td = new Date().getTime() - t0,
p = bd * 100.0 / sz,
nb = bd - bd0,
spd = nb / (td / 1000),
eta = (sz - bd) / spd;
return [p, s2ms(eta), spd / (1024 * 1024)];
};
this.hashed = function (fobj) {
var fo = this.tab[fobj.n];
var nb = fo.bt * (++fo.nh / fo.cb.length);
var p = this.perc(nb, 0, fobj.size, fobj.t1);
fo.hp = '{0}%, {1}, {2} MB/s'.format(
p[0].toFixed(2), p[1], p[2].toFixed(2)
);
if (!this.is_act(fo.in))
return;
var obj = ebi('f{0}p'.format(fobj.n));
obj.innerHTML = fo.hp;
obj.style.color = '#fff';
var o1 = p[0] - 2, o2 = p[0] - 0.1, o3 = p[0];
obj.style.background = 'linear-gradient(90deg, #025, #06a ' + o1 + '%, #09d ' + o2 + '%, #333 ' + o3 + '%, #333 99%, #777)';
};
this.prog = function (fobj, nchunk, cbd) {
var fo = this.tab[fobj.n];
var delta = cbd - fo.cb[nchunk];
fo.cb[nchunk] = cbd;
fo.bd += delta;
var p = this.perc(fo.bd, fo.bd0, fo.bt, fobj.t3);
fo.hp = '{0}%, {1}, {2} MB/s'.format(
p[0].toFixed(2), p[1], p[2].toFixed(2)
);
if (!this.is_act(fo.in))
return;
var obj = ebi('f{0}p'.format(fobj.n));
obj.innerHTML = fo.hp;
obj.style.color = '#fff';
var o1 = p[0] - 2, o2 = p[0] - 0.1, o3 = p[0];
obj.style.background = 'linear-gradient(90deg, #050, #270 ' + o1 + '%, #4b0 ' + o2 + '%, #333 ' + o3 + '%, #333 99%, #777)';
};
this.move = function (nfile, newcat) {
var fo = this.tab[nfile],
oldcat = fo.in,
bz_act = this.act == "bz";
if (oldcat == newcat) {
throw 42;
}
fo.in = newcat;
this.ctr[oldcat]--;
this.ctr[newcat]++;
this.drawcard(oldcat);
this.drawcard(newcat);
if (this.is_act(newcat)) {
this.tail++;
if (!ebi('f' + nfile))
this.addrow(nfile);
}
else if (this.is_act(oldcat)) {
this.head++;
if (!bz_act) {
var tr = ebi("f" + nfile);
tr.parentNode.removeChild(tr);
}
}
if (bz_act) {
this.bzw();
}
};
this.bzw_log = function (first, last) {
console.log("first %d head %d tail %d last %d", first, this.head, this.tail, last);
var trs = document.querySelectorAll('#u2tab>tbody>tr'), msg = [];
for (var a = 0; a < trs.length; a++)
msg.push(trs[a].getAttribute('id'));
console.log(msg.join(' '));
}
this.bzw = function () {
var first = document.querySelector('#u2tab>tbody>tr:first-child');
if (!first)
return;
var last = document.querySelector('#u2tab>tbody>tr:last-child');
first = parseInt(first.getAttribute('id').slice(1));
last = parseInt(last.getAttribute('id').slice(1));
//this.bzw_log(first, last);
while (this.head - first > this.wsz) {
var obj = ebi('f' + (first++));
obj.parentNode.removeChild(obj);
}
while (last - this.tail < this.wsz && last < this.tab.length - 2) {
var obj = ebi('f' + (++last));
if (!obj)
this.addrow(last);
}
//this.bzw_log(first, last);
//console.log('--');
};
this.drawcard = function (cat) {
var cards = document.querySelectorAll('#u2cards>a>span');
if (cat == "q") {
cards[4].innerHTML = this.ctr[cat];
return;
}
if (cat == "bz") {
cards[3].innerHTML = this.ctr[cat];
return;
}
cards[2].innerHTML = this.ctr["ok"] + this.ctr["ng"];
if (cat == "ng") {
cards[1].innerHTML = this.ctr[cat];
}
if (cat == "ok") {
cards[0].innerHTML = this.ctr[cat];
}
};
this.changecard = function (card) {
this.act = card;
var html = [];
this.head = -1;
this.tail = -1;
for (var a = 0; a < this.tab.length; a++) {
var rt = this.tab[a].in;
if (this.is_act(rt)) {
html.push(this.genrow(a, true));
this.tail = a;
if (this.head == -1)
this.head = a;
}
}
if (this.head == -1) {
this.head = this.tab.length;
this.tail = this.head - 1;
}
if (card == "bz") {
for (var a = this.head - 1; a >= this.head - this.wsz && a >= 0; a--) {
html.unshift(this.genrow(a, true).replace(/><td>/, "><td>a "));
}
for (var a = this.tail + 1; a <= this.tail + this.wsz && a < this.tab.length; a++) {
html.push(this.genrow(a, true).replace(/><td>/, "><td>b "));
}
}
ebi('u2tab').tBodies[0].innerHTML = html.join('\n');
};
this.genrow = function (nfile, as_html) {
var r = this.tab[nfile],
td1 = '<td id="f' + nfile,
td = '</td>' + td1,
ret = td1 + 'n">' + r.hn +
td + 't">' + r.ht +
td + 'p" class="prog">' + r.hp + '</td>';
if (as_html)
return '<tr id="f' + nfile + '">' + ret + '</tr>';
var obj = document.createElement('tr');
obj.setAttribute('id', 'f' + nfile);
obj.innerHTML = ret;
return obj;
};
this.addrow = function (nfile) {
var tr = this.genrow(nfile);
ebi('u2tab').tBodies[0].appendChild(tr);
};
var that = this;
btns = document.querySelectorAll(btns + '>a[act]');
for (var a = 0; a < btns.length; a++) {
btns[a].onclick = function (e) {
ev(e);
var newtab = this.getAttribute('act');
for (var b = 0; b < btns.length; b++) {
btns[b].className = (
btns[b].getAttribute('act') == newtab) ? 'act' : '';
}
that.changecard(newtab);
};
}
}
function up2k_init(have_crypto) {
//have_crypto = false;
var need_filereader_cache = undefined;
@@ -216,10 +493,6 @@ function up2k_init(have_crypto) {
var flag_en = bcfg_get('flag_en', false);
var fsearch = bcfg_get('fsearch', false);
var col_hashing = '#00bbff';
var col_hashed = '#004466';
var col_uploading = '#ffcc44';
var col_uploaded = '#00bb00';
var fdom_ctr = 0;
var st = {
"files": [],
@@ -239,6 +512,8 @@ function up2k_init(have_crypto) {
}
};
var pvis = new U2pvis("bz", '#u2cards');
var bobslice = null;
if (window.File)
bobslice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice;
@@ -413,12 +688,12 @@ function up2k_init(have_crypto) {
if (skip)
continue;
var tr = document.createElement('tr');
tr.innerHTML = '<td id="f{0}n"></td><td id="f{0}t">hashing</td><td id="f{0}p" class="prog"></td>'.format(st.files.length);
tr.getElementsByTagName('td')[0].innerHTML = fsearch ? esc(entry.name) : linksplit(
esc(uricom_dec(entry.purl)[0] + entry.name)).join(' ');
ebi('u2tab').appendChild(tr);
pvis.addfile([
fsearch ? esc(entry.name) : linksplit(
esc(uricom_dec(entry.purl)[0] + entry.name)).join(' '),
'📐 hash',
''
], fobj.size);
st.files.push(entry);
st.todo.hash.push(entry);
}
@@ -439,7 +714,10 @@ function up2k_init(have_crypto) {
for (var a = 0; a < st.files.length; a++) {
var t = st.files[a];
if (t.done && t.name) {
var tr = ebi('f{0}p'.format(t.n)).parentNode;
var tr = ebi('f' + t.n);
if (!tr)
continue;
tr.parentNode.removeChild(tr);
t.name = undefined;
}
@@ -462,7 +740,8 @@ function up2k_init(have_crypto) {
function hashing_permitted() {
if (multitask) {
var ahead = st.bytes.hashed - st.bytes.uploaded;
return ahead < 1024 * 1024 * 128;
return ahead < 1024 * 1024 * 1024 * 4 &&
st.todo.handshake.length + st.busy.handshake.length < 16;
}
return handshakes_permitted() && 0 ==
st.todo.handshake.length +
@@ -695,13 +974,8 @@ function up2k_init(have_crypto) {
if (!need_filereader_cache)
subchunks = 1;
var pb_html = '';
var pb_perc = 99.9 / nchunks;
for (var a = 0; a < nchunks; a++)
pb_html += '<div id="f{0}p{1}" style="width:{2}%"><div></div></div>'.format(
t.n, a, pb_perc);
ebi('f{0}p'.format(t.n)).innerHTML = pb_html;
pvis.setab(t.n, nchunks);
pvis.move(t.n, 'bz');
var reader = new FileReader();
@@ -719,8 +993,6 @@ function up2k_init(have_crypto) {
reader.readAsArrayBuffer(
bobslice.call(t.fobj, car, cdr));
prog(t.n, nchunk, col_hashing);
};
var segm_load = function (e) {
@@ -764,9 +1036,8 @@ function up2k_init(have_crypto) {
var b64str = buf2b64(hslice).replace(/=$/, '');
t.hash.push(b64str);
prog(t.n, nchunk, col_hashed);
pvis.hashed(t);
if (++nchunk < nchunks) {
prog(t.n, nchunk, col_hashing);
return segm_next();
}
@@ -776,13 +1047,14 @@ function up2k_init(have_crypto) {
alert('{0} ms, {1} MB/s\n'.format(t.t2 - t.t1, spd.toFixed(3)) + t.hash.join('\n'));
}
ebi('f{0}t'.format(t.n)).innerHTML = 'connecting';
pvis.seth(t.n, 2, 'hashing done');
pvis.seth(t.n, 1, '📦 wait');
st.busy.hash.splice(st.busy.hash.indexOf(t), 1);
st.todo.handshake.push(t);
};
var segm_err = function () {
alert('y o u b r o k e i t\n\n(was that a folder? just files please)');
alert('y o u b r o k e i t\nerror: ' + reader.error);
};
segm_next();
@@ -821,8 +1093,9 @@ function up2k_init(have_crypto) {
msg += '<br /><small>' + tr + ' (srv), ' + tu + ' (You), ' + sdiff + '</span></span>';
}
ebi('f{0}p'.format(t.n)).innerHTML = msg;
ebi('f{0}t'.format(t.n)).innerHTML = smsg;
pvis.seth(t.n, 2, msg);
pvis.seth(t.n, 1, smsg);
pvis.move(t.n, smsg == '404' ? 'ng' : 'ok');
st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
st.bytes.uploaded += t.size;
t.done = true;
@@ -833,7 +1106,15 @@ function up2k_init(have_crypto) {
if (response.name !== t.name) {
// file exists; server renamed us
t.name = response.name;
ebi('f{0}n'.format(t.n)).innerHTML = linksplit(esc(t.purl + t.name)).join(' ');
pvis.seth(t.n, 0, linksplit(esc(t.purl + t.name)).join(' '));
}
var chunksize = get_chunksize(t.size);
var cdr_idx = Math.ceil(t.size / chunksize) - 1;
var cdr_sz = (t.size % chunksize) || chunksize;
var cbd = [];
for (var a = 0; a <= cdr_idx; a++) {
cbd.push(a == cdr_idx ? cdr_sz : chunksize);
}
t.postlist = [];
@@ -846,10 +1127,11 @@ function up2k_init(have_crypto) {
missing[a], JSON.stringify(t)));
t.postlist.push(idx);
cbd[idx] = 0;
}
for (var a = 0; a < t.hash.length; a++)
prog(t.n, a, (t.postlist.indexOf(a) == -1)
? col_uploaded : col_hashed);
pvis.setat(t.n, cbd);
pvis.prog(t, 0, cbd[0]);
var done = true;
var msg = '&#x1f3b7;&#x1f41b;';
@@ -863,7 +1145,7 @@ function up2k_init(have_crypto) {
msg = 'uploading';
done = false;
}
ebi('f{0}t'.format(t.n)).innerHTML = msg;
pvis.seth(t.n, 1, msg);
st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
if (done) {
@@ -871,8 +1153,9 @@ function up2k_init(have_crypto) {
st.bytes.uploaded += t.size - t.bytes_uploaded;
var spd1 = (t.size / ((t.t2 - t.t1) / 1000.)) / (1024 * 1024.);
var spd2 = (t.size / ((t.t4 - t.t3) / 1000.)) / (1024 * 1024.);
ebi('f{0}p'.format(t.n)).innerHTML = 'hash {0}, up {1} MB/s'.format(
spd1.toFixed(2), spd2.toFixed(2));
pvis.seth(t.n, 2, 'hash {0}, up {1} MB/s'.format(
spd1.toFixed(2), spd2.toFixed(2)));
pvis.move(t.n, 'ok');
}
else t.t4 = undefined;
@@ -899,18 +1182,19 @@ function up2k_init(have_crypto) {
}
}
if (err != "") {
ebi('f{0}t'.format(t.n)).innerHTML = "ERROR";
ebi('f{0}p'.format(t.n)).innerHTML = err;
pvis.seth(t.n, 1, "ERROR");
pvis.seth(t.n, 2, err);
pvis.move(t.n, 'ng');
st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
tasker();
return;
}
alert("server broke (error {0}):\n\"{1}\"\n".format(
xhr.status,
(xhr.response && xhr.response.err) ||
(xhr.responseText && xhr.responseText) ||
"no further information"));
alert("server broke; hs-err {0} on file [{1}]:\n".format(
xhr.status, t.name) + (
(xhr.response && xhr.response.err) ||
(xhr.responseText && xhr.responseText) ||
"no further information"));
}
};
@@ -939,8 +1223,10 @@ function up2k_init(have_crypto) {
var npart = upt.npart;
var t = st.files[upt.nfile];
if (!t.t3)
t.t3 = new Date().getTime();
prog(t.n, npart, col_uploading);
pvis.seth(t.n, 1, "🚀 send");
var chunksize = get_chunksize(t.size);
var car = npart * chunksize;
@@ -948,73 +1234,40 @@ function up2k_init(have_crypto) {
if (cdr >= t.size)
cdr = t.size;
var reader = new FileReader();
reader.onerror = function () {
alert('y o u b r o k e i t\n\n(was that a folder? just files please)');
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function (xev) {
pvis.prog(t, npart, xev.loaded);
};
reader.onload = function (e) {
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function (xev) {
var perc = xev.loaded / (cdr - car) * 100;
prog(t.n, npart, '', perc);
};
xhr.onload = function (xev) {
if (xhr.status == 200) {
prog(t.n, npart, col_uploaded);
st.bytes.uploaded += cdr - car;
t.bytes_uploaded += cdr - car;
st.busy.upload.splice(st.busy.upload.indexOf(upt), 1);
t.postlist.splice(t.postlist.indexOf(npart), 1);
if (t.postlist.length == 0) {
t.t4 = new Date().getTime();
ebi('f{0}t'.format(t.n)).innerHTML = 'verifying';
st.todo.handshake.unshift(t);
}
tasker();
xhr.onload = function (xev) {
if (xhr.status == 200) {
pvis.prog(t, npart, cdr - car);
st.bytes.uploaded += cdr - car;
t.bytes_uploaded += cdr - car;
st.busy.upload.splice(st.busy.upload.indexOf(upt), 1);
t.postlist.splice(t.postlist.indexOf(npart), 1);
if (t.postlist.length == 0) {
t.t4 = new Date().getTime();
pvis.seth(t.n, 1, 'verifying');
st.todo.handshake.unshift(t);
}
else
alert("server broke (error {0}):\n\"{1}\"\n".format(
xhr.status,
tasker();
}
else
alert("server broke; cu-err {0} on file [{1}]:\n".format(
xhr.status, t.name) + (
(xhr.response && xhr.response.err) ||
(xhr.responseText && xhr.responseText) ||
"no further information"));
};
xhr.open('POST', t.purl + 'chunkpit.php', true);
//xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart].substr(1) + "x");
xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart]);
xhr.setRequestHeader("X-Up2k-Wark", t.wark);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
if (xhr.overrideMimeType)
xhr.overrideMimeType('Content-Type', 'application/octet-stream');
xhr.responseType = 'text';
xhr.send(e.target.result);
if (!t.t3)
t.t3 = new Date().getTime();
};
xhr.open('POST', t.purl + 'chunkpit.php', true);
xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart]);
xhr.setRequestHeader("X-Up2k-Wark", t.wark);
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
if (xhr.overrideMimeType)
xhr.overrideMimeType('Content-Type', 'application/octet-stream');
reader.readAsArrayBuffer(bobslice.call(t.fobj, car, cdr));
}
/////
////
/// progress bar
//
function prog(nfile, nchunk, color, percent) {
var n1 = ebi('f{0}p{1}'.format(nfile, nchunk));
var n2 = n1.getElementsByTagName('div')[0];
if (percent === undefined) {
n1.style.background = color;
n2.style.display = 'none';
}
else {
n2.style.width = percent + '%';
n2.style.display = 'block';
}
xhr.responseType = 'text';
xhr.send(bobslice.call(t.fobj, car, cdr));
}
/////
@@ -1035,6 +1288,7 @@ function up2k_init(have_crypto) {
if (btn.parentNode !== parent) {
parent.appendChild(btn);
ebi('u2conf').setAttribute('class', wide ? 'has_btn' : '');
ebi('u2cards').setAttribute('class', wide ? 'w' : '');
}
}
window.addEventListener('resize', onresize);
@@ -1070,14 +1324,14 @@ function up2k_init(have_crypto) {
var obj = ebi('nthread');
if (dir.target) {
obj.style.background = '#922';
clmod(obj, 'err', 1);
var v = Math.floor(parseInt(obj.value));
if (v < 1 || v > 8 || v !== v)
return;
parallel_uploads = v;
swrite('nthread', v);
obj.style.background = '#444';
clmod(obj, 'err');
return;
}

View File

@@ -47,6 +47,11 @@
margin: -1.5em 0;
padding: .8em 0;
width: 100%;
max-width: 12em;
display: inline-block;
}
#u2conf #u2btn_cw {
text-align: right;
}
#u2notbtn {
display: none;
@@ -72,6 +77,7 @@
}
#u2tab td:nth-child(2) {
width: 5em;
white-space: nowrap;
}
#u2tab td:nth-child(3) {
width: 40%;
@@ -83,6 +89,35 @@
#u2tab tr+tr:hover td {
background: #222;
}
#u2cards {
margin: 2.5em auto -2.5em auto;
text-align: center;
}
#u2cards.w {
width: 45em;
text-align: left;
}
#u2cards a {
padding: .2em 1em;
border: 1px solid #777;
border-width: 0 0 1px 0;
background: linear-gradient(to bottom, #333, #222);
}
#u2cards a:first-child {
border-radius: .4em 0 0 0;
}
#u2cards a:last-child {
border-radius: 0 .4em 0 0;
}
#u2cards a.act {
border-width: 1px 1px 0 1px;
border-radius: .3em .3em 0 0;
margin-left: -1px;
background: transparent;
}
#u2cards span {
color: #fff;
}
#u2conf {
margin: 1em auto;
width: 30em;
@@ -106,6 +141,9 @@
font-size: 1.2em;
padding: .15em 0;
}
#u2conf .txtbox.err {
background: #922;
}
#u2conf a {
color: #fff;
background: #c38;
@@ -193,24 +231,6 @@
.prog {
font-family: monospace;
}
.prog>div {
display: inline-block;
position: relative;
overflow: hidden;
margin: 0;
padding: 0;
height: 1.1em;
margin-bottom: -.15em;
box-shadow: -1px -1px 0 inset rgba(255,255,255,0.1);
}
.prog>div>div {
width: 0%;
position: absolute;
left: 0;
top: 0;
bottom: 0;
background: #0a0;
}
#u2tab a>span {
font-weight: bold;
font-style: italic;
@@ -221,3 +241,35 @@
float: right;
margin-bottom: -.3em;
}
html.light #u2btn {
box-shadow: .4em .4em 0 #ccc;
}
html.light #u2cards span {
color: #000;
}
html.light #u2cards a {
background: linear-gradient(to bottom, #eee, #fff);
}
html.light #u2cards a.act {
background: inherit;
}
html.light #u2conf .txtbox {
background: #fff;
color: #444;
}
html.light #u2conf .txtbox.err {
background: #f96;
color: #300;
}
html.light #u2cdesc {
background: #fff;
border: none;
}
html.light #op_up2k.srch #u2btn {
border-color: #a80;
}

View File

@@ -79,12 +79,23 @@
</div>
</div>
<div id="u2cards">
<a href="#" act="ok">ok <span>0</span></a><a
href="#" act="ng">ng <span>0</span></a><a
href="#" act="done">done <span>0</span></a><a
href="#" act="bz" class="act">busy <span>0</span></a><a
href="#" act="q">que <span>0</span></a>
</div>
<table id="u2tab">
<tr>
<td>filename</td>
<td>status</td>
<td>progress<a href="#" id="u2cleanup">cleanup</a></td>
</tr>
<thead>
<tr>
<td>filename</td>
<td>status</td>
<td>progress<a href="#" id="u2cleanup">cleanup</a></td>
</tr>
</thead>
<tbody></tbody>
</table>
<p id="u2foot"></p>