mirror of
https://github.com/9001/copyparty.git
synced 2025-11-06 06:43:53 +00:00
Compare commits
11 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9761b4e3e9 | ||
|
|
0cf6924dca | ||
|
|
5fd81e9f90 | ||
|
|
52bf6f892b | ||
|
|
f3cce232a4 | ||
|
|
53d3c8b28e | ||
|
|
83fec3cca7 | ||
|
|
3cefc99b7d | ||
|
|
3a38dcbc05 | ||
|
|
7ff08bce57 | ||
|
|
fd490af434 |
26
README.md
26
README.md
@@ -27,6 +27,7 @@ turn your phone or raspi into a portable file server with resumable uploads/down
|
|||||||
* [metadata from audio files](#metadata-from-audio-files)
|
* [metadata from audio files](#metadata-from-audio-files)
|
||||||
* [file parser plugins](#file-parser-plugins)
|
* [file parser plugins](#file-parser-plugins)
|
||||||
* [complete examples](#complete-examples)
|
* [complete examples](#complete-examples)
|
||||||
|
* [browser support](#browser-support)
|
||||||
* [client examples](#client-examples)
|
* [client examples](#client-examples)
|
||||||
* [dependencies](#dependencies)
|
* [dependencies](#dependencies)
|
||||||
* [optional gpl stuff](#optional-gpl-stuff)
|
* [optional gpl stuff](#optional-gpl-stuff)
|
||||||
@@ -97,6 +98,7 @@ summary: it works! you can use it! (but technically not even close to beta)
|
|||||||
* Windows: python 3.7 and older cannot read tags with ffprobe, so use mutagen or upgrade
|
* Windows: python 3.7 and older cannot read tags with ffprobe, so use mutagen or upgrade
|
||||||
* Windows: python 2.7 cannot index non-ascii filenames with `-e2d`
|
* Windows: python 2.7 cannot index non-ascii filenames with `-e2d`
|
||||||
* Windows: python 2.7 cannot handle filenames with mojibake
|
* Windows: python 2.7 cannot handle filenames with mojibake
|
||||||
|
* hiding the contents at url `/d1/d2/d3` using `-v :d1/d2/d3:cd2d` has the side-effect of creating databases (for files/tags) inside folders d1 and d2, and those databases take precedence over the main db at the top of the vfs - this means all files in d2 and below will be reindexed unless you already had a vfs entry at or below d2
|
||||||
* probably more, pls let me know
|
* probably more, pls let me know
|
||||||
|
|
||||||
|
|
||||||
@@ -195,6 +197,29 @@ copyparty can invoke external programs to collect additional metadata for files
|
|||||||
`python copyparty-sfx.py -v /mnt/nas/music:/music:r -e2dsa -e2ts -mtp .bpm=f,audio-bpm.py -mtp key=f,audio-key.py`
|
`python copyparty-sfx.py -v /mnt/nas/music:/music:r -e2dsa -e2ts -mtp .bpm=f,audio-bpm.py -mtp key=f,audio-key.py`
|
||||||
|
|
||||||
|
|
||||||
|
# browser support
|
||||||
|
|
||||||
|
| feature | ie6 | ie9 | ie10 | ie11 | ff 52+ | chr 49+ |
|
||||||
|
| --------------- | --- | --- | ---- | ---- | ------ | ------- |
|
||||||
|
| browse files | yep | yep | yep | yep | yep | yep |
|
||||||
|
| basic uploader | yep | yep | yep | yep | yep | yep |
|
||||||
|
| make directory | yep | yep | yep | yep | yep | yep |
|
||||||
|
| send message | yep | yep | yep | yep | yep | yep |
|
||||||
|
| set sort order | - | yep | yep | yep | yep | yep |
|
||||||
|
| zip selection | - | yep | yep | yep | yep | yep |
|
||||||
|
| directory tree | - | - | `*1` | yep | yep | yep |
|
||||||
|
| up2k | - | - | yep | yep | yep | yep |
|
||||||
|
| icons work | - | - | yep | yep | yep | yep |
|
||||||
|
| markdown editor | - | - | yep | yep | yep | yep |
|
||||||
|
| markdown viewer | - | - | yep | yep | yep | yep |
|
||||||
|
| play mp3/mp4 | - | yep | yep | yep | yep | yep |
|
||||||
|
| play ogg/opus | - | - | - | - | yep | yep |
|
||||||
|
|
||||||
|
* internet explorer 6 to 8 (and netscape 4.0) behave the same
|
||||||
|
* firefox 52 and chrome 49 are the last winxp versions
|
||||||
|
* `*1` only public folders (login session is dropped) and no history / back-button
|
||||||
|
|
||||||
|
|
||||||
# client examples
|
# client examples
|
||||||
|
|
||||||
* javascript: dump some state into a file (two separate examples)
|
* javascript: dump some state into a file (two separate examples)
|
||||||
@@ -305,7 +330,6 @@ roughly sorted by priority
|
|||||||
* reduce up2k roundtrips
|
* reduce up2k roundtrips
|
||||||
* start from a chunk index and just go
|
* start from a chunk index and just go
|
||||||
* terminate client on bad data
|
* terminate client on bad data
|
||||||
* drop onto folders
|
|
||||||
* `os.copy_file_range` for up2k cloning
|
* `os.copy_file_range` for up2k cloning
|
||||||
* up2k partials ui
|
* up2k partials ui
|
||||||
* support pillow-simd
|
* support pillow-simd
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
VERSION = (0, 10, 3)
|
VERSION = (0, 10, 7)
|
||||||
CODENAME = "zip it"
|
CODENAME = "zip it"
|
||||||
BUILD_DT = (2021, 3, 29)
|
BUILD_DT = (2021, 4, 3)
|
||||||
|
|
||||||
S_VERSION = ".".join(map(str, VERSION))
|
S_VERSION = ".".join(map(str, VERSION))
|
||||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||||
|
|||||||
@@ -168,8 +168,13 @@ class VFS(object):
|
|||||||
for vpath, apath, files, rd, vd in self.walk("", vrem, uname, dots, scandir):
|
for vpath, apath, files, rd, vd in self.walk("", vrem, uname, dots, scandir):
|
||||||
if flt:
|
if flt:
|
||||||
files = [x for x in files if x[0] in flt]
|
files = [x for x in files if x[0] in flt]
|
||||||
rd = [x for x in rd if x[0] in flt]
|
|
||||||
vd = {x: y for x, y in vd.items() if x in flt}
|
rm = [x for x in rd if x[0] not in flt]
|
||||||
|
[rd.remove(x) for x in rm]
|
||||||
|
|
||||||
|
rm = [x for x in vd.keys() if x not in flt]
|
||||||
|
[vd.pop(x) for x in rm]
|
||||||
|
|
||||||
flt = None
|
flt = None
|
||||||
|
|
||||||
# print(repr([vpath, apath, [x[0] for x in files]]))
|
# print(repr([vpath, apath, [x[0] for x in files]]))
|
||||||
|
|||||||
@@ -321,8 +321,19 @@ class HttpCli(object):
|
|||||||
elif "print" in opt:
|
elif "print" in opt:
|
||||||
reader, _ = self.get_body_reader()
|
reader, _ = self.get_body_reader()
|
||||||
for buf in reader:
|
for buf in reader:
|
||||||
buf = buf.decode("utf-8", "replace")
|
orig = buf.decode("utf-8", "replace")
|
||||||
self.log("urlform @ {}\n {}\n".format(self.vpath, buf))
|
m = "urlform_raw {} @ {}\n {}\n"
|
||||||
|
self.log(m.format(len(orig), self.vpath, orig))
|
||||||
|
try:
|
||||||
|
plain = unquote(buf.replace(b"+", b" "))
|
||||||
|
plain = plain.decode("utf-8", "replace")
|
||||||
|
if buf.startswith(b"msg="):
|
||||||
|
plain = plain[4:]
|
||||||
|
|
||||||
|
m = "urlform_dec {} @ {}\n {}\n"
|
||||||
|
self.log(m.format(len(plain), self.vpath, plain))
|
||||||
|
except Exception as ex:
|
||||||
|
self.log(repr(ex))
|
||||||
|
|
||||||
if "get" in opt:
|
if "get" in opt:
|
||||||
return self.handle_get()
|
return self.handle_get()
|
||||||
|
|||||||
@@ -622,7 +622,8 @@ input[type="checkbox"]:checked+label {
|
|||||||
#files td.min a {
|
#files td.min a {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
#files tr.play td {
|
#files tr.play td,
|
||||||
|
#files tr.play div a {
|
||||||
background: #fc4;
|
background: #fc4;
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
color: #400;
|
color: #400;
|
||||||
|
|||||||
@@ -500,7 +500,7 @@ function play(tid, call_depth) {
|
|||||||
setclass(oid, 'play act');
|
setclass(oid, 'play act');
|
||||||
var trs = ebi('files').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
|
var trs = ebi('files').getElementsByTagName('tbody')[0].getElementsByTagName('tr');
|
||||||
for (var a = 0, aa = trs.length; a < aa; a++) {
|
for (var a = 0, aa = trs.length; a < aa; a++) {
|
||||||
trs[a].className = trs[a].className.replace(/ *play */, "");
|
clmod(trs[a], 'play');
|
||||||
}
|
}
|
||||||
ebi(oid).parentElement.parentElement.className += ' play';
|
ebi(oid).parentElement.parentElement.className += ' play';
|
||||||
|
|
||||||
@@ -649,10 +649,10 @@ function tree_up() {
|
|||||||
|
|
||||||
|
|
||||||
document.onkeydown = function (e) {
|
document.onkeydown = function (e) {
|
||||||
if (document.activeElement != document.body && document.activeElement.nodeName.toLowerCase() != 'a')
|
if (!document.activeElement || document.activeElement != document.body && document.activeElement.nodeName.toLowerCase() != 'a')
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var k = e.code, pos = -1;
|
var k = (e.code + ''), pos = -1;
|
||||||
if (k.indexOf('Digit') === 0)
|
if (k.indexOf('Digit') === 0)
|
||||||
pos = parseInt(k.slice(-1)) * 0.1;
|
pos = parseInt(k.slice(-1)) * 0.1;
|
||||||
|
|
||||||
@@ -753,7 +753,7 @@ document.onkeydown = function (e) {
|
|||||||
clearTimeout(search_timeout);
|
clearTimeout(search_timeout);
|
||||||
var now = new Date().getTime();
|
var now = new Date().getTime();
|
||||||
if (now - search_in_progress > 30 * 1000)
|
if (now - search_in_progress > 30 * 1000)
|
||||||
search_timeout = setTimeout(do_search, 100);
|
search_timeout = setTimeout(do_search, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
function do_search() {
|
function do_search() {
|
||||||
@@ -772,6 +772,7 @@ document.onkeydown = function (e) {
|
|||||||
// ebi('srch_q').textContent = JSON.stringify(params, null, 4);
|
// ebi('srch_q').textContent = JSON.stringify(params, null, 4);
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
xhr.open('POST', '/?srch', true);
|
xhr.open('POST', '/?srch', true);
|
||||||
|
xhr.setRequestHeader('Content-Type', 'text/plain');
|
||||||
xhr.onreadystatechange = xhr_search_results;
|
xhr.onreadystatechange = xhr_search_results;
|
||||||
xhr.ts = new Date().getTime();
|
xhr.ts = new Date().getTime();
|
||||||
xhr.send(JSON.stringify(params));
|
xhr.send(JSON.stringify(params));
|
||||||
@@ -796,6 +797,8 @@ document.onkeydown = function (e) {
|
|||||||
var res = JSON.parse(this.responseText),
|
var res = JSON.parse(this.responseText),
|
||||||
tagord = res.tag_order;
|
tagord = res.tag_order;
|
||||||
|
|
||||||
|
sortfiles(res.hits);
|
||||||
|
|
||||||
var ofiles = ebi('files');
|
var ofiles = ebi('files');
|
||||||
if (ofiles.getAttribute('ts') > this.ts)
|
if (ofiles.getAttribute('ts') > this.ts)
|
||||||
return;
|
return;
|
||||||
@@ -814,7 +817,7 @@ document.onkeydown = function (e) {
|
|||||||
|
|
||||||
var html = mk_files_header(tagord);
|
var html = mk_files_header(tagord);
|
||||||
html.push('<tbody>');
|
html.push('<tbody>');
|
||||||
html.push('<tr><td>-</td><td colspan="42"><a href="#" id="unsearch">close search results</a></td></tr>');
|
html.push('<tr><td>-</td><td colspan="42"><a href="#" id="unsearch">! close search results</a></td></tr>');
|
||||||
for (var a = 0; a < res.hits.length; a++) {
|
for (var a = 0; a < res.hits.length; a++) {
|
||||||
var r = res.hits[a],
|
var r = res.hits[a],
|
||||||
ts = parseInt(r.ts),
|
ts = parseInt(r.ts),
|
||||||
@@ -867,6 +870,7 @@ document.onkeydown = function (e) {
|
|||||||
oldcfg = [];
|
oldcfg = [];
|
||||||
ebi('files').innerHTML = orig_html;
|
ebi('files').innerHTML = orig_html;
|
||||||
orig_html = null;
|
orig_html = null;
|
||||||
|
msel.render();
|
||||||
reload_browser();
|
reload_browser();
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
@@ -995,8 +999,6 @@ var treectl = (function () {
|
|||||||
var o = links[a].parentNode;
|
var o = links[a].parentNode;
|
||||||
if (!o.getElementsByTagName('li').length)
|
if (!o.getElementsByTagName('li').length)
|
||||||
o.innerHTML = html;
|
o.innerHTML = html;
|
||||||
//else
|
|
||||||
// links[a].previousSibling.textContent = '-';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1085,35 +1087,8 @@ var treectl = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ebi('srv_info').innerHTML = '<span>' + res.srvinf + '</span>';
|
ebi('srv_info').innerHTML = '<span>' + res.srvinf + '</span>';
|
||||||
var nodes = res.dirs.concat(res.files),
|
var nodes = res.dirs.concat(res.files);
|
||||||
sopts = jread('fsort', []);
|
nodes = sortfiles(nodes);
|
||||||
|
|
||||||
try {
|
|
||||||
for (var a = sopts.length - 1; a >= 0; a--) {
|
|
||||||
var name = sopts[a][0], rev = sopts[a][1], typ = sopts[a][2];
|
|
||||||
if (!name)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (name.indexOf('tags/') == -1) {
|
|
||||||
nodes.sort(function (v1, v2) {
|
|
||||||
if (!v1[name]) return -1 * rev;
|
|
||||||
if (!v2[name]) return 1 * rev;
|
|
||||||
return rev * (typ == 'int' ? (v1[name] - v2[name]) : (v1[name].localeCompare(v2[name])));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
name = name.slice(5);
|
|
||||||
nodes.sort(function (v1, v2) {
|
|
||||||
if (!v1.tags[name]) return -1 * rev;
|
|
||||||
if (!v2.tags[name]) return 1 * rev;
|
|
||||||
return rev * (typ == 'int' ? (v1.tags[name] - v2.tags[name]) : (v1.tags[name].localeCompare(v2.tags[name])));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (ex) {
|
|
||||||
console.log("failed to apply sort config: " + ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
var top = this.top;
|
var top = this.top;
|
||||||
var html = mk_files_header(res.taglist);
|
var html = mk_files_header(res.taglist);
|
||||||
@@ -1307,7 +1282,7 @@ function find_file_col(txt) {
|
|||||||
|
|
||||||
function mk_files_header(taglist) {
|
function mk_files_header(taglist) {
|
||||||
var html = [
|
var html = [
|
||||||
'<thead>',
|
'<thead><tr>',
|
||||||
'<th name="lead"><span>c</span></th>',
|
'<th name="lead"><span>c</span></th>',
|
||||||
'<th name="href"><span>File Name</span></th>',
|
'<th name="href"><span>File Name</span></th>',
|
||||||
'<th name="sz" sort="int"><span>Size</span></th>'
|
'<th name="sz" sort="int"><span>Size</span></th>'
|
||||||
@@ -1326,7 +1301,7 @@ function mk_files_header(taglist) {
|
|||||||
html = html.concat([
|
html = html.concat([
|
||||||
'<th name="ext"><span>T</span></th>',
|
'<th name="ext"><span>T</span></th>',
|
||||||
'<th name="ts"><span>Date</span></th>',
|
'<th name="ts"><span>Date</span></th>',
|
||||||
'</thead>',
|
'</tr></thead>',
|
||||||
]);
|
]);
|
||||||
return html;
|
return html;
|
||||||
}
|
}
|
||||||
@@ -1360,13 +1335,13 @@ var filecols = (function () {
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
var name = span[0].textContent,
|
var name = span[0].textContent,
|
||||||
cls = '';
|
cls = false;
|
||||||
|
|
||||||
if (has(hidden, name)) {
|
if (has(hidden, name)) {
|
||||||
ohidden.push(a);
|
ohidden.push(a);
|
||||||
cls = ' min';
|
cls = true;
|
||||||
}
|
}
|
||||||
ths[a].className = ths[a].className.replace(/ *min */, " ") + cls;
|
clmod(ths[a], 'min', cls)
|
||||||
}
|
}
|
||||||
for (var a = 0; a < ncols; a++) {
|
for (var a = 0; a < ncols; a++) {
|
||||||
var cls = has(ohidden, a) ? 'min' : '';
|
var cls = has(ohidden, a) ? 'min' : '';
|
||||||
@@ -1483,8 +1458,11 @@ var mukey = (function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function render() {
|
function render() {
|
||||||
var ci = find_file_col('Key'),
|
var ci = find_file_col('Key');
|
||||||
i = ci[0],
|
if (!ci)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var i = ci[0],
|
||||||
min = ci[1],
|
min = ci[1],
|
||||||
rows = ebi('files').tBodies[0].rows;
|
rows = ebi('files').tBodies[0].rows;
|
||||||
|
|
||||||
@@ -1533,10 +1511,13 @@ var mukey = (function () {
|
|||||||
|
|
||||||
|
|
||||||
function addcrc() {
|
function addcrc() {
|
||||||
var links = document.querySelectorAll('#files>tbody>tr>td:nth-child(2)>a');
|
var links = document.querySelectorAll(
|
||||||
|
'#files>tbody>tr>td:first-child+td>' + (
|
||||||
|
ebi('unsearch') ? 'div>a:last-child' : 'a'));
|
||||||
|
|
||||||
for (var a = 0, aa = links.length; a < aa; a++)
|
for (var a = 0, aa = links.length; a < aa; a++)
|
||||||
if (!links[a].getAttribute('id'))
|
if (!links[a].getAttribute('id'))
|
||||||
links[a].setAttribute('id', 'f-' + crc32(links[a].textContent));
|
links[a].setAttribute('id', 'f-' + crc32(links[a].textContent || links[a].innerText));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1639,27 +1620,26 @@ var msel = (function () {
|
|||||||
return names;
|
return names;
|
||||||
}
|
}
|
||||||
function selui() {
|
function selui() {
|
||||||
var fun = getsel().length ? "add" : "remove";
|
clmod(ebi('wtoggle'), 'sel', getsel().length);
|
||||||
ebi('wtoggle').classList[fun]('sel');
|
|
||||||
}
|
}
|
||||||
function seltgl(e) {
|
function seltgl(e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
var tr = this.parentNode;
|
var tr = this.parentNode;
|
||||||
tr.classList.toggle('sel');
|
clmod(tr, 'sel', 't');
|
||||||
selui();
|
selui();
|
||||||
}
|
}
|
||||||
function evsel(e, fun) {
|
function evsel(e, fun) {
|
||||||
ev(e);
|
ev(e);
|
||||||
var trs = document.querySelectorAll('#files tbody tr');
|
var trs = document.querySelectorAll('#files tbody tr');
|
||||||
for (var a = 0, aa = trs.length; a < aa; a++)
|
for (var a = 0, aa = trs.length; a < aa; a++)
|
||||||
trs[a].classList[fun]('sel');
|
clmod(trs[a], 'sel', fun);
|
||||||
selui();
|
selui();
|
||||||
}
|
}
|
||||||
ebi('selall').onclick = function (e) {
|
ebi('selall').onclick = function (e) {
|
||||||
evsel(e, "add");
|
evsel(e, "add");
|
||||||
};
|
};
|
||||||
ebi('selinv').onclick = function (e) {
|
ebi('selinv').onclick = function (e) {
|
||||||
evsel(e, "toggle");
|
evsel(e, "t");
|
||||||
};
|
};
|
||||||
ebi('selzip').onclick = function (e) {
|
ebi('selzip').onclick = function (e) {
|
||||||
ev(e);
|
ev(e);
|
||||||
|
|||||||
@@ -524,7 +524,7 @@ function up2k_init(have_crypto) {
|
|||||||
|
|
||||||
if (st.todo.handshake.length > 0 &&
|
if (st.todo.handshake.length > 0 &&
|
||||||
st.busy.handshake.length == 0 && (
|
st.busy.handshake.length == 0 && (
|
||||||
st.todo.handshake[0].t3 || (
|
st.todo.handshake[0].t4 || (
|
||||||
handshakes_permitted() &&
|
handshakes_permitted() &&
|
||||||
st.busy.upload.length < parallel_uploads
|
st.busy.upload.length < parallel_uploads
|
||||||
)
|
)
|
||||||
@@ -868,27 +868,32 @@ function up2k_init(have_crypto) {
|
|||||||
t.done = true;
|
t.done = true;
|
||||||
st.bytes.uploaded += t.size - t.bytes_uploaded;
|
st.bytes.uploaded += t.size - t.bytes_uploaded;
|
||||||
var spd1 = (t.size / ((t.t2 - t.t1) / 1000.)) / (1024 * 1024.);
|
var spd1 = (t.size / ((t.t2 - t.t1) / 1000.)) / (1024 * 1024.);
|
||||||
var spd2 = (t.size / ((t.t3 - t.t2) / 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(
|
ebi('f{0}p'.format(t.n)).innerHTML = 'hash {0}, up {1} MB/s'.format(
|
||||||
spd1.toFixed(2), spd2.toFixed(2));
|
spd1.toFixed(2), spd2.toFixed(2));
|
||||||
}
|
}
|
||||||
else t.t3 = undefined;
|
else t.t4 = undefined;
|
||||||
|
|
||||||
tasker();
|
tasker();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
var err = "";
|
var err = "",
|
||||||
var rsp = (xhr.responseText + '');
|
rsp = (xhr.responseText + ''),
|
||||||
|
ofs = rsp.lastIndexOf('\nURL: ');
|
||||||
|
|
||||||
|
if (ofs !== -1)
|
||||||
|
rsp = rsp.slice(0, ofs);
|
||||||
|
|
||||||
|
if (rsp.indexOf('<pre>') === 0)
|
||||||
|
rsp = rsp.slice(5);
|
||||||
|
|
||||||
|
st.bytes.uploaded += t.size;
|
||||||
if (rsp.indexOf('partial upload exists') !== -1 ||
|
if (rsp.indexOf('partial upload exists') !== -1 ||
|
||||||
rsp.indexOf('file already exists') !== -1) {
|
rsp.indexOf('file already exists') !== -1) {
|
||||||
err = rsp;
|
err = rsp;
|
||||||
var ofs = err.lastIndexOf(' : ');
|
|
||||||
if (ofs > 0)
|
|
||||||
err = err.slice(0, ofs);
|
|
||||||
|
|
||||||
ofs = err.indexOf('\n/');
|
ofs = err.indexOf('\n/');
|
||||||
if (ofs !== -1) {
|
if (ofs !== -1) {
|
||||||
err = err.slice(0, ofs + 1) + linksplit(err.slice(ofs + 2, -1)).join(' ');
|
err = err.slice(0, ofs + 1) + linksplit(err.slice(ofs + 2)).join(' ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err != "") {
|
if (err != "") {
|
||||||
@@ -961,7 +966,7 @@ function up2k_init(have_crypto) {
|
|||||||
st.busy.upload.splice(st.busy.upload.indexOf(upt), 1);
|
st.busy.upload.splice(st.busy.upload.indexOf(upt), 1);
|
||||||
t.postlist.splice(t.postlist.indexOf(npart), 1);
|
t.postlist.splice(t.postlist.indexOf(npart), 1);
|
||||||
if (t.postlist.length == 0) {
|
if (t.postlist.length == 0) {
|
||||||
t.t3 = new Date().getTime();
|
t.t4 = new Date().getTime();
|
||||||
ebi('f{0}t'.format(t.n)).innerHTML = 'verifying';
|
ebi('f{0}t'.format(t.n)).innerHTML = 'verifying';
|
||||||
st.todo.handshake.unshift(t);
|
st.todo.handshake.unshift(t);
|
||||||
}
|
}
|
||||||
@@ -979,9 +984,14 @@ function up2k_init(have_crypto) {
|
|||||||
xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart]);
|
xhr.setRequestHeader("X-Up2k-Hash", t.hash[npart]);
|
||||||
xhr.setRequestHeader("X-Up2k-Wark", t.wark);
|
xhr.setRequestHeader("X-Up2k-Wark", t.wark);
|
||||||
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
|
xhr.setRequestHeader('Content-Type', 'application/octet-stream');
|
||||||
|
if (xhr.overrideMimeType)
|
||||||
xhr.overrideMimeType('Content-Type', 'application/octet-stream');
|
xhr.overrideMimeType('Content-Type', 'application/octet-stream');
|
||||||
|
|
||||||
xhr.responseType = 'text';
|
xhr.responseType = 'text';
|
||||||
xhr.send(e.target.result);
|
xhr.send(e.target.result);
|
||||||
|
|
||||||
|
if (!t.t3)
|
||||||
|
t.t3 = new Date().getTime();
|
||||||
};
|
};
|
||||||
|
|
||||||
reader.readAsArrayBuffer(bobslice.call(t.fobj, car, cdr));
|
reader.readAsArrayBuffer(bobslice.call(t.fobj, car, cdr));
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="op_msg" class="opview opbox">
|
<div id="op_msg" class="opview opbox act">
|
||||||
<form method="post" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
|
<form method="post" enctype="application/x-www-form-urlencoded" accept-charset="utf-8">
|
||||||
<input type="text" name="msg" size="30">
|
<input type="text" name="msg" size="30">
|
||||||
<input type="submit" value="send msg">
|
<input type="submit" value="send msg">
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
|
if (!window['console'])
|
||||||
|
window['console'] = {
|
||||||
|
"log": function (msg) { }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
// error handler for mobile devices
|
// error handler for mobile devices
|
||||||
function hcroak(msg) {
|
function hcroak(msg) {
|
||||||
document.body.innerHTML = msg;
|
document.body.innerHTML = msg;
|
||||||
@@ -113,6 +119,84 @@ function crc32(str) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function clmod(obj, cls, add) {
|
||||||
|
var re = new RegExp('\\s*\\b' + cls + '\\s*\\b', 'g');
|
||||||
|
if (add == 't')
|
||||||
|
add = !re.test(obj.className);
|
||||||
|
|
||||||
|
obj.className = obj.className.replace(re, ' ') + (add ? ' ' + cls : '');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function sortfiles(nodes) {
|
||||||
|
var sopts = jread('fsort', [["lead", -1, ""], ["href", 1, ""]]);
|
||||||
|
|
||||||
|
try {
|
||||||
|
var is_srch = false;
|
||||||
|
if (nodes[0]['rp']) {
|
||||||
|
is_srch = true;
|
||||||
|
for (var b = 0, bb = nodes.length; b < bb; b++)
|
||||||
|
nodes[b].ext = nodes[b].rp.split('.').pop();
|
||||||
|
for (var b = 0; b < sopts.length; b++)
|
||||||
|
if (sopts[b][0] == 'href')
|
||||||
|
sopts[b][0] = 'rp';
|
||||||
|
}
|
||||||
|
for (var a = sopts.length - 1; a >= 0; a--) {
|
||||||
|
var name = sopts[a][0], rev = sopts[a][1], typ = sopts[a][2];
|
||||||
|
if (!name)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (name.indexOf('tags/') === 0) {
|
||||||
|
name = name.slice(5);
|
||||||
|
for (var b = 0, bb = nodes.length; b < bb; b++)
|
||||||
|
nodes[b]._sv = nodes[b].tags[name];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (var b = 0, bb = nodes.length; b < bb; b++) {
|
||||||
|
var v = nodes[b][name];
|
||||||
|
|
||||||
|
if ((v + '').indexOf('<a ') === 0)
|
||||||
|
v = v.split('>')[1];
|
||||||
|
else if (name == "href" && v)
|
||||||
|
v = uricom_dec(v)[0]
|
||||||
|
|
||||||
|
nodes[b]._sv = v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var onodes = nodes.map(function (x) { return x; });
|
||||||
|
nodes.sort(function (n1, n2) {
|
||||||
|
var v1 = n1._sv,
|
||||||
|
v2 = n2._sv;
|
||||||
|
|
||||||
|
if (v1 === undefined) {
|
||||||
|
if (v2 === undefined) {
|
||||||
|
return onodes.indexOf(n1) - onodes.indexOf(n2);
|
||||||
|
}
|
||||||
|
return -1 * rev;
|
||||||
|
}
|
||||||
|
if (v2 === undefined) return 1 * rev;
|
||||||
|
|
||||||
|
var ret = rev * (typ == 'int' ? (v1 - v2) : (v1.localeCompare(v2)));
|
||||||
|
if (ret === 0)
|
||||||
|
ret = onodes.indexOf(n1) - onodes.indexOf(n2);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
for (var b = 0, bb = nodes.length; b < bb; b++) {
|
||||||
|
delete nodes[b]._sv;
|
||||||
|
if (is_srch)
|
||||||
|
delete nodes[b].ext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (ex) {
|
||||||
|
console.log("failed to apply sort config: " + ex);
|
||||||
|
}
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function sortTable(table, col, cb) {
|
function sortTable(table, col, cb) {
|
||||||
var tb = table.tBodies[0],
|
var tb = table.tBodies[0],
|
||||||
th = table.tHead.rows[0].cells,
|
th = table.tHead.rows[0].cells,
|
||||||
@@ -186,7 +270,6 @@ function makeSortable(table, cb) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
(function () {
|
(function () {
|
||||||
var ops = document.querySelectorAll('#ops>a');
|
var ops = document.querySelectorAll('#ops>a');
|
||||||
for (var a = 0; a < ops.length; a++) {
|
for (var a = 0; a < ops.length; a++) {
|
||||||
@@ -212,16 +295,16 @@ function opclick(e) {
|
|||||||
function goto(dest) {
|
function goto(dest) {
|
||||||
var obj = document.querySelectorAll('.opview.act');
|
var obj = document.querySelectorAll('.opview.act');
|
||||||
for (var a = obj.length - 1; a >= 0; a--)
|
for (var a = obj.length - 1; a >= 0; a--)
|
||||||
obj[a].classList.remove('act');
|
clmod(obj[a], 'act');
|
||||||
|
|
||||||
obj = document.querySelectorAll('#ops>a');
|
obj = document.querySelectorAll('#ops>a');
|
||||||
for (var a = obj.length - 1; a >= 0; a--)
|
for (var a = obj.length - 1; a >= 0; a--)
|
||||||
obj[a].classList.remove('act');
|
clmod(obj[a], 'act');
|
||||||
|
|
||||||
if (dest) {
|
if (dest) {
|
||||||
var ui = ebi('op_' + dest);
|
var ui = ebi('op_' + dest);
|
||||||
ui.classList.add('act');
|
clmod(ui, 'act', true);
|
||||||
document.querySelector('#ops>a[data-dest=' + dest + ']').classList.add('act');
|
document.querySelector('#ops>a[data-dest=' + dest + ']').className += " act";
|
||||||
|
|
||||||
var fn = window['goto_' + dest];
|
var fn = window['goto_' + dest];
|
||||||
if (fn)
|
if (fn)
|
||||||
@@ -408,8 +491,7 @@ function bcfg_upd_ui(name, val) {
|
|||||||
if (o.getAttribute('type') == 'checkbox')
|
if (o.getAttribute('type') == 'checkbox')
|
||||||
o.checked = val;
|
o.checked = val;
|
||||||
else if (o) {
|
else if (o) {
|
||||||
var fun = val ? 'add' : 'remove';
|
clmod(o, 'on', val);
|
||||||
o.classList[fun]('on');
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,13 @@ shab64() { sp=$1; f="$2"; v=0; sz=$(stat -c%s "$f"); while true; do w=$((v+sp*10
|
|||||||
command -v gdate && date() { gdate "$@"; }; while true; do t=$(date +%s.%N); (time wget http://127.0.0.1:3923/?ls -qO- | jq -C '.files[]|{sz:.sz,ta:.tags.artist,tb:.tags.".bpm"}|del(.[]|select(.==null))' | awk -F\" '/"/{t[$2]++} END {for (k in t){v=t[k];p=sprintf("%" (v+1) "s",v);gsub(/ /,"#",p);printf "\033[36m%s\033[33m%s ",k,p}}') 2>&1 | awk -v ts=$t 'NR==1{t1=$0} NR==2{sub(/.*0m/,"");sub(/s$/,"");t2=$0;c=2; if(t2>0.3){c=3} if(t2>0.8){c=1} } END{sub(/[0-9]{6}$/,"",ts);printf "%s \033[3%dm%s %s\033[0m\n",ts,c,t2,t1}'; sleep 0.1 || break; done
|
command -v gdate && date() { gdate "$@"; }; while true; do t=$(date +%s.%N); (time wget http://127.0.0.1:3923/?ls -qO- | jq -C '.files[]|{sz:.sz,ta:.tags.artist,tb:.tags.".bpm"}|del(.[]|select(.==null))' | awk -F\" '/"/{t[$2]++} END {for (k in t){v=t[k];p=sprintf("%" (v+1) "s",v);gsub(/ /,"#",p);printf "\033[36m%s\033[33m%s ",k,p}}') 2>&1 | awk -v ts=$t 'NR==1{t1=$0} NR==2{sub(/.*0m/,"");sub(/s$/,"");t2=$0;c=2; if(t2>0.3){c=3} if(t2>0.8){c=1} } END{sub(/[0-9]{6}$/,"",ts);printf "%s \033[3%dm%s %s\033[0m\n",ts,c,t2,t1}'; sleep 0.1 || break; done
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## js oneliners
|
||||||
|
|
||||||
|
# get all up2k search result URLs
|
||||||
|
var t=[]; var b=document.location.href.split('#')[0].slice(0, -1); document.querySelectorAll('#u2tab .prog a').forEach((x) => {t.push(b+encodeURI(x.getAttribute("href")))}); console.log(t.join("\n"));
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## sqlite3 stuff
|
## sqlite3 stuff
|
||||||
|
|
||||||
@@ -129,6 +136,16 @@ pip install virtualenv
|
|||||||
# readme toc
|
# readme toc
|
||||||
cat README.md | awk '!/^#/{next} {lv=length($1);sub(/[^ ]+ /,"");bab=$0;gsub(/ /,"-",bab)} {printf "%" ((lv-1)*4+1) "s [%s](#%s)\n", "*",$0,bab}'
|
cat README.md | awk '!/^#/{next} {lv=length($1);sub(/[^ ]+ /,"");bab=$0;gsub(/ /,"-",bab)} {printf "%" ((lv-1)*4+1) "s [%s](#%s)\n", "*",$0,bab}'
|
||||||
|
|
||||||
|
# fix firefox phantom breakpoints,
|
||||||
|
# suggestions from bugtracker, doesnt work (debugger is not attachable)
|
||||||
|
devtools settings >> advanced >> enable browser chrome debugging + enable remote debugging
|
||||||
|
burger > developer >> browser toolbox (ctrl-alt-shift-i)
|
||||||
|
iframe btn topright >> chrome://devtools/content/debugger/index.html
|
||||||
|
dbg.asyncStore.pendingBreakpoints = {}
|
||||||
|
|
||||||
|
# fix firefox phantom breakpoints
|
||||||
|
about:config >> devtools.debugger.prefs-schema-version = -1
|
||||||
|
|
||||||
|
|
||||||
##
|
##
|
||||||
## http 206
|
## http 206
|
||||||
|
|||||||
@@ -161,7 +161,7 @@ find .. -type f \( -name .DS_Store -or -name ._.DS_Store \) -delete
|
|||||||
find .. -type f -name ._\* | while IFS= read -r f; do cmp <(printf '\x00\x05\x16') <(head -c 3 -- "$f") && rm -f -- "$f"; done
|
find .. -type f -name ._\* | while IFS= read -r f; do cmp <(printf '\x00\x05\x16') <(head -c 3 -- "$f") && rm -f -- "$f"; done
|
||||||
|
|
||||||
echo use smol web deps
|
echo use smol web deps
|
||||||
rm -f copyparty/web/deps/*.full.*
|
rm -f copyparty/web/deps/*.full.* copyparty/web/{Makefile,splash.js}
|
||||||
|
|
||||||
# it's fine dw
|
# it's fine dw
|
||||||
grep -lE '\.full\.(js|css)' copyparty/web/* |
|
grep -lE '\.full\.(js|css)' copyparty/web/* |
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ from copyparty import util
|
|||||||
|
|
||||||
class Cfg(Namespace):
|
class Cfg(Namespace):
|
||||||
def __init__(self, a=[], v=[], c=None):
|
def __init__(self, a=[], v=[], c=None):
|
||||||
ex = {k: False for k in "e2d e2ds e2dsa e2t e2ts e2tsr mte".split()}
|
ex = {k: False for k in "e2d e2ds e2dsa e2t e2ts e2tsr".split()}
|
||||||
|
ex["mtp"] = []
|
||||||
|
ex["mte"] = "a"
|
||||||
super(Cfg, self).__init__(a=a, v=v, c=c, **ex)
|
super(Cfg, self).__init__(a=a, v=v, c=c, **ex)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user