diff --git a/.vscode/launch.py b/.vscode/launch.py
index 9a76fa78..df4bd936 100644
--- a/.vscode/launch.py
+++ b/.vscode/launch.py
@@ -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
diff --git a/copyparty/web/up2k.js b/copyparty/web/up2k.js
index 20194ece..16ef1556 100644
--- a/copyparty/web/up2k.js
+++ b/copyparty/web/up2k.js
@@ -132,6 +132,187 @@ 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.addfile = function (entry) {
+ this.tab.push({
+ "hn": entry[0],
+ "ht": entry[1],
+ "hp": entry[2],
+ "in": 'q',
+ "nh": 0, //hashed
+ "nd": 0, //done
+ "pa": [], //percents
+ "pb": [] //active-list
+ });
+ this.ctr["q"]++;
+ this.drawcard("q");
+ if (this.act == "q") {
+ this.addrow(this.genrow(this.tab.length - 1));
+ }
+ };
+
+ 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];
+ fo[field] = html;
+ if (this.is_act(fo.in))
+ ebi('f{0}{1}'.format(nfile, field.slice(1))).innerHTML = html;
+ };
+
+ this.setab = function (nfile, blocks) {
+ var t = [];
+ for (var a = 0; a < blocks; a++)
+ t.push(0);
+
+ this.tab[nfile].pa = t;
+ };
+
+ this.perc = function (n, t, e, t0) {
+ var p = (n + e) * 100.0 / t,
+ td = new Date().getTime() - t0,
+ eta = ((td / 1000) / p) * (100 - p);
+
+ return [p, s2ms(eta)];
+ };
+
+ this.hashed = function (nfile, t0) {
+ var fo = this.tab[nfile];
+ fo.nh++;
+ var p = this.perc(fo.nh, fo.pa.length, 0, t0);
+ fo.hp = '{0}% ({1})'.format(
+ p[0].toFixed(2), p[1]
+ );
+ if (this.is_act(fo.in))
+ ebi('f{0}p'.format(nfile)).innerHTML = fo.hp;
+ };
+
+ this.prog = function (nfile, nchunk, percent, t0) {
+ var fo = this.tab[nfile], pb = fo.pb;
+ var i = pb.indexOf(nchunk);
+ fo.pa[nchunk] = percent;
+ if (percent == 101) {
+ fo.nd++;
+ if (i >= 0)
+ pb.splice(i);
+ }
+ else if (i == -1) {
+ pb.push(nchunk);
+ }
+
+ var extra = 0;
+ for (var a = 0; a < pb.length; a++)
+ extra += fo.pa[a];
+
+ extra /= fo.pa.length;
+
+ var perc = this.perc(fo.nd, fo.pa.length, extra, t0);
+ fo.hp = '{0}% ({1})'.format(
+ perc[0].toFixed(2), perc[1]
+ );
+
+ if (this.is_act(fo.in))
+ ebi('f{0}p'.format(nfile)).innerHTML = fo.hp;
+ };
+
+ this.move = function (nfile, newcat) {
+ var fo = this.tab[nfile],
+ oldcat = fo.in;
+
+ 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.addrow(this.genrow(nfile));
+ }
+ else if (this.is_act(oldcat)) {
+ var tr = ebi("f{0}n".format(nfile)).parentNode;
+ tr.parentNode.removeChild(tr);
+ }
+ };
+
+ 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 = [];
+ 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));
+ }
+ }
+ ebi('u2tab').tBodies[0].innerHTML =
+ '
' + html.join('
\n') + '
';
+ };
+
+ this.genrow = function (nfile) {
+ var r = this.tab[nfile],
+ td1 = '' + r.hn + td + 't">' + r.ht + td + 'p" class="prog">' + r.hp + ' | ';
+ };
+
+ this.addrow = function (html) {
+ var tr = document.createElement('tr');
+ tr.innerHTML = html;
+ 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 +397,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 +416,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 +592,12 @@ function up2k_init(have_crypto) {
if (skip)
continue;
- var tr = document.createElement('tr');
- tr.innerHTML = ' | hashing | | '.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(' '),
+ 'hashing',
+ ''
+ ]);
st.files.push(entry);
st.todo.hash.push(entry);
}
@@ -439,7 +618,11 @@ 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{0}p'.format(t.n));
+ if (!tr)
+ continue;
+
+ tr = tr.parentNode;
tr.parentNode.removeChild(tr);
t.name = undefined;
}
@@ -695,13 +878,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 += ''.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 +897,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 +940,8 @@ function up2k_init(have_crypto) {
var b64str = buf2b64(hslice).replace(/=$/, '');
t.hash.push(b64str);
- prog(t.n, nchunk, col_hashed);
+ pvis.hashed(t.n, t.t1);
if (++nchunk < nchunks) {
- prog(t.n, nchunk, col_hashing);
return segm_next();
}
@@ -776,7 +951,7 @@ 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, 1, 'connecting');
st.busy.hash.splice(st.busy.hash.indexOf(t), 1);
st.todo.handshake.push(t);
};
@@ -821,8 +996,9 @@ function up2k_init(have_crypto) {
msg += '
' + tr + ' (srv), ' + tu + ' (You), ' + sdiff + '';
}
- 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 +1009,7 @@ 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(' '));
}
t.postlist = [];
@@ -847,9 +1023,6 @@ function up2k_init(have_crypto) {
t.postlist.push(idx);
}
- for (var a = 0; a < t.hash.length; a++)
- prog(t.n, a, (t.postlist.indexOf(a) == -1)
- ? col_uploaded : col_hashed);
var done = true;
var msg = '🎷🐛';
@@ -863,7 +1036,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,14 +1044,16 @@ 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.move(t.n, 'ok');
+ pvis.seth(t.n, 2, 'hash {0}, up {1} MB/s'.format(
+ spd1.toFixed(2), spd2.toFixed(2)));
}
else t.t4 = undefined;
tasker();
}
else {
+ pvis.move(t.n, 'ng');
var err = "",
rsp = (xhr.responseText + ''),
ofs = rsp.lastIndexOf('\nURL: ');
@@ -899,8 +1074,8 @@ 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;
+ seth(t.n, 1, "ERROR");
+ seth(t.n, 2, err);
st.busy.handshake.splice(st.busy.handshake.indexOf(t), 1);
tasker();
@@ -940,7 +1115,7 @@ function up2k_init(have_crypto) {
var npart = upt.npart;
var t = st.files[upt.nfile];
- prog(t.n, npart, col_uploading);
+ pvis.seth(t.n, 1, "upping");
var chunksize = get_chunksize(t.size);
var car = npart * chunksize;
@@ -958,18 +1133,18 @@ function up2k_init(have_crypto) {
var xhr = new XMLHttpRequest();
xhr.upload.onprogress = function (xev) {
var perc = xev.loaded / (cdr - car) * 100;
- prog(t.n, npart, '', perc);
+ pvis.prog(t.n, npart, perc, t.t3);
};
xhr.onload = function (xev) {
if (xhr.status == 200) {
- prog(t.n, npart, col_uploaded);
+ pvis.prog(t.n, npart, 101, t.t3);
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';
+ pvis.seth(t.n, 1, 'verifying');
st.todo.handshake.unshift(t);
}
tasker();
@@ -999,24 +1174,6 @@ function up2k_init(have_crypto) {
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';
- }
- }
-
/////
////
/// config ui
@@ -1035,6 +1192,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);
diff --git a/copyparty/web/upload.css b/copyparty/web/upload.css
index d081fd0e..680fe97f 100644
--- a/copyparty/web/upload.css
+++ b/copyparty/web/upload.css
@@ -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;
@@ -83,6 +88,32 @@
#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;
+}
#u2conf {
margin: 1em auto;
width: 30em;
@@ -193,24 +224,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;
diff --git a/copyparty/web/upload.html b/copyparty/web/upload.html
index a9bd2df9..1fb37466 100644
--- a/copyparty/web/upload.html
+++ b/copyparty/web/upload.html
@@ -79,12 +79,23 @@
+
+
-
- filename |
- status |
- progresscleanup |
-
+
+
+ filename |
+ status |
+ progresscleanup |
+
+
+