Merge branch '9001:hovudstraum' into hovudstraum

This commit is contained in:
SelfishPig 2025-11-30 12:58:54 -06:00 committed by GitHub
commit 3d228d9a6e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 164 additions and 32 deletions

1
.gitignore vendored
View file

@ -43,6 +43,7 @@ scripts/docker/*.err
# nix build output link # nix build output link
result result
result-*
# IDEA config # IDEA config
.idea/ .idea/

View file

@ -2924,6 +2924,11 @@ if [cfssl](https://github.com/cloudflare/cfssl/releases/latest) is installed, co
* this will be a self-signed certificate so you must install your `ca.pem` into all your browsers/devices * this will be a self-signed certificate so you must install your `ca.pem` into all your browsers/devices
* if you want to avoid the hassle of distributing certs manually, please consider using a reverse proxy * if you want to avoid the hassle of distributing certs manually, please consider using a reverse proxy
to install cfssl on windows:
* [download](https://github.com/cloudflare/cfssl/releases/latest) `cfssl_windows_amd64.exe`, `cfssljson_windows_amd64.exe`, `cfssl-certinfo_windows_amd64.exe`
* rename them to `cfssl.exe`, `cfssljson.exe`, `cfssl-certinfo.exe`
* put them in PATH, for example inside `c:\windows\system32`
# recovering from crashes # recovering from crashes

View file

@ -34,7 +34,10 @@ MOUNT_BASE = b"/run/media/egon/"
def main(): def main():
try: try:
label = sys.argv[1].split(":usb-eject:")[1].split(":")[0] msg = sys.argv[1]
if msg.startswith("upload-queue-empty;"):
return
label = msg.split(":usb-eject:")[1].split(":")[0]
mp = MOUNT_BASE + unquote(label) mp = MOUNT_BASE + unquote(label)
# print("ejecting [%s]... " % (mp,), end="") # print("ejecting [%s]... " % (mp,), end="")
mp = os.path.abspath(os.path.realpath(mp)) mp = os.path.abspath(os.path.realpath(mp))

View file

@ -62,6 +62,9 @@ def do_stuff(inf):
log = inf["log"] log = inf["log"]
url = inf["txt"] url = inf["txt"]
if url.startswith("upload-queue-empty;"):
return
if "://" not in url: if "://" not in url:
url = "https://" + url url = "https://" + url

View file

@ -47,6 +47,9 @@ while you're in the /inc folder (or any folder below there)
def main(): def main():
inf = json.loads(sys.argv[1]) inf = json.loads(sys.argv[1])
url = inf["txt"] url = inf["txt"]
if url.startswith("upload-queue-empty;"):
return
if "://" not in url: if "://" not in url:
url = "https://" + url url = "https://" + url

View file

@ -67,18 +67,64 @@
# additional dependencies # additional dependencies
extraPythonPackages ? (_p: [ ]), extraPythonPackages ? (_p: [ ]),
# to build stable + unstable with the same file
stable ? true,
# for commit date, only used when stable = false
copypartyFlake ? null,
nix-gitignore,
}: }:
let let
pinData = lib.importJSON ./pin.json; pinData = lib.importJSON ./pin.json;
runtimeDeps = ([ util-linux ] ++ extraPackages ++ lib.optional withMediaProcessing ffmpeg); runtimeDeps = ([ util-linux ] ++ extraPackages ++ lib.optional withMediaProcessing ffmpeg);
inherit (copypartyFlake) lastModifiedDate;
# ex: "1970" "01" "01"
dateStringsZeroPrefixed = {
year = builtins.substring 0 4 lastModifiedDate;
month = builtins.substring 4 2 lastModifiedDate;
day = builtins.substring 6 2 lastModifiedDate;
};
# ex: "1970" "1" "1"
dateStringsShort = builtins.mapAttrs (_: val: toString (lib.toIntBase10 val)) dateStringsZeroPrefixed;
unstableVersion =
if copypartyFlake == null then
"${pinData.version}-unstable"
else
with dateStringsZeroPrefixed; "${pinData.version}-unstable-${year}-${month}-${day}"
;
version = if stable then pinData.version else unstableVersion;
stableSrc = fetchurl {
inherit (pinData) url hash;
};
root = ../../../..;
unstableSrc = nix-gitignore.gitignoreSource [] root;
src = if stable then stableSrc else unstableSrc;
rev = copypartyFlake.shortRev or copypartyFlake.dirtyShortRev or "unknown";
unstableCodename = "unstable" + (lib.optionalString (copypartyFlake != null) "-${rev}");
in in
buildPythonApplication { buildPythonApplication {
pname = "copyparty"; pname = "copyparty";
inherit (pinData) version; inherit version src;
src = fetchurl { postPatch = lib.optionalString (!stable) ''
inherit (pinData) url hash; old_src="$(mktemp -d)"
}; tar -C "$old_src" -xf ${stableSrc}
declare -a folders
folders=("$old_src"/*)
count_folders="''${#folders[@]}"
if [[ $count_folders != 1 ]]; then
declare -p folders
echo "Expected 1 folder, found $count_folders" >&2
exit 1
fi
old_src_folder="''${folders[0]}"
cp -r "$old_src_folder"/copyparty/web/deps copyparty/web/deps
sed -i 's/^CODENAME =.*$/CODENAME = "${unstableCodename}"/' copyparty/__version__.py
${lib.optionalString (copypartyFlake != null) (with dateStringsShort; ''
sed -i 's/^BUILD_DT =.*$/BUILD_DT = (${year}, ${month}, ${day})/' copyparty/__version__.py
'')}
'';
dependencies = dependencies =
[ [
jinja2 jinja2

View file

@ -1,8 +1,28 @@
final: prev: { final: prev:
copyparty = final.python3.pkgs.callPackage ./copyparty { let
ffmpeg = final.ffmpeg-full; fullAttrs = {
withHashedPasswords = true;
withCertgen = true;
withThumbnails = true;
withFastThumbnails = true;
withMediaProcessing = true;
withBasicAudioMetadata = true;
withZeroMQ = true;
withFTP = true;
withFTPS = true;
withTFTP = true;
withSMB = true;
withMagic = true;
}; };
call = attrs: final.python3.pkgs.callPackage ./copyparty ({ ffmpeg = final.ffmpeg-full; } // attrs);
in
{
copyparty = call { stable = true; };
copyparty-unstable = call { stable = false; };
copyparty-full = call (fullAttrs // { stable = true; });
copyparty-unstable-full = call (fullAttrs // { stable = false; });
python3 = prev.python3.override { python3 = prev.python3.override {
packageOverrides = pyFinal: pyPrev: { packageOverrides = pyFinal: pyPrev: {
partftpy = pyFinal.callPackage ./partftpy { }; partftpy = pyFinal.callPackage ./partftpy { };

View file

@ -2,6 +2,7 @@ import calendar
import errno import errno
import json import json
import os import os
import shutil
import time import time
from .__init__ import ANYWIN from .__init__ import ANYWIN
@ -19,6 +20,19 @@ else:
VF = {"mv_re_t": 0, "rm_re_t": 0} VF = {"mv_re_t": 0, "rm_re_t": 0}
def _sp_err(exe, what, rc, so, se, sin):
try:
zs = shutil.which(exe)
except:
zs = "<?>"
try:
zi = os.path.getsize(zs)
except:
zi = 0
t = "failed to %s; error %s using %s (%s):\n STDOUT: %s\n STDERR: %s\n STDIN: %s\n"
raise Exception(t % (what, rc, zs, zi, so, se, sin.decode("utf-8")))
def ensure_cert(log: "RootLogger", args) -> None: def ensure_cert(log: "RootLogger", args) -> None:
""" """
the default cert (and the entire TLS support) is only here to enable the the default cert (and the entire TLS support) is only here to enable the
@ -107,13 +121,13 @@ def _gen_ca(log: "RootLogger", args):
cmd = "cfssl gencert -initca -" cmd = "cfssl gencert -initca -"
rc, so, se = runcmd(cmd.split(), 30, sin=sin) rc, so, se = runcmd(cmd.split(), 30, sin=sin)
if rc: if rc:
raise Exception("failed to create ca-cert: {}, {}".format(rc, se), 3) _sp_err("cfssl", "create ca-cert", rc, so, se, sin)
cmd = "cfssljson -bare ca" cmd = "cfssljson -bare ca"
sin = so.encode("utf-8") sin = so.encode("utf-8")
rc, so, se = runcmd(cmd.split(), 10, sin=sin, cwd=args.crt_dir) rc, so, se = runcmd(cmd.split(), 10, sin=sin, cwd=args.crt_dir)
if rc: if rc:
raise Exception("failed to translate ca-cert: {}, {}".format(rc, se), 3) _sp_err("cfssljson", "translate ca-cert", rc, so, se, sin)
bname = os.path.join(args.crt_dir, "ca") bname = os.path.join(args.crt_dir, "ca")
try: try:
@ -201,13 +215,13 @@ def _gen_srv(log: "RootLogger", args, netdevs: dict[str, Netdev]):
acmd = cmd.split() + ["-hostname=" + ",".join(names), "-"] acmd = cmd.split() + ["-hostname=" + ",".join(names), "-"]
rc, so, se = runcmd(acmd, 30, sin=sin, cwd=args.crt_dir) rc, so, se = runcmd(acmd, 30, sin=sin, cwd=args.crt_dir)
if rc: if rc:
raise Exception("failed to create cert: {}, {}".format(rc, se)) _sp_err("cfssl", "create cert", rc, so, se, sin)
cmd = "cfssljson -bare srv" cmd = "cfssljson -bare srv"
sin = so.encode("utf-8") sin = so.encode("utf-8")
rc, so, se = runcmd(cmd.split(), 10, sin=sin, cwd=args.crt_dir) rc, so, se = runcmd(cmd.split(), 10, sin=sin, cwd=args.crt_dir)
if rc: if rc:
raise Exception("failed to translate cert: {}, {}".format(rc, se)) _sp_err("cfssljson", "translate cert", rc, so, se, sin)
bname = os.path.join(args.crt_dir, "srv") bname = os.path.join(args.crt_dir, "srv")
try: try:

View file

@ -2449,7 +2449,7 @@ function mpause(e) {
return true; return true;
dist *= -1; dist *= -1;
mp.setvol(mp.vol + dist / 500); mp.setvol(Math.round((mp.vol + dist / 500) * 100) / 100 );
vbar.draw(); vbar.draw();
ev(e); ev(e);
}; };
@ -3019,9 +3019,6 @@ function play(tid, is_ev, seek) {
} }
if (tn >= mp.order.length) { if (tn >= mp.order.length) {
if (mpl.pb_mode == 'stop')
return;
if (mpl.pb_mode == 'loop' || ebi('unsearch')) { if (mpl.pb_mode == 'loop' || ebi('unsearch')) {
tn = 0; tn = 0;
} }
@ -3029,6 +3026,7 @@ function play(tid, is_ev, seek) {
treectl.ls_cb = next_song; treectl.ls_cb = next_song;
return tree_neigh(1); return tree_neigh(1);
} }
else return;
} }
if (tn < 0) { if (tn < 0) {
@ -3039,6 +3037,7 @@ function play(tid, is_ev, seek) {
treectl.ls_cb = last_song; treectl.ls_cb = last_song;
return tree_neigh(-1); return tree_neigh(-1);
} }
else return;
} }
tid = mp.order[tn]; tid = mp.order[tn];

View file

@ -2271,11 +2271,17 @@ function up2k_init(subtle) {
busy = {}, busy = {},
nbusy = 0, nbusy = 0,
init = 0, init = 0,
ninit = 0,
hashtab = {}, hashtab = {},
mem = (MOBILE ? 128 : 256) * 1024 * 1024; mem = (MOBILE ? 128 : 256) * 1024 * 1024;
if (!hws_ok) if (!hws_ok)
init = setTimeout(function() { init = setInterval(function() {
if (ninit < hws_ok) {
ninit = hws_ok;
return toast.inf(10, 'initializing webworkers ({0}/{1})'.format(hws_ok, hws.length), "iwwt");
}
clearInterval(init);
hws_ng = true; hws_ng = true;
toast.warn(30, 'webworkers failed to start\n\nwill be a bit slower due to\nhashing on main-thread'); toast.warn(30, 'webworkers failed to start\n\nwill be a bit slower due to\nhashing on main-thread');
apop(st.busy.hash, t); apop(st.busy.hash, t);
@ -2325,12 +2331,17 @@ function up2k_init(subtle) {
} }
function onmsg(d) { function onmsg(d) {
if (hws_ng)
return;
d = d.data; d = d.data;
var k = d[0]; var k = d[0];
if (k == "pong") if (k == "pong")
if (++hws_ok == hws.length) { if (++hws_ok == hws.length) {
clearTimeout(init); clearInterval(init);
if (toast.tag == 'iwwt')
toast.hide();
go_next(); go_next();
} }

View file

@ -50,7 +50,7 @@
[/] # create a volume at "/" (the webroot), which will [/] # create a volume at "/" (the webroot), which will
/w # share /w (the docker data volume) /w # share /w (the docker data volume)
accs: accs:
rw: * # everyone gets read-access, but r: * # everyone gets read-access, but
rwmda: @su # the group "su" gets read-write-move-delete-admin rwmda: @su # the group "su" gets read-write-move-delete-admin

View file

@ -12,7 +12,8 @@
}: }:
{ {
nixosModules.default = ./contrib/nixos/modules/copyparty.nix; nixosModules.default = ./contrib/nixos/modules/copyparty.nix;
overlays.default = import ./contrib/package/nix/overlay.nix; overlays.default = final: prev:
(import ./contrib/package/nix/overlay.nix final prev) // { copypartyFlake = self; };
} }
// flake-utils.lib.eachDefaultSystem ( // flake-utils.lib.eachDefaultSystem (
system: system:
@ -22,26 +23,26 @@
config = { config = {
allowAliases = false; allowAliases = false;
}; };
overlays = [ self.overlays.default ]; overlays = [
self.overlays.default
];
}; };
in in
{ {
# check that copyparty builds with all optionals turned on # check that copyparty builds with all optionals turned on
checks.copyparty-full = self.packages.${system}.copyparty.override { checks = {
withHashedPasswords = true; inherit (pkgs)
withCertgen = true; copyparty-full
withThumbnails = true; copyparty-unstable-full
withFastThumbnails = true; ;
withMediaProcessing = true;
withBasicAudioMetadata = true;
withZeroMQ = true;
withFTPS = true;
withSMB = true;
}; };
packages = { packages = {
inherit (pkgs) inherit (pkgs)
copyparty copyparty
copyparty-full
copyparty-unstable
copyparty-unstable-full
; ;
default = self.packages.${system}.copyparty; default = self.packages.${system}.copyparty;
}; };

View file

@ -1,6 +1,12 @@
#!/bin/bash #!/bin/bash
set -e set -e
command -v gfind >/dev/null &&
command -v gsed >/dev/null &&
command -v gsort >/dev/null && {
sed() { gsed "$@"; }
}
[ -e make-sfx.sh ] || cd scripts [ -e make-sfx.sh ] || cd scripts
[ -e make-sfx.sh ] && [ -e deps-docker ] || { [ -e make-sfx.sh ] && [ -e deps-docker ] || {
echo cd into the scripts folder first echo cd into the scripts folder first

View file

@ -37,7 +37,12 @@ def cnv(src):
hostname = str(socket.gethostname()).split(".")[0] hostname = str(socket.gethostname()).split(".")[0]
yield '<!DOCTYPE html>' yield '<!DOCTYPE html>'
yield '<html style="background:#222;color:#fff"><body>' yield '<html><body><style>'
yield 'html{background:#222;color:#fff;line-height:1.25em}'
yield 'h3{margin:0;padding:0}'
yield 'a{color:#fc5;text-decoration:none;scroll-margin-top:3em}'
yield 'a:active,a:target{background:#fc5;color:#000;box-shadow:0 0 0 .12em #fc5}'
yield '</style>'
skip_sfx = False skip_sfx = False
in_sfx = 0 in_sfx = 0
in_salt = 0 in_salt = 0
@ -104,6 +109,15 @@ def cnv(src):
ln = re.sub(r">[0-9]{1,2}\.[0-9]<", ">dynamic<", ln) ln = re.sub(r">[0-9]{1,2}\.[0-9]<", ">dynamic<", ln)
if t != ln: if t != ln:
in_th_ram_max = 0 in_th_ram_max = 0
m = re.search(r"^# (.* help page)(.*)", ln)
if m:
zs1, zs2 = m.groups()
zs3 = zs1.replace(" ", "-")
ln = '<h3># <a id="%s" href="#%s">%s</a>%s</h3></a>' % (zs3, zs3, zs1, zs2)
m = re.search(r"^ (-{1,2})([^ ,]+)(.*)", ln)
if m:
zs1, zs2, zs3 = m.groups()
ln = ' <a href="#g-%s" id="g-%s">%s%s</a>%s' % (zs2, zs2, zs1, zs2, zs3)
ln = ln.replace(">/home/ed/", ">~/") ln = ln.replace(">/home/ed/", ">~/")
if ln.startswith("0" * 20): if ln.startswith("0" * 20):

View file

@ -1,6 +1,12 @@
#!/bin/bash #!/bin/bash
set -e set -e
command -v gfind >/dev/null &&
command -v gsed >/dev/null &&
command -v gsort >/dev/null && {
head() { ghead "$@"; }
}
( ( HLPTXT=CAT && cat || xsel -ob ) | sed -r ' ( ( HLPTXT=CAT && cat || xsel -ob ) | sed -r '
s`/home/ed/`~/`; s`/home/ed/`~/`;
s/uuid:[0-9a-f-]{36}/autogenerated/; s/uuid:[0-9a-f-]{36}/autogenerated/;