mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
meadup changes
This commit is contained in:
parent
9e6d5dd2b9
commit
fc9dd5d743
|
@ -5,6 +5,11 @@
|
||||||
* if something breaks just restart it
|
* if something breaks just restart it
|
||||||
|
|
||||||
|
|
||||||
|
# [`partyjournal.py`](partyjournal.py)
|
||||||
|
produces a chronological list of all uploads by collecting info from up2k databases and the filesystem
|
||||||
|
* outputs a standalone html file
|
||||||
|
* optional mapping from IP-addresses to nicknames
|
||||||
|
|
||||||
|
|
||||||
# [`copyparty-fuse.py`](copyparty-fuse.py)
|
# [`copyparty-fuse.py`](copyparty-fuse.py)
|
||||||
* mount a copyparty server as a local filesystem (read-only)
|
* mount a copyparty server as a local filesystem (read-only)
|
||||||
|
|
|
@ -1,10 +1,18 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
use copyparty to xdg-open anything that is posted to it,
|
use copyparty as a chromecast replacement:
|
||||||
and also xdg-open file uploads
|
* post a URL and it will open in the default browser
|
||||||
|
* upload a file and it will open in the default application
|
||||||
|
* the `key` command simulates keyboard input
|
||||||
|
* the `x` command executes other xdotool commands
|
||||||
|
* the `c` command executes arbitrary unix commands
|
||||||
|
|
||||||
HELLA DANGEROUS,
|
the android app makes it a breeze to post pics and links:
|
||||||
|
https://github.com/9001/party-up/releases
|
||||||
|
(iOS devices have to rely on the web-UI)
|
||||||
|
|
||||||
|
goes without saying, but this is HELLA DANGEROUS,
|
||||||
GIVES RCE TO ANYONE WHO HAVE UPLOAD PERMISSIONS
|
GIVES RCE TO ANYONE WHO HAVE UPLOAD PERMISSIONS
|
||||||
|
|
||||||
example copyparty config to use this:
|
example copyparty config to use this:
|
||||||
|
@ -12,6 +20,7 @@ example copyparty config to use this:
|
||||||
|
|
||||||
recommended deps:
|
recommended deps:
|
||||||
apt install xdotool libnotify-bin
|
apt install xdotool libnotify-bin
|
||||||
|
https://github.com/9001/copyparty/blob/hovudstraum/contrib/plugins/meadup.js
|
||||||
|
|
||||||
and you probably want `twitter-unmute.user.js` from the res folder
|
and you probably want `twitter-unmute.user.js` from the res folder
|
||||||
|
|
||||||
|
@ -62,6 +71,7 @@ cd ~/Downloads; python3 copyparty-sfx.py --urlform save,get -v.::rw:c,e2d,e2t,mt
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
import subprocess as sp
|
import subprocess as sp
|
||||||
from urllib.parse import unquote_to_bytes as unquote
|
from urllib.parse import unquote_to_bytes as unquote
|
||||||
|
|
||||||
|
@ -79,16 +89,48 @@ def main():
|
||||||
|
|
||||||
def open_post(txt):
|
def open_post(txt):
|
||||||
txt = unquote(txt.replace(b"+", b" ")).decode("utf-8")[4:]
|
txt = unquote(txt.replace(b"+", b" ")).decode("utf-8")[4:]
|
||||||
open_url(txt)
|
try:
|
||||||
|
k, v = txt.split(" ", 1)
|
||||||
|
except:
|
||||||
|
open_url(txt)
|
||||||
|
|
||||||
|
if k == "key":
|
||||||
|
sp.call(["xdotool", "key"] + v.split(" "))
|
||||||
|
elif k == "x":
|
||||||
|
sp.call(["xdotool"] + v.split(" "))
|
||||||
|
elif k == "c":
|
||||||
|
env = os.environ.copy()
|
||||||
|
while " " in v:
|
||||||
|
v1, v2 = v.split(" ", 1)
|
||||||
|
if "=" not in v1:
|
||||||
|
break
|
||||||
|
|
||||||
|
ek, ev = v1.split("=", 1)
|
||||||
|
env[ek] = ev
|
||||||
|
v = v2
|
||||||
|
|
||||||
|
sp.call(v.split(" "), env=env)
|
||||||
|
else:
|
||||||
|
open_url(txt)
|
||||||
|
|
||||||
|
|
||||||
def open_url(txt):
|
def open_url(txt):
|
||||||
sp.call(["notify-send", "", txt])
|
ext = txt.rsplit(".")[-1].lower()
|
||||||
# sp.call(["wmctrl", "-c", ":ACTIVE:"]) # closes the active window correctly
|
sp.call(["notify-send", "--", txt])
|
||||||
sp.call(["xdotool", "key", "ctrl+w"]) # closes the open tab correctly
|
if ext not in ["jpg", "jpeg", "png", "gif", "webp"]:
|
||||||
sp.call(["xdotool", "getactivewindow", "windowminimize"])
|
# sp.call(["wmctrl", "-c", ":ACTIVE:"]) # closes the active window correctly
|
||||||
|
sp.call(["killall", "vlc"])
|
||||||
|
sp.call(["killall", "mpv"])
|
||||||
|
sp.call(["killall", "feh"])
|
||||||
|
time.sleep(0.5)
|
||||||
|
for _ in range(20):
|
||||||
|
sp.call(["xdotool", "key", "ctrl+w"]) # closes the open tab correctly
|
||||||
|
# else:
|
||||||
|
# sp.call(["xdotool", "getactivewindow", "windowminimize"]) # minimizes the focused windo
|
||||||
|
|
||||||
|
# close any error messages:
|
||||||
|
sp.call(["xdotool", "search", "--name", "Error", "windowclose"])
|
||||||
# sp.call(["xdotool", "key", "ctrl+alt+d"]) # doesnt work at all
|
# sp.call(["xdotool", "key", "ctrl+alt+d"]) # doesnt work at all
|
||||||
sp.call(["killall", "vlc"])
|
|
||||||
# sp.call(["xdotool", "keydown", "--delay", "100", "ctrl+alt+d"])
|
# sp.call(["xdotool", "keydown", "--delay", "100", "ctrl+alt+d"])
|
||||||
# sp.call(["xdotool", "keyup", "ctrl+alt+d"])
|
# sp.call(["xdotool", "keyup", "ctrl+alt+d"])
|
||||||
sp.call(["xdg-open", txt])
|
sp.call(["xdg-open", txt])
|
||||||
|
|
177
bin/partyjournal.py
Executable file
177
bin/partyjournal.py
Executable file
|
@ -0,0 +1,177 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
"""
|
||||||
|
partyjournal.py: chronological history of uploads
|
||||||
|
2021-12-31, v0.1, ed <irc.rizon.net>, MIT-Licensed
|
||||||
|
https://github.com/9001/copyparty/blob/hovudstraum/bin/partyjournal.py
|
||||||
|
|
||||||
|
produces a chronological list of all uploads,
|
||||||
|
by collecting info from up2k databases and the filesystem
|
||||||
|
|
||||||
|
specify subnet `192.168.1.*` with argument `.=192.168.1.`,
|
||||||
|
affecting all successive mappings
|
||||||
|
|
||||||
|
usage:
|
||||||
|
./partyjournal.py > partyjournal.html .=192.168.1. cart=125 steen=114 steen=131 sleepy=121 fscarlet=144 ed=101 ed=123
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import base64
|
||||||
|
import sqlite3
|
||||||
|
import argparse
|
||||||
|
from datetime import datetime
|
||||||
|
from urllib.parse import quote_from_bytes as quote
|
||||||
|
from urllib.parse import unquote_to_bytes as unquote
|
||||||
|
|
||||||
|
|
||||||
|
FS_ENCODING = sys.getfilesystemencoding()
|
||||||
|
|
||||||
|
|
||||||
|
class APF(argparse.ArgumentDefaultsHelpFormatter, argparse.RawDescriptionHelpFormatter):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## snibbed from copyparty
|
||||||
|
|
||||||
|
|
||||||
|
def s3dec(v):
|
||||||
|
if not v.startswith("//"):
|
||||||
|
return v
|
||||||
|
|
||||||
|
v = base64.urlsafe_b64decode(v.encode("ascii")[2:])
|
||||||
|
return v.decode(FS_ENCODING, "replace")
|
||||||
|
|
||||||
|
|
||||||
|
def quotep(txt):
|
||||||
|
btxt = txt.encode("utf-8", "replace")
|
||||||
|
quot1 = quote(btxt, safe=b"/")
|
||||||
|
quot1 = quot1.encode("ascii")
|
||||||
|
quot2 = quot1.replace(b" ", b"+")
|
||||||
|
return quot2.decode("utf-8", "replace")
|
||||||
|
|
||||||
|
|
||||||
|
def html_escape(s, quote=False, crlf=False):
|
||||||
|
"""html.escape but also newlines"""
|
||||||
|
s = s.replace("&", "&").replace("<", "<").replace(">", ">")
|
||||||
|
if quote:
|
||||||
|
s = s.replace('"', """).replace("'", "'")
|
||||||
|
if crlf:
|
||||||
|
s = s.replace("\r", " ").replace("\n", " ")
|
||||||
|
|
||||||
|
return s
|
||||||
|
|
||||||
|
|
||||||
|
## end snibs
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
ap = argparse.ArgumentParser(formatter_class=APF)
|
||||||
|
ap.add_argument("who", nargs="*")
|
||||||
|
ar = ap.parse_args()
|
||||||
|
|
||||||
|
imap = {}
|
||||||
|
subnet = ""
|
||||||
|
for v in ar.who:
|
||||||
|
if "=" not in v:
|
||||||
|
raise Exception("bad who: " + v)
|
||||||
|
|
||||||
|
k, v = v.split("=")
|
||||||
|
if k == ".":
|
||||||
|
subnet = v
|
||||||
|
continue
|
||||||
|
|
||||||
|
imap["{}{}".format(subnet, v)] = k
|
||||||
|
|
||||||
|
print(repr(imap), file=sys.stderr)
|
||||||
|
|
||||||
|
print(
|
||||||
|
"""\
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head><meta charset="utf-8"><style>
|
||||||
|
|
||||||
|
html, body {
|
||||||
|
color: #ccc;
|
||||||
|
background: #222;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
color: #fc5;
|
||||||
|
}
|
||||||
|
td, th {
|
||||||
|
padding: .2em .5em;
|
||||||
|
border: 1px solid #999;
|
||||||
|
border-width: 0 1px 1px 0;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
td:nth-child(1),
|
||||||
|
td:nth-child(2),
|
||||||
|
td:nth-child(3) {
|
||||||
|
font-family: monospace, monospace;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
tr:first-child {
|
||||||
|
position: sticky;
|
||||||
|
top: -1px;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background: #222;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style></head><body><table><tr>
|
||||||
|
<th>wark</th>
|
||||||
|
<th>time</th>
|
||||||
|
<th>size</th>
|
||||||
|
<th>who</th>
|
||||||
|
<th>link</th>
|
||||||
|
</tr>"""
|
||||||
|
)
|
||||||
|
|
||||||
|
db_path = ".hist/up2k.db"
|
||||||
|
conn = sqlite3.connect(db_path)
|
||||||
|
q = r"pragma table_info(up)"
|
||||||
|
inf = conn.execute(q).fetchall()
|
||||||
|
cols = [x[1] for x in inf]
|
||||||
|
print("<!-- " + str(cols) + " -->")
|
||||||
|
# ['w', 'mt', 'sz', 'rd', 'fn', 'ip', 'at']
|
||||||
|
|
||||||
|
q = r"select * from up order by case when at > 0 then at else mt end"
|
||||||
|
for w, mt, sz, rd, fn, ip, at in conn.execute(q):
|
||||||
|
link = "/".join([s3dec(x) for x in [rd, fn] if x])
|
||||||
|
if fn.startswith("put-") and sz < 4096:
|
||||||
|
try:
|
||||||
|
with open(link, "rb") as f:
|
||||||
|
txt = f.read().decode("utf-8", "replace")
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if txt.startswith("msg="):
|
||||||
|
txt = txt.encode("utf-8", "replace")
|
||||||
|
txt = unquote(txt.replace(b"+", b" "))
|
||||||
|
link = txt.decode("utf-8")[4:]
|
||||||
|
|
||||||
|
sz = "{:,}".format(sz)
|
||||||
|
v = [
|
||||||
|
w[:16],
|
||||||
|
datetime.utcfromtimestamp(at if at > 0 else mt).strftime(
|
||||||
|
"%Y-%m-%d %H:%M:%S"
|
||||||
|
),
|
||||||
|
sz,
|
||||||
|
imap.get(ip, ip),
|
||||||
|
]
|
||||||
|
|
||||||
|
row = "<tr>\n "
|
||||||
|
row += "\n ".join(["<td>{}</th>".format(x) for x in v])
|
||||||
|
row += '\n <td><a href="{}">{}</a></td>'.format(link, html_escape(link))
|
||||||
|
row += "\n</tr>"
|
||||||
|
print(row)
|
||||||
|
|
||||||
|
print("</table></body></html>")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
|
@ -1,3 +1,6 @@
|
||||||
|
### [`plugins/`](plugins/)
|
||||||
|
* example extensions
|
||||||
|
|
||||||
### [`copyparty.bat`](copyparty.bat)
|
### [`copyparty.bat`](copyparty.bat)
|
||||||
* launches copyparty with no arguments (anon read+write within same folder)
|
* launches copyparty with no arguments (anon read+write within same folder)
|
||||||
* intended for windows machines with no python.exe in PATH
|
* intended for windows machines with no python.exe in PATH
|
||||||
|
|
25
contrib/plugins/README.md
Normal file
25
contrib/plugins/README.md
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# example resource files
|
||||||
|
|
||||||
|
can be provided to copyparty to tweak things
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## example `.epilogue.html`
|
||||||
|
save one of these as `.epilogue.html` inside a folder to customize it:
|
||||||
|
|
||||||
|
* [`minimal-up2k.html`](minimal-up2k.html) will [simplify the upload ui](https://user-images.githubusercontent.com/241032/118311195-dd6ca380-b4ef-11eb-86f3-75a3ff2e1332.png)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## example browser-css
|
||||||
|
point `--css-browser` to one of these by URL:
|
||||||
|
|
||||||
|
* [`browser.css`](browser.css) changes the background
|
||||||
|
* [`browser-icons.css`](browser-icons.css) adds filetype icons
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## meadup.js
|
||||||
|
|
||||||
|
* turns copyparty into chromecast just more flexible (and probably way more buggy)
|
||||||
|
* usage: put the js somewhere in the webroot and `--js-browser /memes/meadup.js`
|
506
contrib/plugins/meadup.js
Normal file
506
contrib/plugins/meadup.js
Normal file
|
@ -0,0 +1,506 @@
|
||||||
|
// USAGE:
|
||||||
|
// place this file somewhere in the webroot and then
|
||||||
|
// python3 -m copyparty --js-browser /memes/meadup.js
|
||||||
|
//
|
||||||
|
// FEATURES:
|
||||||
|
// * adds an onscreen keyboard for operating a media center remotely,
|
||||||
|
// relies on https://github.com/9001/copyparty/blob/hovudstraum/contrib/plugins/meadup.js
|
||||||
|
// * adds an interactive anime girl (if you can find the dependencies)
|
||||||
|
|
||||||
|
var hambagas = [
|
||||||
|
"https://www.youtube.com/watch?v=pFA3KGp4GuU"
|
||||||
|
];
|
||||||
|
|
||||||
|
// keybaord,
|
||||||
|
// onscreen keyboard by @steinuil
|
||||||
|
function initKeybaord(BASE_URL, HAMBAGA, consoleLog, consoleError) {
|
||||||
|
document.querySelector('.keybaord-container').innerHTML = `
|
||||||
|
<div class="keybaord-body">
|
||||||
|
<div class="keybaord-row keybaord-row-1">
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Escape">
|
||||||
|
esc
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F1">
|
||||||
|
F1
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F2">
|
||||||
|
F2
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F3">
|
||||||
|
F3
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F4">
|
||||||
|
F4
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F5">
|
||||||
|
F5
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F6">
|
||||||
|
F6
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F7">
|
||||||
|
F7
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F8">
|
||||||
|
F8
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F9">
|
||||||
|
F9
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F10">
|
||||||
|
F10
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F11">
|
||||||
|
F11
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="F12">
|
||||||
|
F12
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Insert">
|
||||||
|
ins
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Delete">
|
||||||
|
del
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-row keybaord-row-2">
|
||||||
|
<div class="keybaord-key" data-keybaord-key="\`">
|
||||||
|
\`
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="1">
|
||||||
|
1
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="2">
|
||||||
|
2
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="3">
|
||||||
|
3
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="4">
|
||||||
|
4
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="5">
|
||||||
|
5
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="6">
|
||||||
|
6
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="7">
|
||||||
|
7
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="8">
|
||||||
|
8
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="9">
|
||||||
|
9
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="0">
|
||||||
|
0
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="-">
|
||||||
|
-
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="=">
|
||||||
|
=
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-backspace" data-keybaord-key="BackSpace">
|
||||||
|
backspace
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-row keybaord-row-3">
|
||||||
|
<div class="keybaord-key keybaord-tab" data-keybaord-key="Tab">
|
||||||
|
tab
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="q">
|
||||||
|
q
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="w">
|
||||||
|
w
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="e">
|
||||||
|
e
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="r">
|
||||||
|
r
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="t">
|
||||||
|
t
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="y">
|
||||||
|
y
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="u">
|
||||||
|
u
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="i">
|
||||||
|
i
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="o">
|
||||||
|
o
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="p">
|
||||||
|
p
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="[">
|
||||||
|
[
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="]">
|
||||||
|
]
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-enter" data-keybaord-key="Return">
|
||||||
|
enter
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-row keybaord-row-4">
|
||||||
|
<div class="keybaord-key keybaord-capslock" data-keybaord-key="HAMBAGA">
|
||||||
|
🍔
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="a">
|
||||||
|
a
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="s">
|
||||||
|
s
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="d">
|
||||||
|
d
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="f">
|
||||||
|
f
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="g">
|
||||||
|
g
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="h">
|
||||||
|
h
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="j">
|
||||||
|
j
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="k">
|
||||||
|
k
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="l">
|
||||||
|
l
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key=";">
|
||||||
|
;
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="'">
|
||||||
|
'
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-backslash" data-keybaord-key="\\">
|
||||||
|
\\
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-row keybaord-row-5">
|
||||||
|
<div class="keybaord-key keybaord-lshift" data-keybaord-key="Shift_L">
|
||||||
|
shift
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="\\">
|
||||||
|
\\
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="z">
|
||||||
|
z
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="x">
|
||||||
|
x
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="c">
|
||||||
|
c
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="v">
|
||||||
|
v
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="b">
|
||||||
|
b
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="n">
|
||||||
|
n
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="m">
|
||||||
|
m
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key=",">
|
||||||
|
,
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key=".">
|
||||||
|
.
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="/">
|
||||||
|
/
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-rshift" data-keybaord-key="Shift_R">
|
||||||
|
shift
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-row keybaord-row-6">
|
||||||
|
<div class="keybaord-key keybaord-lctrl" data-keybaord-key="Control_L">
|
||||||
|
ctrl
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-super" data-keybaord-key="Meta_L">
|
||||||
|
win
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-alt" data-keybaord-key="Alt_L">
|
||||||
|
alt
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-spacebar" data-keybaord-key="space">
|
||||||
|
space
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-altgr" data-keybaord-key="Alt_R">
|
||||||
|
altgr
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-what" data-keybaord-key="Menu">
|
||||||
|
menu
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key keybaord-rctrl" data-keybaord-key="Control_R">
|
||||||
|
ctrl
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-row">
|
||||||
|
<div class="keybaord-key" data-keybaord-key="XF86AudioLowerVolume">
|
||||||
|
🔉
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="XF86AudioRaiseVolume">
|
||||||
|
🔊
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Left">
|
||||||
|
⬅️
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Down">
|
||||||
|
⬇️
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Up">
|
||||||
|
⬆️
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Right">
|
||||||
|
➡️
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Page_Up">
|
||||||
|
PgUp
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Page_Down">
|
||||||
|
PgDn
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="Home">
|
||||||
|
🏠
|
||||||
|
</div>
|
||||||
|
<div class="keybaord-key" data-keybaord-key="End">
|
||||||
|
End
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
`;
|
||||||
|
|
||||||
|
function arraySample(array) {
|
||||||
|
return array[Math.floor(Math.random() * array.length)];
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMessage(msg) {
|
||||||
|
return fetch(BASE_URL, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded;charset=UTF-8",
|
||||||
|
},
|
||||||
|
body: "msg=" + encodeURIComponent(msg),
|
||||||
|
}).then(
|
||||||
|
(r) => r.text(), // so the response body shows up in network tab
|
||||||
|
(err) => consoleError(err)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
const MODIFIER_ON_CLASS = "keybaord-modifier-on";
|
||||||
|
const KEY_DATASET = "data-keybaord-key";
|
||||||
|
const KEY_CLASS = "keybaord-key";
|
||||||
|
|
||||||
|
const modifiers = new Set()
|
||||||
|
|
||||||
|
function toggleModifier(button, key) {
|
||||||
|
button.classList.toggle(MODIFIER_ON_CLASS);
|
||||||
|
if (modifiers.has(key)) {
|
||||||
|
modifiers.delete(key);
|
||||||
|
} else {
|
||||||
|
modifiers.add(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function popModifiers() {
|
||||||
|
let modifierString = "";
|
||||||
|
|
||||||
|
modifiers.forEach((mod) => {
|
||||||
|
document.querySelector("[" + KEY_DATASET + "='" + mod + "']")
|
||||||
|
.classList.remove(MODIFIER_ON_CLASS);
|
||||||
|
|
||||||
|
modifierString += mod + "+";
|
||||||
|
});
|
||||||
|
|
||||||
|
modifiers.clear();
|
||||||
|
|
||||||
|
return modifierString;
|
||||||
|
}
|
||||||
|
|
||||||
|
Array.from(document.querySelectorAll("." + KEY_CLASS)).forEach((button) => {
|
||||||
|
const key = button.dataset.keybaordKey;
|
||||||
|
|
||||||
|
button.addEventListener("click", (ev) => {
|
||||||
|
switch (key) {
|
||||||
|
case "HAMBAGA":
|
||||||
|
sendMessage(arraySample(HAMBAGA));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "Shift_L":
|
||||||
|
case "Shift_R":
|
||||||
|
|
||||||
|
case "Control_L":
|
||||||
|
case "Control_R":
|
||||||
|
|
||||||
|
case "Meta_L":
|
||||||
|
|
||||||
|
case "Alt_L":
|
||||||
|
case "Alt_R":
|
||||||
|
toggleModifier(button, key);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: {
|
||||||
|
const keyWithModifiers = popModifiers() + key;
|
||||||
|
|
||||||
|
consoleLog(keyWithModifiers);
|
||||||
|
|
||||||
|
sendMessage("key " + keyWithModifiers)
|
||||||
|
.then(() => consoleLog(keyWithModifiers + " OK"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// keybaord integration
|
||||||
|
(function () {
|
||||||
|
var o = mknod('div');
|
||||||
|
clmod(o, 'keybaord-container', 1);
|
||||||
|
ebi('op_msg').appendChild(o);
|
||||||
|
|
||||||
|
o = mknod('style');
|
||||||
|
o.innerHTML = `
|
||||||
|
.keybaord-body {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column nowrap;
|
||||||
|
margin: .6em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-row {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key {
|
||||||
|
border: 1px solid rgba(128,128,128,0.2);
|
||||||
|
width: 41px;
|
||||||
|
height: 40px;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key:active {
|
||||||
|
background-color: lightgrey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-modifier-on {
|
||||||
|
background-color: lightblue;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-backspace {
|
||||||
|
width: 82px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-tab {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-enter {
|
||||||
|
width: 69px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-capslock {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-backslash {
|
||||||
|
width: 88px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-lshift {
|
||||||
|
width: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-rshift {
|
||||||
|
width: 103px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-lctrl {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-super {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-alt {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-altgr {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-what {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-rctrl {
|
||||||
|
width: 55px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keybaord-key.keybaord-spacebar {
|
||||||
|
width: 302px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
document.head.appendChild(o);
|
||||||
|
|
||||||
|
initKeybaord('/', hambagas,
|
||||||
|
(msg) => { toast.inf(2, msg.toString()) },
|
||||||
|
(msg) => { toast.err(30, msg.toString()) });
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
// live2d (dumb pointless meme)
|
||||||
|
// dependencies for this part are not tracked in git
|
||||||
|
// so delete this section if you wanna use this file
|
||||||
|
// (or supply your own l2d model and js)
|
||||||
|
(function () {
|
||||||
|
var o = mknod('link');
|
||||||
|
o.setAttribute('rel', 'stylesheet');
|
||||||
|
o.setAttribute('href', "/bad-memes/pio.css");
|
||||||
|
document.head.appendChild(o);
|
||||||
|
|
||||||
|
o = mknod('style');
|
||||||
|
o.innerHTML = '.pio-container{text-shadow:none;z-index:1}';
|
||||||
|
document.head.appendChild(o);
|
||||||
|
|
||||||
|
o = mknod('div');
|
||||||
|
clmod(o, 'pio-container', 1);
|
||||||
|
o.innerHTML = '<div class="pio-action"></div><canvas id="pio" width="280" height="500"></canvas>';
|
||||||
|
document.body.appendChild(o);
|
||||||
|
|
||||||
|
var remaining = 3;
|
||||||
|
for (var a of ['pio', 'l2d', 'fireworks']) {
|
||||||
|
import_js(`/bad-memes/${a}.js`, function () {
|
||||||
|
if (remaining-- > 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
o = mknod('script');
|
||||||
|
o.innerHTML = 'var pio = new Paul_Pio({"selector":[],"mode":"fixed","hidden":false,"content":{"close":"ok bye"},"model":["/bad-memes/sagiri/model.json"]});';
|
||||||
|
document.body.appendChild(o);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
|
@ -1097,7 +1097,8 @@ def read_socket(sr, total_size):
|
||||||
|
|
||||||
buf = sr.recv(bufsz)
|
buf = sr.recv(bufsz)
|
||||||
if not buf:
|
if not buf:
|
||||||
raise Pebkac(400, "client d/c during binary post")
|
m = "client d/c during binary post after {} bytes, {} bytes remaining"
|
||||||
|
raise Pebkac(400, m.format(total_size - remains, remains))
|
||||||
|
|
||||||
remains -= len(buf)
|
remains -= len(buf)
|
||||||
yield buf
|
yield buf
|
||||||
|
|
|
@ -86,6 +86,9 @@ function vis_exh(msg, url, lineNo, columnNo, error) {
|
||||||
if ((msg + '').indexOf('ResizeObserver') !== -1)
|
if ((msg + '').indexOf('ResizeObserver') !== -1)
|
||||||
return; // chrome issue 809574 (benign, from <video>)
|
return; // chrome issue 809574 (benign, from <video>)
|
||||||
|
|
||||||
|
if ((msg + '').indexOf('l2d.js') !== -1)
|
||||||
|
return; // `t` undefined in tapEvent -> hitTestSimpleCustom
|
||||||
|
|
||||||
var ekey = url + '\n' + lineNo + '\n' + msg;
|
var ekey = url + '\n' + lineNo + '\n' + msg;
|
||||||
if (ignexd[ekey] || crashed)
|
if (ignexd[ekey] || crashed)
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -2,27 +2,6 @@
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# example resource files
|
|
||||||
|
|
||||||
can be provided to copyparty to tweak things
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## example `.epilogue.html`
|
|
||||||
save one of these as `.epilogue.html` inside a folder to customize it:
|
|
||||||
|
|
||||||
* [`minimal-up2k.html`](minimal-up2k.html) will [simplify the upload ui](https://user-images.githubusercontent.com/241032/118311195-dd6ca380-b4ef-11eb-86f3-75a3ff2e1332.png)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## example browser-css
|
|
||||||
point `--css-browser` to one of these by URL:
|
|
||||||
|
|
||||||
* [`browser.css`](browser.css) changes the background
|
|
||||||
* [`browser-icons.css`](browser-icons.css) adds filetype icons
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# utilities
|
# utilities
|
||||||
|
|
||||||
## [`multisearch.html`](multisearch.html)
|
## [`multisearch.html`](multisearch.html)
|
||||||
|
|
Loading…
Reference in a new issue