mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
add hook: usb-eject
This commit is contained in:
parent
fff38f484d
commit
f38c754301
|
@ -30,4 +30,5 @@ these are `--xiu` hooks; unlike `xbu` and `xau` (which get executed on every sin
|
||||||
# on message
|
# on message
|
||||||
* [wget.py](wget.py) lets you download files by POSTing URLs to copyparty
|
* [wget.py](wget.py) lets you download files by POSTing URLs to copyparty
|
||||||
* [qbittorrent-magnet.py](qbittorrent-magnet.py) starts downloading a torrent if you post a magnet url
|
* [qbittorrent-magnet.py](qbittorrent-magnet.py) starts downloading a torrent if you post a magnet url
|
||||||
|
* [usb-eject.py](usb-eject.py) adds web-UI buttons to safe-remove usb flashdrives shared through copyparty
|
||||||
* [msg-log.py](msg-log.py) is a guestbook; logs messages to a doc in the same folder
|
* [msg-log.py](msg-log.py) is a guestbook; logs messages to a doc in the same folder
|
||||||
|
|
54
bin/hooks/usb-eject.js
Normal file
54
bin/hooks/usb-eject.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
// see usb-eject.py for usage
|
||||||
|
|
||||||
|
function usbclick() {
|
||||||
|
QS('#treeul a[href="/usb/"]').click();
|
||||||
|
}
|
||||||
|
|
||||||
|
function eject_cb() {
|
||||||
|
var t = this.responseText;
|
||||||
|
if (t.indexOf('can be safely unplugged') < 0 && t.indexOf('Device can be removed') < 0)
|
||||||
|
return toast.err(30, 'usb eject failed:\n\n' + t);
|
||||||
|
|
||||||
|
toast.ok(5, esc(t.replace(/ - /g, '\n\n')));
|
||||||
|
usbclick(); setTimeout(usbclick, 10);
|
||||||
|
};
|
||||||
|
|
||||||
|
function add_eject_2(a) {
|
||||||
|
var aw = a.getAttribute('href').split(/\//g);
|
||||||
|
if (aw.length != 4 || aw[3])
|
||||||
|
return;
|
||||||
|
|
||||||
|
var v = aw[2],
|
||||||
|
k = 'umount_' + v;
|
||||||
|
|
||||||
|
qsr('#' + k);
|
||||||
|
a.appendChild(mknod('span', k, '⏏'), a);
|
||||||
|
|
||||||
|
var o = ebi(k);
|
||||||
|
o.style.cssText = 'position:absolute; right:1em; margin-top:-.2em; font-size:1.3em';
|
||||||
|
o.onclick = function (e) {
|
||||||
|
ev(e);
|
||||||
|
var xhr = new XHR();
|
||||||
|
xhr.open('POST', get_evpath(), true);
|
||||||
|
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8');
|
||||||
|
xhr.send('msg=' + uricom_enc(':usb-eject:' + v + ':'));
|
||||||
|
xhr.onload = xhr.onerror = eject_cb;
|
||||||
|
toast.inf(10, "ejecting " + v + "...");
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
function add_eject() {
|
||||||
|
for (var a of QSA('#treeul a[href^="/usb/"]'))
|
||||||
|
add_eject_2(a);
|
||||||
|
};
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
var f0 = treectl.rendertree;
|
||||||
|
treectl.rendertree = function (res, ts, top0, dst, rst) {
|
||||||
|
var ret = f0(res, ts, top0, dst, rst);
|
||||||
|
add_eject();
|
||||||
|
return ret;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
setTimeout(add_eject, 50);
|
49
bin/hooks/usb-eject.py
Normal file
49
bin/hooks/usb-eject.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
import stat
|
||||||
|
import subprocess as sp
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
if you've found yourself using copyparty to serve flashdrives on a LAN
|
||||||
|
and your only wish is that the web-UI had a button to unmount / safely
|
||||||
|
remove those flashdrives, then boy howdy are you in the right place :D
|
||||||
|
|
||||||
|
put usb-eject.js in the webroot (or somewhere else http-accessible)
|
||||||
|
then run copyparty with these args:
|
||||||
|
|
||||||
|
-v /run/media/ed:/usb:A:c,hist=/tmp/junk
|
||||||
|
--xm=c1,bin/hooks/usb-eject.py
|
||||||
|
--js-browser=/usb-eject.js
|
||||||
|
|
||||||
|
which does the following respectively,
|
||||||
|
|
||||||
|
* share all of /run/media/ed as /usb with admin for everyone
|
||||||
|
and put the histpath somewhere it won't cause trouble
|
||||||
|
* run the usb-eject hook with stdout redirect to the web-ui
|
||||||
|
* add the complementary usb-eject.js to the browser
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
label = sys.argv[1].split(":usb-eject:")[1].split(":")[0]
|
||||||
|
mp = "/run/media/ed/" + label
|
||||||
|
# print("ejecting [%s]... " % (mp,), end="")
|
||||||
|
mp = os.path.abspath(os.path.realpath(mp.encode("utf-8")))
|
||||||
|
st = os.lstat(mp)
|
||||||
|
if not stat.S_ISDIR(st.st_mode):
|
||||||
|
raise Exception("not a regular directory")
|
||||||
|
|
||||||
|
cmd = [b"gio", b"mount", b"-e", mp]
|
||||||
|
print(sp.check_output(cmd).decode("utf-8", "replace").strip())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
print("unmount failed: %r" % (ex,))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -7460,12 +7460,12 @@ var treectl = (function () {
|
||||||
xhr.rst = rst;
|
xhr.rst = rst;
|
||||||
xhr.ts = Date.now();
|
xhr.ts = Date.now();
|
||||||
xhr.open('GET', addq(dst, 'tree=' + top + (r.dots ? '&dots' : '') + k), true);
|
xhr.open('GET', addq(dst, 'tree=' + top + (r.dots ? '&dots' : '') + k), true);
|
||||||
xhr.onload = xhr.onerror = recvtree;
|
xhr.onload = xhr.onerror = r.recvtree;
|
||||||
xhr.send();
|
xhr.send();
|
||||||
enspin('#tree');
|
enspin('#tree');
|
||||||
}
|
}
|
||||||
|
|
||||||
function recvtree() {
|
r.recvtree = function () {
|
||||||
if (!xhrchk(this, L.tl_xe1, L.tl_xe2))
|
if (!xhrchk(this, L.tl_xe1, L.tl_xe2))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -7475,10 +7475,10 @@ var treectl = (function () {
|
||||||
catch (ex) {
|
catch (ex) {
|
||||||
return toast.err(30, "bad <code>?tree</code> reply;\nexpected json, got this:\n\n" + esc(this.responseText + ''));
|
return toast.err(30, "bad <code>?tree</code> reply;\nexpected json, got this:\n\n" + esc(this.responseText + ''));
|
||||||
}
|
}
|
||||||
rendertree(res, this.ts, this.top, this.dst, this.rst);
|
r.rendertree(res, this.ts, this.top, this.dst, this.rst);
|
||||||
}
|
};
|
||||||
|
|
||||||
function rendertree(res, ts, top0, dst, rst) {
|
r.rendertree = function (res, ts, top0, dst, rst) {
|
||||||
var cur = ebi('treeul').getAttribute('ts');
|
var cur = ebi('treeul').getAttribute('ts');
|
||||||
if (cur && parseInt(cur) > ts + 20 && QS('#treeul>li>a+a')) {
|
if (cur && parseInt(cur) > ts + 20 && QS('#treeul>li>a+a')) {
|
||||||
console.log("reject tree; " + cur + " / " + (ts - cur));
|
console.log("reject tree; " + cur + " / " + (ts - cur));
|
||||||
|
@ -7532,7 +7532,7 @@ var treectl = (function () {
|
||||||
console.log("dir_cb failed", ex);
|
console.log("dir_cb failed", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function reload_tree() {
|
function reload_tree() {
|
||||||
var cdir = r.nextdir || get_vpath(),
|
var cdir = r.nextdir || get_vpath(),
|
||||||
|
@ -7754,7 +7754,7 @@ var treectl = (function () {
|
||||||
dirs.push(dn);
|
dirs.push(dn);
|
||||||
}
|
}
|
||||||
|
|
||||||
rendertree({ "a": dirs }, this.ts, ".", get_evpath() + (dk ? '?k=' + dk : ''));
|
r.rendertree({ "a": dirs }, this.ts, ".", get_evpath() + (dk ? '?k=' + dk : ''));
|
||||||
}
|
}
|
||||||
|
|
||||||
r.gentab(this.top, res);
|
r.gentab(this.top, res);
|
||||||
|
|
Loading…
Reference in a new issue