Merge branch '9001:hovudstraum' into hovudstraum

This commit is contained in:
ArtemisOne 2026-03-04 22:14:13 +00:00 committed by GitHub
commit 49e75e67db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 751 additions and 140 deletions

4
.gitignore vendored
View file

@ -29,6 +29,10 @@ copyparty.egg-info/
copyparty/res/COPYING.txt
copyparty/web/deps/
srv/
scripts/docker/base/b/
scripts/docker/base/cver*
scripts/docker/base/test-aac/
scripts/docker/base/whl/
scripts/docker/i/
scripts/deps-docker/uncomment.py
contrib/package/arch/pkg/

View file

@ -491,6 +491,9 @@ upgrade notes
* thumbnails are broken (you get a colorful square which says the filetype instead)
* you need to install `FFmpeg` or `Pillow`; see [thumbnails](#thumbnails)
* thumbnails are broken, specifically for photos and videos taken by iphones
* the [docker image](https://github.com/9001/copyparty/blob/hovudstraum/scripts/docker) and [bootable flashdrive](https://a.ocv.me/pub/stuff/edcd001/enterprise-edition/) are not able to read heif/heic images and h265/HEVC video due to [legal reasons](docs/bad-codecs.md)
* thumbnails are broken (some images appear, but other files just get a blank box, and/or the broken-image placeholder)
* probably due to a reverse-proxy messing with the request URLs and stripping the query parameters (`?th=w`), so check your URL rewrite rules
* could also be due to incorrect caching settings in reverse-proxies and/or CDNs, so make sure that nothing is set to ignore the query string
@ -760,8 +763,7 @@ to show `/icons/exe.png` and `/icons/elf.gif` as the thumbnail for all `.exe` an
* be careful with svg; chrome will crash if you have too many unique svg files showing on the same page (the limit is 250 or so) -- showing the same handful of svg files thousands of times is ok however
note:
* heif/heifs/heic/heics images usually require the `libvips` [optional dependency](#optional-dependencies) (available in the `iv` docker image, `withFastThumbnails` in nixos)
* technical trivia: FFmpeg has basic support for tiled heic as of v7.0; need `-show_stream_groups` for correct resolution
* heif/heifs/heic/heics images usually require the `libvips` [optional dependency](#optional-dependencies) but this is not possible with the docker-images due to [legal reasons](docs/bad-codecs.md)
config file example:
@ -1437,7 +1439,7 @@ general usage:
on macos, connect from finder:
* [Go] -> [Connect to Server...] -> http://192.168.123.1:3923/
to upload or edit files with WebDAV clients, enable the `daw` volflag (because most WebDAV clients expect this) and give your account the delete-permission. This avoids getting several copies of the same file on the server. HOWEVER: This will also make all PUT-uploads overwrite existing files if the user has delete-access, so use with caution.
to be able to edit existing files, the client must have the Delete-permission, and some webdav clients will also require the [daw](https://copyparty.eu/cli/#g-daw) volflag or global-option (not necessary if the client sends the `x-oc-mtime` header). Without `daw`, those clients will fail to modify existing files and instead create new copies with names like `notes.txt-1771978661.726032-3i9GPghL.txt`. **NOTE:** Enabling `daw` will also make all PUT-uploads overwrite existing files if the user has delete-access, so use with caution. Another alternative is the [dav-port](https://copyparty.eu/cli/#g-dav-port) option
> note: if you have enabled [IdP authentication](#identity-providers) then that may cause issues for some/most webdav clients; see [the webdav section in the IdP docs](https://github.com/9001/copyparty/blob/hovudstraum/docs/idp.md#connecting-webdav-clients)

View file

@ -3,7 +3,7 @@
# NOTE: You generally shouldn't use this PKGBUILD on Arch, as it is mainly for testing purposes. Install copyparty using pacman instead.
pkgname=copyparty
pkgver="1.20.7"
pkgver="1.20.10"
pkgrel=1
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
arch=("any")
@ -24,7 +24,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag
)
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
backup=("etc/${pkgname}/copyparty.conf" )
sha256sums=("a05ae0226c6171551d0af0e8dbbbbf6d6c32fa19ec06446b5f56726dcce1b8c4")
sha256sums=("a651df2ab768ebdf2f41b7ff1e1fec788ae8a34848ce228c189f2d0f566c9fd9")
build() {
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"

View file

@ -2,7 +2,7 @@
pkgname=copyparty
pkgver=1.20.7
pkgver=1.20.10
pkgrel=1
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, SFTP, FTP, TFTP, zeroconf, media indexer, thumbnails++"
arch=("any")
@ -21,7 +21,7 @@ optdepends=("ffmpeg: thumbnails for videos, images (slower) and audio, music tag
)
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
backup=("/etc/${pkgname}.d/init" )
sha256sums=("a05ae0226c6171551d0af0e8dbbbbf6d6c32fa19ec06446b5f56726dcce1b8c4")
sha256sums=("a651df2ab768ebdf2f41b7ff1e1fec788ae8a34848ce228c189f2d0f566c9fd9")
build() {
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"

View file

@ -1,5 +1,5 @@
{
"url": "https://github.com/9001/copyparty/releases/download/v1.20.7/copyparty-1.20.7.tar.gz",
"version": "1.20.7",
"hash": "sha256-oFrgImxhcVUdCvDo27u/bWwy+hnsBkRrX1ZybczhuMQ="
"url": "https://github.com/9001/copyparty/releases/download/v1.20.10/copyparty-1.20.10.tar.gz",
"version": "1.20.10",
"hash": "sha256-plHfKrdo698vQbf/Hh/seIroo0hIziKMGJ8tD1Zsn9k="
}

View file

@ -1482,7 +1482,7 @@ def add_ftp(ap):
def add_webdav(ap):
ap2 = ap.add_argument_group("WebDAV options")
ap2.add_argument("--daw", action="store_true", help="enable full write support, even if client may not be webdav. \033[1;31mWARNING:\033[0m This has side-effects -- PUT-operations will now \033[1;31mOVERWRITE\033[0m existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client)")
ap2.add_argument("--daw", action="store_true", help="enable full write support, even if client may not be webdav. Some webdav clients need this option for editing existing files; not necessary for clients that send the 'x-oc-mtime' header. Regardless, the delete-permission must always be given. \033[1;31mWARNING:\033[0m This has side-effects -- PUT-operations will now \033[1;31mOVERWRITE\033[0m existing files, rather than inventing new filenames to avoid loss of data. You might want to instead set this as a volflag where needed. By not setting this flag, uploaded files can get written to a filename which the client does not expect (which might be okay, depending on client)")
ap2.add_argument("--dav-inf", action="store_true", help="allow depth:infinite requests (recursive file listing); extremely server-heavy but required for spec compliance -- luckily few clients rely on this")
ap2.add_argument("--dav-mac", action="store_true", help="disable apple-garbage filter -- allow macos to create junk files (._* and .DS_Store, .Spotlight-*, .fseventsd, .Trashes, .AppleDouble, __MACOS)")
ap2.add_argument("--dav-rt", action="store_true", help="show symlink-destination's lastmodified instead of the link itself; always enabled for recursive listings (volflag=davrt)")

View file

@ -1,8 +1,8 @@
# coding: utf-8
VERSION = (1, 20, 7)
VERSION = (1, 20, 10)
CODENAME = "sftp is fine too"
BUILD_DT = (2026, 2, 14)
BUILD_DT = (2026, 2, 25)
S_VERSION = ".".join(map(str, VERSION))
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)

View file

@ -147,8 +147,11 @@ class AXS(object):
class Lim(object):
def __init__(self, log_func: Optional["RootLogger"]) -> None:
def __init__(
self, args: argparse.Namespace, log_func: Optional["RootLogger"]
) -> None:
self.log_func = log_func
self.use_scandir = not args.no_scandir
self.reg: Optional[dict[str, dict[str, Any]]] = None # up2k registry
@ -190,12 +193,12 @@ class Lim(object):
self.log_func("up-lim", msg, c)
def set_rotf(self, fmt: str, tz: str) -> None:
self.rotf = fmt
self.rotf = fmt.rstrip("/\\")
if tz != "UTC":
from zoneinfo import ZoneInfo
self.rotf_tz = ZoneInfo(tz)
r = re.escape(fmt).replace("%Y", "[0-9]{4}").replace("%j", "[0-9]{3}")
r = re.escape(self.rotf).replace("%Y", "[0-9]{4}").replace("%j", "[0-9]{3}")
r = re.sub("%[mdHMSWU]", "[0-9]{2}", r)
self.rot_re = re.compile("(^|/)" + r + "$")
@ -312,12 +315,17 @@ class Lim(object):
return ret, d
def dive(self, path: str, lvs: int) -> Optional[str]:
items = bos.listdir(path)
if not lvs:
# at leaf level
items = statdir(self.log_func, self.use_scandir, False, path, True)
items = [
x
for x in items
if not stat.S_ISDIR(x[1].st_mode) and not x[0].endswith(".PARTIAL")
]
return None if len(items) >= self.rotn else ""
items = bos.listdir(path)
dirs = [int(x) for x in items if x and all(y in "1234567890" for y in x)]
dirs.sort()
@ -2284,7 +2292,7 @@ class AuthSrv(object):
vol.flags["zipmax"] = True
for vol in vfs.all_vols.values():
lim = Lim(self.log_func)
lim = Lim(self.args, self.log_func)
use = False
if vol.flags.get("nosub"):

View file

@ -178,6 +178,7 @@ RE_HTTP1 = re.compile(r"(GET|HEAD|POST|PUT) [^ ]+ HTTP/1.1$")
RE_HR = re.compile(r"[<>\"'&]")
RE_MDV = re.compile(r"(.*)\.([0-9]+\.[0-9]{3})(\.[Mm][Dd])$")
RE_RSS_KW = re.compile(r"(\{[^} ]+\})")
RE_SETCK = re.compile(r"[^0-9a-z=]")
UPARAM_CC_OK = set("doc move tree".split())
@ -649,8 +650,8 @@ class HttpCli(object):
if len(zso) > self.args.cookie_cmax:
self.loud_reply("cookie header too big", status=400)
return False
zsll = [x.split("=", 1) for x in zso.split(";") if "=" in x]
cookies = {k.strip(): unescape_cookie(zs) for k, zs in zsll}
zsll = [x.lstrip().split("=", 1) for x in zso.split(";") if "=" in x]
cookies = {k.rstrip(): unescape_cookie(zs.strip(), k) for k, zs in zsll}
cookie_pw = cookies.get("cppws" if self.is_https else "cppwd") or ""
if "b" in cookies and "b" not in uparam:
uparam["b"] = cookies["b"]
@ -2575,6 +2576,10 @@ class HttpCli(object):
vfs.flags.get("daw")
or "replace" in self.headers
or "x-oc-mtime" in self.headers
or (
self.args.dav_port
and self.args.dav_port == self.s.getsockname()[1]
)
)
) or (
not bos.path.exists(os.path.join(fdir, tnam))
@ -5628,7 +5633,10 @@ class HttpCli(object):
return True
def setck(self) -> bool:
k, v = self.uparam["setck"].split("=", 1)
zs = self.uparam["setck"]
if len(zs) > 9 or RE_SETCK.search(zs):
raise Pebkac(400, "illegal value")
k, v = zs.split("=")
t = 0 if v in ("", "x") else 86400 * 299
ck = gencookie(k, v, self.args.R, True, False, t)
self.out_headerlist.append(("Set-Cookie", ck))

View file

@ -1439,7 +1439,7 @@ class SvcHub(object):
self.log("root", "ssdp startup failed;\n" + min_ex(), 3)
def reload(self, rescan_all_vols: bool, up2k: bool) -> str:
t = "config has been reloaded"
t = "users, volumes, and volflags have been reloaded"
with self.reload_mutex:
self.log("root", "reloading config")
self.asrv.reload(9 if up2k else 4)
@ -1449,6 +1449,7 @@ class SvcHub(object):
t += "; volumes are now reinitializing"
else:
self.log("root", "reload done")
t += "\n\nchanges to global options (if any) require a restart of copyparty to take effect"
self.broker.reload()
return t

View file

@ -6,6 +6,7 @@ import io
import logging
import os
import re
import shlex
import shutil
import subprocess as sp
import tempfile
@ -554,11 +555,12 @@ class ThumbSrv(object):
conv_ok = True
break
except Exception as ex:
r321 = getattr(ex, "returncode", 0) == 321
msg = "%s could not create thumbnail of %r\n%s"
msg = msg % (fun.__name__, abspath, min_ex())
msg = msg % (fun.__name__, abspath, ex if r321 else min_ex())
c: Union[str, int] = 1 if "<Signals.SIG" in msg else "90"
self.log(msg, c)
if getattr(ex, "returncode", 0) != 321:
if not r321:
if fun == funs[-1]:
try:
with open(ttpath, "wb") as _:
@ -826,7 +828,13 @@ class ThumbSrv(object):
c: Union[str, int] = "90"
t = "FFmpeg failed (probably a corrupt file):\n"
if (
if "but no decoder found for: hevc" in serr:
t = "thumbnail cannot be created due to legal reasons; https://github.com/9001/copyparty/blob/hovudstraum/docs/bad-codecs.md \033[0;90m\n"
ret = 321
c = 3
elif (
(not self.args.th_ff_jpg or time.time() - int(self.args.th_ff_jpg) < 60)
and cmd[-1].lower().endswith(b".webp")
and (
@ -841,7 +849,7 @@ class ThumbSrv(object):
ret = 321
c = 1
if (
elif (
not self.args.th_ff_swr or time.time() - int(self.args.th_ff_swr) < 60
) and (
"Requested resampling engine is unavailable" in serr
@ -860,7 +868,12 @@ class ThumbSrv(object):
if len(txt) > 5000:
txt = txt[:2500] + "...\nff: [...]\nff: ..." + txt[-2500:]
self.log(t + txt, c=c)
try:
zs = shlex.join([x.decode("utf-8", "replace") for x in cmd])
except:
zs = "'" + (b"' '".join(cmd2)).decode("utf-8", "replace") + "'"
self.log("%scmd: %s\n%s" % (t, zs, txt), c=c)
raise sp.CalledProcessError(ret, (cmd[0], b"...", cmd[-1]))
def conv_waves(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:

View file

@ -3260,6 +3260,21 @@ class Up2k(object):
dst = djoin(cj["ptop"], cj["prel"], cj["name"])
vsrc = djoin(job["vtop"], job["prel"], job["name"])
vsrc = vsrc.replace("\\", "/") # just for prints anyways
if vfs.lim:
dst, cj["prel"] = vfs.lim.all(
cj["addr"],
cj["prel"],
cj["size"],
cj["ptop"],
djoin(cj["ptop"], cj["prel"]),
self.hub.broker,
reg,
"up2k._get_volsize",
)
bos.makedirs(dst, vf=vfs.flags)
vfs.lim.nup(cj["addr"])
vfs.lim.bup(cj["addr"], cj["size"])
if "done" not in job:
self.log("unfinished:\n %r\n %r" % (src, dst))
err = "partial upload exists at a different location; please resume uploading here instead:\n"

View file

@ -3439,8 +3439,10 @@ def rmdirs_up(top: str, stop: str) -> tuple[list[str], list[str]]:
return [top] + ok, ng
def unescape_cookie(orig: str) -> str:
def unescape_cookie(orig: str, name: str) -> str:
# mw=idk; doot=qwe%2Crty%3Basd+fgh%2Bjkl%25zxc%26vbn # qwe,rty;asd fgh+jkl%zxc&vbn
if not name.startswith("cppw"):
orig = orig[:3]
ret = []
esc = ""
for ch in orig:

View file

@ -332,8 +332,7 @@ if (1)
"mt_ssvt": "volume threshold (0-255)\">vol",
"mt_ssts": "active threshold (% of track, start)\">start",
"mt_sste": "active threshold (% of track, end)\">end",
"mt_ssrt": "volume/speed ramp up/down time\">fade",
"mt_sssm": "playback speed multiplier\">ffwd",
"mt_sssm": "playback speed multiplier (range: 0.15 to 8)\">ffwd",
"mb_play": "play",
"mm_hashplay": "play this audio file?",
@ -2718,8 +2717,8 @@ var afilt = (function () {
"drcv": [-24, 30, 12, 0.01, 0.25],
"drch": ['tresh', 'knee', 'ratio', 'atk', 'rls'],
"drck": ['threshold', 'knee', 'ratio', 'attack', 'release'],
"sscl": [L.mt_ssvt, L.mt_ssts, L.mt_sste, L.mt_ssrt, L.mt_sssm],
"sscv": [1, 5, 5, 5.0, 0.2],
"sscl": [L.mt_ssvt, L.mt_ssts, L.mt_sste, L.mt_sssm],
"sscv": [1, 5, 5, 5.0],
"drcn": null,
"filters": [],
"filterskip": [],
@ -10042,8 +10041,8 @@ var mpss = (function() {
vthresh: afilt.sscv[0],
sthresh: afilt.sscv[1],
etresh: afilt.sscv[2],
sspeed: afilt.sscv[3],
rspeed: afilt.sscv[4],
sspeed: clamp(afilt.sscv[3], 0.15, 8.0),
rspeed: 0.2,
loopInterval: 25,
};
return true;

View file

@ -325,7 +325,6 @@ Ls.chi = {
"mt_ssvt": "音量阈值 (0-255)\">音量", //m
"mt_ssts": "活动阈值 (曲目百分比,开始)\">开始", //m
"mt_sste": "活动阈值 (曲目百分比,结束)\">结束", //m
"mt_ssrt": "音量/速度 渐变时间\">攻", //m
"mt_sssm": "播放速度倍率\">快进", //m
"mb_play": "播放",

View file

@ -329,7 +329,6 @@ Ls.cze = {
"mt_ssvt": "prahová hlasitost (0-255)\">hl", //m
"mt_ssts": "aktivní práh (% stopy, začátek)\">zač", //m
"mt_sste": "aktivní práh (% stopy, konec)\">kon", //m
"mt_ssrt": "doba náběhu/útlumu hlasitosti/rychlosti\">fade", //m
"mt_sssm": "násobič rychlosti přehrávání\">rych", //m
"mb_play": "přehrát",

View file

@ -325,7 +325,6 @@ Ls.deu = {
"mt_ssvt": "Lautstärkeschwelle (0-255)\">laut", //m
"mt_ssts": "Aktiv-Schwelle (% Titel, Anfang)\">anf", //m
"mt_sste": "Aktiv-Schwelle (% Titel, Ende)\">end", //m
"mt_ssrt": "Ein/Ausblendzeit Lautstärke/Geschwindigkeit\">fade", //m
"mt_sssm": "Wiedergabegeschwindigkeits-Multiplikator\">vor", //m
"mb_play": "Abspielen",

View file

@ -325,7 +325,6 @@ Ls.epo = {
"mt_ssvt": "maksimuma laŭtnivelo por silentsaltado (0-255)\">laŭt",
"mt_ssts": "komenca intervalo por silentsaltado (% de trakolongo)\">ek%",
"mt_sste": "fina intervalo por silentsaltado (% de trakolongo)\">fin%",
"mt_ssrt": "tempo por laŭgrada ŝanĝo de laŭteco/rapideco dum silentsaltado\">ŝanĝ⏱",
"mt_sssm": "multiplikado de ludrapideco dum silentsaltado\">×rapid",
"mb_play": "ludi",

View file

@ -84,8 +84,8 @@ Ls.fin = {
["M", "sulje tekstitiedosto"],
["E", "muokkaa tekstitiedostoa"],
["S", "valitse tiedosto (leikkausta/kopiointia/uudelleennimeämistä varten)"],
["Y", "lataa tekstitiedosto"], //m
["⇧ J", "kaunista json"], //m
["Y", "lataa tekstitiedosto"],
["⇧ J", "muotoile/siisti json"],
]
],
@ -111,14 +111,14 @@ Ls.fin = {
"gou": 'ylempi hakemisto">ylös',
"gon": 'seuraava hakemisto">seur',
"logout": "Kirjaudu ulos ",
"login": "Kirjaudu sisään", //m
"login": "Kirjaudu sisään",
"access": " -oikeudet",
"ot_close": "sulje alavalikko",
"ot_search": "`etsi tiedostoja ominaisuuksien, tiedostopolun tai -nimen, musiikkitägien tai näiden yhdistelmän perusteella$N$N`foo bar` = täytyy sisältää sekä «foo» että «bar»,$N`foo -bar` = täytyy sisältää «foo» mutta ei «bar»,$N`^yana .opus$` = alkaa «yana» ja on «opus»-tiedosto$N`&quot;try unite&quot;` = sisältää täsmälleen «try unite»$N$Npäivämäärän muoto on iso-8601, kuten$N`2009-12-31` tai `2020-09-12 23:30:00`",
"ot_unpost": "unpost: poista viimeaikaiset tai keskeytä keskeneräiset lataukset",
"ot_bup": "bup: tiedostojen 'perus'lähetysohjelma, tukee jopa netscape 4.0",
"ot_mkdir": "mkdir: luo uusi hakemisto",
"ot_md": "new-file: luo uusi tekstitiedosto", //m
"ot_md": "new-file: luo uusi tekstitiedosto",
"ot_msg": "msg: lähetä viesti palvelinlokiin",
"ot_mp": "mediasoittimen asetukset",
"ot_cfg": "asetukset",
@ -127,7 +127,7 @@ Ls.fin = {
"ot_noie": 'Suosittelemme käyttämään uudempaa selainta.',
"ab_mkdir": "luo hakemisto",
"ab_mkdoc": "luo tekstitiedosto", //m
"ab_mkdoc": "luo tekstitiedosto",
"ab_msg": "lähetä viesti palvelinlokiin",
"ay_path": "siirry hakemistoihin",
@ -155,7 +155,7 @@ Ls.fin = {
"ul_par": "rinnakkaislatausten lkm:",
"ut_rand": "satunnaisgeneroidut tiedostonimet",
"ut_u2ts": "kopioi viimeksi muokattu aikaleima$Ntiedostojärjestelmästäsi palvelimelle\">📅",
"ut_ow": "korvaa olemassa olevat tiedostot palvelimella?$N🛡: ei koskaan (luo sen sijaan uuden tiedostonimen)$N🕒: korvaa jos palvelintiedosto on vanhempi kuin omasi$N♻: korvaa aina jos tiedostot ovat erilaisia$N⏭: ohita kaikki olemassa olevat tiedostot ehdottomasti", //m
"ut_ow": "korvaa olemassa olevat tiedostot palvelimella?$N🛡: ei koskaan (luo sen sijaan uuden tiedostonimen)$N🕒: korvaa jos palvelintiedosto on vanhempi kuin omasi$N♻: korvaa aina jos tiedostot ovat erilaisia$N⏭: ohita kaikki olemassa olevat tiedostot ehdottomasti",
"ut_mt": "jatka muiden tiedostojen tiivisteiden laskemista latauksen aikana$N$Nkannattanee poistaa käytöstä, mikäli prosessori tai kovalevy on vanhempaa mallia",
"ut_ask": 'kysy vahvistusta ennen latauksen aloittamista">💭',
"ut_pot": "paranna latausnopeutta hitailla laitteilla$Nvähentämällä käyttöliittymän monimutkaisuutta",
@ -206,7 +206,7 @@ Ls.fin = {
"u_nav_b": '<a href="#" id="modal-ok">Tiedostoja</a><a href="#" id="modal-ng">Yksi hakemisto</a>',
"cl_opts": "asetukset",
"cl_hfsz": "tiedostokoko", //m
"cl_hfsz": "tiedostokoko",
"cl_themes": "teema",
"cl_langs": "kieli",
"cl_ziptype": "hakemiston pakkaustyyppi",
@ -220,14 +220,14 @@ Ls.fin = {
"cl_reset": "palauta",
"cl_hpick": "napauta sarakeotsikoita piilottaaksesi alla olevassa taulukossa",
"cl_hcancel": "sarakkeiden piilotus peruttu",
"cl_rcm": "hiiren oikean painikkeen valikko", //m
"cl_rcm": "hiiren pikavalikko",
"ct_grid": '田 kuvanäkymä',
"ct_ttips": '◔ ◡ ◔"> vihjelaatikot',
"ct_thumb": 'valitse kuvakkeiden / pienoiskuvien välillä kuvanäkymässä $NPikanäppäin: T">🖼️ pienoiskuvat',
"ct_csel": 'käytä CTRL ja SHIFT tiedostojen valintaan kuvanäkymässä">valitse',
"ct_dsel": 'käytä aluevalintaa tiedostojen valintaan kuvanäkymässä">aluevalinta',
"ct_dl": 'pakota lataus (älä näytä upotettuna), kun tiedostoa napsautetaan">dl', //m
"ct_dl": 'pakota lataus (älä näytä upotettuna), kun tiedostoa klikataan">dl',
"ct_ihop": 'kun kuvakatselin suljetaan, vieritä alas viimeksi katsottuun tiedostoon">g⮯',
"ct_dots": 'näytä piilotetut tiedostot (jos palvelin sallii)">piilotiedostot',
"ct_qdel": 'kysy vahvistusta vain kerran tiedostoja poistaessa">qdel',
@ -264,8 +264,8 @@ Ls.fin = {
"cdt_lim": "tiedostojen enimmäismäärä näytettäväksi hakemistossa",
"cdt_ask": "sivun lopussa, sen sijaan että lataa $Nautomaattisesti lisää tiedostoja, kysy mitä tehdä",
"cdt_hsort": "`kuinka monta lajittelusääntöä (`,sorthref`) sisällyttää media-URL:eihin. Tämän asettaminen nollaan jättää myös huomioimatta media-linkeissä sisällytetyt lajittelusäännöt kun napsautat niitä",
"cdt_ren": "ota käyttöön mukautettu valikko, tavallinen valikko on käytettävissä painamalla shift ja napsauttamalla oikealla\">aktivoi", //m
"cdt_rdb": "näytä tavallinen oikean painikkeen valikko, kun mukautettu on jo auki ja oikeaa painiketta painetaan uudelleen\">x2", //m
"cdt_ren": "ota käyttöön mukautettu pikavalikko, tavallinen valikko on käytettävissä painamalla shift ja napsauttamalla hiiren oikeanpuoleisella painikkeella\">aktivoi",
"cdt_rdb": "näytä tavallinen pikavalikko, kun mukautettu on jo auki ja oikeanpuoleista painiketta painetaan uudelleen\">x2",
"tt_entree": "näytä navigointipaneeli$NPikanäppäin: B",
"tt_detree": "näytä linkkipolku$NPikanäppäin: B",
@ -283,7 +283,7 @@ Ls.fin = {
"ml_tint": "sävy",
"ml_eq": "taajuuskorjain",
"ml_drc": "dynaaminen alueen kompressori",
"ml_ss": "ohita hiljaisuus", //m
"ml_ss": "ohita hiljaiset kohdat",
"mt_loop": "toista samaa kappaletta\">🔁",
"mt_one": "lopeta yhden toiston jälkeen\">1⃣",
@ -312,8 +312,8 @@ Ls.fin = {
"mt_c2owa": "opus-weba, iOS 17.5:lle ja uudemmille\">owa",
"mt_c2caf": "opus-caf, iOS 11:lle - 17:lle\">caf",
"mt_c2mp3": "käytä tätä erittäin vanhoissa laitteissa\">mp3",
"mt_c2flac": "paras äänenlaatu, mutta isot lataukset\">flac", //m
"mt_c2wav": "pakkaamaton toisto (vielä suurempi tiedosto)\">wav", //m
"mt_c2flac": "paras äänenlaatu, suuremmat latauskoot\">flac",
"mt_c2wav": "pakkaamaton toisto, suurimmat latauskoot\">wav",
"mt_c2ok": "hienoa, hyvä valinta",
"mt_c2nd": "tuo ei ole suositeltu formaatti laitteellesi, mutta tee miten lystäät",
"mt_c2ng": "laitteesi ei näytä tukevan tätä formaattia, mutta yritetään nyt silti",
@ -321,12 +321,11 @@ Ls.fin = {
"mt_tint": "taustan taso (0-100) liukupalkissa$Ntehden puskuroinnista vähemmän häiritsevän",
"mt_eq": "`aktivoi taajuuskorjaimen ja vahvistussäätimen;$N$Nvahvistus `0` = normaali 100% äänenvoimakkuus (muokkaamaton)$N$Nleveys `1 &nbsp;` = normaali stereo (muokkaamaton)$Nleveys `0.5` = 50% vasen-oikea ristisyöttö$Nleveys `0 &nbsp;` = mono$N$Nvahvistus `-0.8` &amp; leveys `10` = laulun poisto :^)$N$Nequalizerin käyttöönotto tekee saumattomista albumeista täysin saumattomia, joten jätä se päälle kaikilla arvoilla nollassa (paitsi leveys = 1) jos välität siitä",
"mt_drc": "aktivoi dynaamisen alueen kompressorin; ottaa myös käyttöön taajuuskorjaimen tasapainottamaan spagettia, joten aseta kaikki EQ-kentät paitsi 'leveys' nollaan jos et halua sitä$N$Nalentaa äänenvoimakkuutta KYNNYS dB:n yläpuolella; jokaisesta SUHDE dB:stä KYNNYKSEN yli tulee 1 dB ulos, joten oletusarvot kynnys -24 ja suhde 12 tarkoittaa ettei sen pitäisi koskaan tulla kovempaa kuin -22 dB ja on turvallista nostaa equalizerin vahvistus 0.8:aan, tai jopa 1.8:aan ATK 0:lla ja valtavalla RLS:llä kuten 90 (toimii vain firefoxissa; RLS on max 1 muissa selaimissa)$N$N(katso wikipedia, he selittävät sen paljon paremmin)",
"mt_ss": "`ottaa käyttöön hiljaisuuden ohituksen; moninkertaistaa toistonopeuden `pik` lähellä kappaleen alkua/loppua, kun äänenvoimakkuus on alle `vol` ja sijainti on ensimmäisessä `alk`% tai viimeisessä `lop`%", //m
"mt_ssvt": "äänenvoimakkuuden kynnys (0-255)\">vol", //m
"mt_ssts": "aktiivikynnys (% kappale, alku)\">alk", //m
"mt_sste": "aktiivikynnys (% kappale, loppu)\">lop", //m
"mt_ssrt": "äänenvoim./nopeuden nousu/laskuaika\">häiv", //m
"mt_sssm": "toistonopeuden kerroin\">pik", //m
"mt_ss": "`ottaa käyttöön hiljaisuuden ohituksen; moninkertaistaa toistonopeuden `nop`:lla lähellä kappaleen alkua/loppua, kun äänenvoimakkuus on alle `vol` ja kappaleesta on kulunut vasta on `alk`% tai sitä on jäljellä enää `lop`%",
"mt_ssvt": "äänenvoimakkuuden kynnysarvo (0-255)\">vol",
"mt_ssts": "alkuraja (prosenttia kappaleen alusta)\">alk",
"mt_sste": "loppuraja (prosenttia kappaleen lopusta)\">lop",
"mt_sssm": "toistonopeuden kerroin (min. 0.15, max. 8))\">nop",
"mb_play": "toista",
"mm_hashplay": "soita tämä äänitiedosto?",
@ -343,7 +342,7 @@ Ls.fin = {
"mm_eunk": "Tuntematon virhe",
"mm_e404": "Kappaletta ei voitu toistaa; virhe 404: Tiedostoa ei löydy.",
"mm_e403": "Kappaletta ei voitu toistaa; virhe 403: Pääsy kielletty.\n\nKokeile painaa F5 päivittääksesi, ehkä kirjauduit ulos",
"mm_e415": "Kappaletta ei voitu toistaa; virhe 415: Tiedoston muunnos epäonnistui; tarkista palvelinlokit.", //m
"mm_e415": "Kappaletta ei voitu toistaa; virhe 415: Tiedoston muunnos epäonnistui; tarkista palvelimen lokitiedostot.",
"mm_e500": "Kappaletta ei voitu toistaa; virhe 500: Tarkista palvelinlokit.",
"mm_e5xx": "Kappaletta ei voitu toistaa; palvelinvirhe ",
"mm_nof": "ei löydy enempää äänitiedostoja lähistöltä",
@ -363,7 +362,7 @@ Ls.fin = {
"f_anota": "vain {0} / {1} kohdetta valittiin;\nvalitaksesi koko hakemiston, vieritä ensin loppuun",
"f_dls": 'nykyisen hakemiston tiedostolinkit on\nvaihdettu latauslinkeiksi',
"f_dl_nd": 'ohitetaan kansio (käytä zip/tar-latausta sen sijaan):\n', //m
"f_dl_nd": 'ohitetaan kansio (käytä sen sijaan zip/tar-latausta):\n',
"f_partial": "Ladataksesi turvallisesti tiedoston joka on parhaillaan latautumassa, klikkaa tiedostoa jolla on sama nimi mutta ilman <code>.PARTIAL</code> päätettä. Paina PERUUTA tai Escape tehdäksesi tämän.\n\nOK / Enter painaminen sivuuttaa tämän varoituksen ja jatkaa <code>.PARTIAL</code> väliaikaistiedoston lataamista, mikä todennäköisesti antaa sinulle vioittunutta dataa.",
@ -432,16 +431,16 @@ Ls.fin = {
"fcc_warn": 'kopioitiin {0} kohdetta leikepöydälle\n\nmutta: vain <b>tämä</b> selain-välilehti voi liittää ne\n(koska valinta on niin valtavan suuri)',
"fp_apply": "käytä näitä nimiä",
"fp_skip": "ohita ristiriidat", //m
"fp_skip": "ohita ristiriitatilanteissa",
"fp_ecut": "leikkaa tai kopioi ensin joitakin tiedostoja / hakemistoja liitettäväksi / siirrettäväksi\n\nhuom: voit leikata / liittää eri selain-välilehtien välillä",
"fp_ename": "{0} kohdetta ei voida siirtää tänne koska nimet ovat jo käytössä. Anna niille uudet nimet alla jatkaaksesi, tai tyhjennä nimi (\"ohita ristiriidat\") ohittaaksesi ne:", //m
"fcp_ename": "{0} kohdetta ei voida kopioida tänne koska nimet ovat jo käytössä. Anna niille uudet nimet alla jatkaaksesi, tai tyhjennä nimi (\"ohita ristiriidat\") ohittaaksesi ne:", //m
"fp_ename": "{0} kohdetta ei voida siirtää tänne koska nimet ovat jo käytössä. Anna niille uudet nimet alla jatkaaksesi, tai tyhjennä nimi (\"ohita ristiriitatilanteissa\") ohittaaksesi ne:",
"fcp_ename": "{0} kohdetta ei voida kopioida tänne koska nimet ovat jo käytössä. Anna niille uudet nimet alla jatkaaksesi, tai tyhjennä nimi (\"ohita ristiriitatilanteissa\") ohittaaksesi ne:",
"fp_emore": "tiedostonimien törmäyksiä on vielä korjaamatta",
"fp_ok": "siirto OK",
"fcp_ok": "kopiointi OK",
"fp_busy": "siirretään {0} kohdetta...\n\n{1}",
"fcp_busy": "kopioidaan {0} kohdetta...\n\n{1}",
"fp_abrt": "keskeytetään...", //m
"fp_abrt": "keskeytetään...",
"fp_err": "siirto epäonnistui:\n",
"fcp_err": "kopiointi epäonnistui:\n",
"fp_confirm": "siirrä nämä {0} kohdetta tänne?",
@ -454,8 +453,8 @@ Ls.fin = {
"fcp_both_b": '<a href="#" id="modal-ok">Kopioi</a><a href="#" id="modal-ng">Lähetä</a>',
"mk_noname": "kirjoita nimi vasemmalla olevaan tekstikenttään ennen kuin teet tuon :p",
"nmd_i1": "voit myös lisätä haluamasi tiedostopäätteen, esimerkiksi <code>.md</code>", //m
"nmd_i2": "voit luoda vain <code>.{0}</code>-tiedostoja, koska sinulla ei ole poistolupaa", //m
"nmd_i1": "voit myös lisätä haluamasi tiedostopäätteen, esimerkiksi <code>.md</code>",
"nmd_i2": "voit luoda vain <code>.{0}</code>-tiedostoja, koska sinulla ei ole “delete”-oikeutta",
"tv_load": "Ladataan tekstidokumenttia:\n\n{0}\n\n{1}% ({2} / {3} Mt ladattu)",
"tv_xe1": "tekstitiedoston lataaminen epäonnistui:\n\nvirhe ",
@ -466,7 +465,7 @@ Ls.fin = {
"tvt_prev": "näytä edellinen dokumentti$NPikanäppäin: i\">⬆ edell",
"tvt_next": "näytä seuraava dokumentti$NPikanäppäin: K\">⬇ seur",
"tvt_sel": "valitse tiedosto &nbsp; ( leikkausta / kopiointia / poistoa / ... varten )$NPikanäppäin: S\">val",
"tvt_j": "kaunista json$NPikanäppäin: shift-J\">j", //m
"tvt_j": "muotoile/siisti json$NPikanäppäin: shift-J\">j",
"tvt_edit": "avaa tiedosto tekstieditorissa$NPikanäppäin: E\">✏️ muokkaa",
"tvt_tail": "seuraa tiedoston muutoksia; näytä uudet rivit reaaliaikaisesti\">📡 seuraa",
"tvt_wrap": "rivitys\">↵",
@ -651,25 +650,25 @@ Ls.fin = {
"ur_um": "Valmis;\n{0} latausta OK,\n{1} latausta epäonnistui, pahoittelen",
"ur_sm": "Valmis;\n{0} tiedostoa löytyi palvelimelta,\n{1} tiedostoa EI löytynyt palvelimelta",
"rc_opn": "avaa", //m
"rc_ply": "toista", //m
"rc_pla": "toista äänenä", //m
"rc_txt": "avaa tiedostoselaimessa", //m
"rc_md": "avaa tekstieditorissa", //m
"rc_dl": "Lataa", //m
"rc_zip": "Lataa arkistona", //m
"rc_cpl": "kopioi linkki", //m
"rc_del": "poista", //m
"rc_cut": "Leikkaa", //m
"rc_cpy": "kopioi", //m
"rc_pst": "Liitä", //m
"rc_rnm": "nimeä uudelleen", //m
"rc_nfo": "uusi kansio", //m
"rc_nfi": "uusi tiedosto", //m
"rc_sal": "valitse kaikki", //m
"rc_sin": "käännä valinta", //m
"rc_shf": "jaa tämä kansio", //m
"rc_shs": "jaa valinta", //m
"rc_opn": "avaa",
"rc_ply": "toista",
"rc_pla": "toista äänitiedostona",
"rc_txt": "avaa tekstinäkymässä",
"rc_md": "avaa markdown-näkymässä",
"rc_dl": "lataa",
"rc_zip": "lataa arkistona",
"rc_cpl": "kopioi linkki",
"rc_del": "poista",
"rc_cut": "leikkaa",
"rc_cpy": "kopioi",
"rc_pst": "liitä",
"rc_rnm": "nimeä uudelleen",
"rc_nfo": "uusi kansio",
"rc_nfi": "uusi tiedosto",
"rc_sal": "valitse kaikki",
"rc_sin": "käänteinen valinta",
"rc_shf": "jaa tämä kansio",
"rc_shs": "jaa valinta",
"lang_set": "ladataanko sivu uudestaan kielen vaihtamiseksi?",
@ -689,11 +688,11 @@ Ls.fin = {
"j1": "k304 katkaisee yhteytesi jokaisella HTTP 304:llä, mikä voi estää joitain bugisia välityspalvelimia jumittumasta/lopettamasta sivujen lataamista, <em>mutta</em> se myös vähentää suorituskykyä",
"k1": "nollaa asetukset",
"l1": "kirjaudu sisään:",
"ls3": "kirjaudu sisään", //m
"lu4": "käyttäjätunnus", //m
"lp4": "salasana", //m
"lo3": "kirjaa “{0}” ulos kaikkialta", //m
"lo2": "tämä lopettaa istunnon kaikissa selaimissa", //m
"ls3": "kirjaudu sisään",
"lu4": "käyttäjätunnus",
"lp4": "salasana",
"lo3": "kirjaa “{0}” ulos kaikkialta",
"lo2": "tämä lopettaa istunnon kaikissa selaimissa",
"m1": "tervetuloa takaisin,",
"n1": "404: ei löytynyt mitään &nbsp;┐( ´ -`)┌",
"o1": 'tai ehkä sinulla ei vain ole käyttöoikeuksia? kokeile salasanaa tai <a href="' + SR + '/?h">mene kotiin</a>',
@ -712,8 +711,8 @@ Ls.fin = {
"ta1": "täytä ensin uusi salasana",
"ta2": "toista vahvistaaksesi uuden salasanan:",
"ta3": "löytyi kirjoitusvirhe; yritä uudelleen",
"nop": "VIRHE: Salasana ei voi olla tyhjä", //m
"nou": "VIRHE: Käyttäjänimi ja/tai salasana ei voi olla tyhjä", //m
"nop": "VIRHE: Salasana ei voi olla tyhjä",
"nou": "VIRHE: Käyttäjänimi ja/tai salasana ei voi olla tyhjä",
"aa1": "saapuvat:",
"ab1": "poista no304 käytöstä",
"ac1": "ota no304 käyttöön",

View file

@ -325,7 +325,6 @@ Ls.fra = {
"mt_ssvt": "seuil de volume (0-255)\">vol", //m
"mt_ssts": "seuil actif (% piste, début)\">deb", //m
"mt_sste": "seuil actif (% piste, fin)\">fin", //m
"mt_ssrt": "temps de montée/descente volume/vitesse\">fondu", //m
"mt_sssm": "multiplicateur de vitesse de lecture\">av", //m
"mb_play": "lecture",

View file

@ -325,7 +325,6 @@ Ls.grc = {
"mt_ssvt": "ὅριον φωνῆς (0-255)\">φων", //m
"mt_ssts": "ἐνεργὸν ὅριον (% τροχιᾶς, ἀρχή)\">ἀρχ", //m
"mt_sste": "ἐνεργὸν ὅριον (% τροχιᾶς, τέλος)\">τελ", //m
"mt_ssrt": "χρόνος αὔξησης/μείωσης φωνῆς/ταχύτητος\">σβέσις", //m
"mt_sssm": "πολλαπλασιαστὴς ταχύτητος\">ταχ", //m
"mb_play": "παίξε",

View file

@ -326,7 +326,6 @@ Ls.hun = {
"mt_ssvt": 'hangerő küszöb (0-255)">vol',
"mt_ssts": 'aktív tartomány (%, eleje)">start',
"mt_sste": 'aktív tartomány (%, vége)">end',
"mt_ssrt": 'hangosodási/halkulási idő">fade',
"mt_sssm": 'lejátszási sebesség szorzó">ffwd',
"mb_play": 'play',

View file

@ -325,7 +325,6 @@ Ls.ita = {
"mt_ssvt": "soglia volume (0-255)\">vol", //m
"mt_ssts": "soglia attiva (% traccia, inizio)\">ini", //m
"mt_sste": "soglia attiva (% traccia, fine)\">fin", //m
"mt_ssrt": "tempo rampa volume/velocità\">fade", //m
"mt_sssm": "moltiplicatore velocità riproduzione\">av", //m
"mb_play": "riproduci",

View file

@ -325,7 +325,6 @@ Ls.jpn = {
"mt_ssvt": "音量しきい値 (0-255)\">音", //m
"mt_ssts": "有効しきい値 (トラック%, 開始)\">始", //m
"mt_sste": "有効しきい値 (トラック%, 終了)\">終", //m
"mt_ssrt": "音量/速度 ランプ時間\">フェード", //m
"mt_sssm": "再生速度倍率\">速", //m
"mb_play": "再生",

View file

@ -325,7 +325,6 @@ Ls.kor = {
"mt_ssvt": "볼륨 임계값 (0-255)\">음", //m
"mt_ssts": "활성 임계값 (% 트랙, 시작)\">시", //m
"mt_sste": "활성 임계값 (% 트랙, 끝)\">끝", //m
"mt_ssrt": "볼륨/속도 램프 시간\">페이드", //m
"mt_sssm": "재생 속도 배율\">고", //m
"mb_play": "재생",

View file

@ -325,7 +325,6 @@ Ls.nld = {
"mt_ssvt": "Volumedrempel (0-255)\">vol", //m
"mt_ssts": "Actieve drempel (% track, begin)\">beg", //m
"mt_sste": "Actieve drempel (% track, einde)\">eind", //m
"mt_ssrt": "Op/aflooptijd volume/snelheid\">fade", //m
"mt_sssm": "Vermenigvuldiger afspeelsnelheid\">vrs", //m
"mb_play": "Afspelen",

View file

@ -322,7 +322,6 @@ Ls.nno = {
"mt_ssvt": "volumterskel (0-255)\">volum",
"mt_ssts": "aktiv innanfor første % av songen\">start",
"mt_sste": "aktiv innanfor siste % av songen\">slutt",
"mt_ssrt": "kor fort volum/tempo skal justerast\">fade",
"mt_sssm": "avspelingshastigheitsmultiplikator\">ffwd",
"mb_play": "lytt",

View file

@ -322,7 +322,6 @@ Ls.nor = {
"mt_ssvt": "volumterskel (0-255)\">volum",
"mt_ssts": "aktiv innenfor første % av sangen\">start",
"mt_sste": "aktiv innenfor siste % av sangen\">slutt",
"mt_ssrt": "hvor fort volum/tempo skal justeres\">fade",
"mt_sssm": "avspillingshastighetsmultiplikator\">ffwd",
"mb_play": "lytt",

View file

@ -328,7 +328,6 @@ Ls.pol = {
"mt_ssvt": "próg głośności (0-255)\">gł", //m
"mt_ssts": "aktywny próg (% utworu, początek)\">pocz", //m
"mt_sste": "aktywny próg (% utworu, koniec)\">kon", //m
"mt_ssrt": "czas narastania/opadania głośn./pręd.\">fade", //m
"mt_sssm": "mnożnik prędkości odtwarzania\">szyb", //m
"mb_play": "odtwórz",

View file

@ -325,7 +325,6 @@ Ls.por = {
"mt_ssvt": "limiar de volume (0-255)\">vol", //m
"mt_ssts": "limiar ativo (% faixa, início)\">ini", //m
"mt_sste": "limiar ativo (% faixa, fim)\">fim", //m
"mt_ssrt": "tempo de rampa volume/velocidade\">fade", //m
"mt_sssm": "multiplicador de velocidade de reprodução\">av", //m
"mb_play": "reproduzir",

View file

@ -325,7 +325,6 @@ Ls.rus = {
"mt_ssvt": "порог громкости (0-255)\">гром", //m
"mt_ssts": "активный порог (% трека, начало)\">нач", //m
"mt_sste": "активный порог (% трека, конец)\">кон", //m
"mt_ssrt": "время нарастания/спада громк./скор.\">фейд", //m
"mt_sssm": "множитель скорости воспроизведения\">уск", //m
"mb_play": "играть",

View file

@ -324,7 +324,6 @@ Ls.spa = {
"mt_ssvt": "umbral de volumen (0-255)\">vol", //m
"mt_ssts": "umbral activo (% pista, inicio)\">ini", //m
"mt_sste": "umbral activo (% pista, fin)\">fin", //m
"mt_ssrt": "tiempo de rampa volumen/velocidad\">fund", //m
"mt_sssm": "multiplicador de velocidad de reproducción\">av", //m
"mb_play": "reproducir",

View file

@ -325,7 +325,6 @@ Ls.swe = {
"mt_ssvt": "volymtröskel (0-255)\">vol", //m
"mt_ssts": "aktiv tröskel (% spår, start)\">sta", //m
"mt_sste": "aktiv tröskel (% spår, slut)\">slt", //m
"mt_ssrt": "upp/ned-rampningstid volym/hastighet\">fade", //m
"mt_sssm": "uppspelningshastighetsmultiplikator\">sn", //m
"mb_play": "play",

View file

@ -325,7 +325,6 @@ Ls.tur = {
"mt_ssvt": "ses eşiği (0-255)\">ses", //m
"mt_ssts": "etkin eşik (% parça, başlangıç)\">bas", //m
"mt_sste": "etkin eşik (% parça, bitiş)\">son", //m
"mt_ssrt": "ses/hız rampa süresi\">fade", //m
"mt_sssm": "oynatma hızı çarpanı\">ileri", //m
"mb_play": "oynat",

View file

@ -325,7 +325,6 @@ Ls.ukr = {
"mt_ssvt": "поріг гучності (0-255)\">гуч", //m
"mt_ssts": "активний поріг (% треку, початок)\">поч", //m
"mt_sste": "активний поріг (% треку, кінець)\">кін", //m
"mt_ssrt": "час нарост./спаду гучн./швидк.\">фейд", //m
"mt_sssm": "множник швидкості відтворення\">шв", //m
"mb_play": "відтворити",

View file

@ -332,7 +332,6 @@ Ls.vie = {
"mt_ssvt": "ngưỡng âm lượng (0-255)\">am", //m
"mt_ssts": "ngưỡng hoạt động (% bài, đầu)\">dau", //m
"mt_sste": "ngưỡng hoạt động (% bài, cuối)\">cuoi", //m
"mt_ssrt": "thời gian tăng/giảm âm lượng/tốc độ\">fade", //m
"mt_sssm": "hệ số tốc độ phát\">nh", //m
"mb_play": "phát",

53
docs/bad-codecs.md Normal file
View file

@ -0,0 +1,53 @@
due to legal reasons, the copyparty [docker image](https://github.com/9001/copyparty/blob/hovudstraum/scripts/docker) and [bootable flashdrive](https://a.ocv.me/pub/stuff/edcd001/enterprise-edition/) are not able to decode and display images and videos which were made using certain codecs
* specifically, photos and videos taken with iphones will not work, and perhaps some samsung phones, idk
* this also includes thumbnails thereof
I suggest you stop reading at this point, unless you want to share my frustration, in which case please do continue
## why hevc is not included
the following is my understanding, which is probably wrong because [I anal](https://en.wikipedia.org/wiki/IANAL)
* the h265 codec, also known as h.265 and hevc, is patent-encumbered and legally problematic to distribute;
* there are several patent-pools of patent-holders with conflicting and unclear requirements
* even FOSS is not exempt from demands of payment; https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding#Provision_for_costless_software
* I have no idea how "number of sales" maps to FOSS, but copyparty doesn't have telemetry so it would be impossible to satisfy the requirements either way
* due to this, both chrome and firefox refuse to add a built-in decoder for hevc; https://caniuse.com/hevc
* and while I haven't discussed this with a lawyer, I presume the reason is they did
* most heif/heic images are hevc, meaning they are equally troublesome
* safari is the only webbrowser willing to decode and display heif/heic photos, for self-inflicted reasons https://caniuse.com/heif
and anyways there's no reason to use hevc in the first place because [av1](https://en.wikipedia.org/wiki/AV1) gives higher quality at a smaller filesize, is entirely free, and avif (its heif counterpart) is widely supported across all browsers: https://caniuse.com/avif
## why only the docker and flashdrive images are affected
supposedly, royalties is like a jigsaw puzzle, where whoever lays down the last piece wins the responsibility of dealing with that mess -- and because the docker-image has everything bundled as one big ball of software, that might(?) be a problem...idk, i anal
so because ffmpeg is the component that handles everything regarding hevc, only the packages which include ffmpeg are affected, which means the docker-image and bootable-flashdrive-image
if you use or install copyparty in any other way, then you are in charge of obtaining and providing an ffmpeg for copyparty to use, and thus nothing has changed
## how hevc support was removed
the regular ffmpeg package from the alpinelinux repos was replaced with a [custom ffmpeg build](https://github.com/9001/copyparty/tree/hovudstraum/scripts/docker/base) where the hevc decoder was physically stripped out, meaning hevc is not just "disabled", but entirely removed from all official copyparty distributions
oh and the aac support has also been tampered with; now only AAC-LC can be decoded, which is fine because that's like 99% of all aac files (nobody uses HE-AAC or AAC-LD), and LC-AAC has become royalty-free in all relevant parts of the world at this point
and any traces of vvc was also stripped out because that codec was dead on arrival, unable to compete with av1 (and soon av2)
the silver lining is that this has made the docker images *much* smaller; the `ac` image is now half the size -- it went from 67 to 35 MiB gzipped, from 195 to 99 MiB installed, which is nice
## how to enable hevc support
all I can say is good luck; I legally cannot help you with that
see, here's the fun part -- apparently I'm not allowed to assist with a technical explanation on how it could be done, because that would "facilitate access" as they call it?? but all copyparty does is call `ffmpeg` to generate the thumbnail; copyparty doesn't even know or care what "hevc" is; this is all purely on the ffmpeg side of things -- so technically none of this is even related to copyparty itself in the first place... ah whatever
man I just wanna write software, I hate this
pain peko

View file

@ -1,3 +1,88 @@
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# 2026-0225-0834 `v1.20.9` SECURITY: XSS fix
## ⚠️ ATTN: this release fixes an XSS vulnerability
[GHSA-62cr-6wp5-q43h](https://github.com/9001/copyparty/security/advisories/GHSA-62cr-6wp5-q43h) could let an attacker execute arbitrary JS by tricking you into clicking a malicious link 31b2801f
## 🔧 other changes
* webdav: [dav-port](https://copyparty.eu/cli/#g-dav-port) can be used as an alternative to [daw](https://copyparty.eu/cli/#g-daw) d21242fc
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# 2026-0222-1507 `v1.20.8` no265
## 🧪 new features
* #1298 add Hungarian translation (thx @sonacl!) eefb181b f37c3b96
* #1299 chown now accepts 4-digit values (thx @new-sashok724!) 5a7504fd
## 🩹 bugfixes
* audioplayer skip-silence:
* #1303 clamp ffwd to safe values (thx @icxes!) f5e70c7f
* fix crash on folderchange f1a433a6
## 🔧 other changes
* due to [legal reasons](https://github.com/9001/copyparty/blob/hovudstraum/docs/bad-codecs.md), the [docker-images](https://github.com/9001/copyparty/blob/hovudstraum/scripts/docker) and [bootable flashdrive](https://a.ocv.me/pub/stuff/edcd001/enterprise-edition/) are now unable to create thumbnails of HEVC/h265 videos and heif/heic images 1bec91d1
* this primarily means photos/videos taken with iphones (and maybe some samsung phones)
* on the bright side, this has made the docker-images much smaller; `ac` is now half the size it used to be, and `iv` / `dj` are each 97 MiB smaller
## 🌠 fun facts
* if you wanna see your car doing its best impression of a frictionless spherical cow, I can warmly (heh) recommend the icy snowcoated countryroads of viken this weekend
* goes oddly well with [sakuraburst - deconstructing nature](https://www.youtube.com/watch?v=MJjO-pwYpJg)
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# 2026-0214-2315 `v1.20.7` fika
## 🧪 new features
* now possible to upload/delete files while the filesystem-indexer is still busy d44ea245 0ca4c1bd
* global-option [fika](https://copyparty.eu/cli/#g-fika) decides which actions to allow while still indexing; default is upload+copy+delete
* full deduplication is only guaranteed if this option is set blank, as dupes are allowed while indexing
* #1266 browsers can request thumbnails as jxl images, and view jxl files in the gallery (thx @intelfx!) b2711e05 720c83b2 93ffc65c a65a30b1 a7a25deb 59de5e2c 16403d8c 48c10178 0e8913c2
* only works in browsers which support jxl, which is FINALLY happening ([sure took a while](https://issues.chromium.org/issues/40168998))
* some notes on memory/RAM usage though -- it is fine on Alpine Linux, so docker is also fine, just don't enable mimalloc
* jxl can be disabled with global-option [th-no-jxl](https://copyparty.eu/cli/#g-th-no-jxl) if necessary on baremetal deployments until libvips fixes this
* #1265 audioplayer can "skip silence" now (thx @icxes!) 66949989
* #1287 opensearch support for opds (thx @philips!) 84e687a0
* #1276 option [rw-edit](https://copyparty.eu/cli/#g-rw-edit) is the list of file-extensions that can be edited as textfiles with only permissions read+write (default is `md` like before); all other files still require read+write+delete 312f48e1 d6928380
* #1288 option to customize the links copied when selecting files and pressing ctrl-c (thx @icxes!) e5d0a057
* docker: add env-var [DI_PREPARTY](https://github.com/9001/copyparty/blob/hovudstraum/scripts/docker/devnotes.md#modding-on-the-fly) to run an arbitrary script during startup, for customizations and such bf01ca48
## 🩹 bugfixes
* #1279 the textfile-viewer would refuse to load huge documents when hotlinked f02e9cf6
* #1280 the custom rightclick-menu was enabled in the textfile viewer fc8a4b8e
* #1262 logtail now works on windows; would previously take an exclusive-lock on the monitored file, as windows does by default a368fc66
## 🔧 other changes
* volumes are hidden from the treeview if the name starts with a dot 76041fdb
* #1277 `descript.ion` files no longer require the `e2d` and `e2t` options to be enabled 4cb4e820
* chunked PUT-uploads are now terminated if they exceed a configured size limit dfadb5a7
* #1282 improved compatibility with GraalPy (thx @vgskye!) e8609b87
* #1292 #1296 updated Esperanto translation (thx @slashdevslashurandom!) 418bf2f9 914f84ce
* thumbnails: use libvips as fallback for rawpy 27ae2e1e
* libvips doesn't support .arw files (sony) yet, so still need rawpy
* make server config slightly easier:
* improve xff warnings 96aeb898
* warn if config-values are quoted 598df44e
* lowercase headernames in configs fd096385
## 🌠 fun facts
* the `fika` option sends the filesystem-indexer on [a coffee break](https://en.wikipedia.org/wiki/Coffee_in_Sweden#Fika)
* exci wants me to mention aoi yuuki here for some reason :^) so here's [gekisou gungnir](https://www.youtube.com/watch?v=feeFscLH6QE)
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
# 2026-0131-2001 `v1.20.6` one safeguard too many

View file

@ -10,11 +10,9 @@ ENV XDG_CONFIG_HOME=/cfg
RUN apk --no-cache add !pyc \
tzdata wget mimalloc2 mimalloc2-insecure \
py3-jinja2 py3-argon2-cffi py3-pyzmq \
py3-openssl py3-paramiko py3-pillow \
ffmpeg
py3-openssl py3-paramiko py3-pillow
COPY i/dist/copyparty-sfx.py innvikler.sh ./
ADD base ./base
COPY i innvikler.sh ./
RUN ash innvikler.sh ac
WORKDIR /state

View file

@ -15,15 +15,15 @@ RUN apk add -U !pyc \
py3-jinja2 py3-argon2-cffi py3-pyzmq \
py3-openssl py3-paramiko py3-pillow \
py3-pip py3-cffi \
ffmpeg \
py3-magic \
vips-jxl vips-heif vips-poppler vips-magick \
vips-jxl vips-poppler vips-magick \
py3-numpy fftw libsndfile \
vamp-sdk vamp-sdk-libs keyfinder-cli \
libraw py3-numpy \
&& apk add -t .bd \
bash wget gcc g++ make cmake patchelf \
python3-dev ffmpeg-dev fftw-dev libsndfile-dev \
ffmpeg ffmpeg-dev \
python3-dev fftw-dev libsndfile-dev \
py3-wheel py3-numpy-dev libffi-dev \
vamp-sdk-dev \
libraw-dev py3-numpy-dev cython \
@ -35,8 +35,7 @@ RUN apk add -U !pyc \
&& chmod 777 /root \
&& ln -s /root/vamp /root/.local /
COPY i/dist/copyparty-sfx.py innvikler.sh ./
ADD base ./base
COPY i innvikler.sh ./
RUN ash innvikler.sh dj
WORKDIR /state

View file

@ -12,8 +12,7 @@ RUN apk --no-cache add !pyc \
py3-jinja2 py3-argon2-cffi \
py3-openssl py3-paramiko py3-pillow py3-mutagen
COPY i/dist/copyparty-sfx.py innvikler.sh ./
ADD base ./base
COPY i innvikler.sh ./
RUN ash innvikler.sh im
WORKDIR /state

View file

@ -12,9 +12,8 @@ RUN apk add -U !pyc \
py3-jinja2 py3-argon2-cffi py3-pyzmq \
py3-openssl py3-paramiko py3-pillow \
py3-pip py3-cffi \
ffmpeg \
py3-magic \
vips-jxl vips-heif vips-poppler vips-magick \
vips-jxl vips-poppler vips-magick \
libraw py3-numpy \
&& apk add -t .bd \
bash wget gcc g++ make cmake patchelf \
@ -25,8 +24,7 @@ RUN apk add -U !pyc \
&& python3 -m pip install "$(wget -O- https://api.github.com/repos/letmaik/rawpy/releases/latest | awk -F\" '$2=="tarball_url"{print$4}')" \
&& apk del py3-pip .bd
COPY i/dist/copyparty-sfx.py innvikler.sh ./
ADD base ./base
COPY i innvikler.sh ./
RUN ash innvikler.sh iv
WORKDIR /state

View file

@ -10,7 +10,7 @@ ENV XDG_CONFIG_HOME=/cfg
RUN apk --no-cache add !pyc \
py3-jinja2
COPY i/dist/copyparty-sfx.py innvikler.sh ./
COPY i innvikler.sh ./
RUN ash innvikler.sh min
WORKDIR /state

View file

@ -2,4 +2,7 @@ FROM alpine:latest
WORKDIR /z
RUN apk add py3-pip make gcc musl-dev python3-dev
RUN pip wheel https://files.pythonhosted.org/packages/c4/a7/0b7673be5945071e99364a3ac1987b02fc1d416617e97f3e8816d275174e/zlib_ng-0.5.1.tar.gz
RUN pip wheel https://files.pythonhosted.org/packages/46/7d/901c6e333fb031b5bfbd1532099200cf859f12aa83689be494eade6685ec/zlib_ng-1.0.0.tar.gz \
&& mkdir whl \
&& mv *.whl whl

View file

@ -1,14 +1,26 @@
self := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))
all:
# build all outdated
bash verchk.sh
ff:
# legally comfy
/usr/bin/time ./build-no265.sh img
zlib:
# build zlib-ng from source so we know how the sausage was made
# (still only doing the archs which are officially supported/tested)
podman build --arch amd64 -t localhost/cpp-zlibng-amd64:latest -f Dockerfile.zlibng .
podman run --arch amd64 --rm --log-driver=none -i localhost/cpp-zlibng-amd64:latest tar -cC/z . | tar -xv
podman run --arch amd64 --rm --log-driver=none -i localhost/cpp-zlibng-amd64:latest tar -cC/z whl | tar -xv
podman build --arch arm64 -t localhost/cpp-zlibng-amd64:latest -f Dockerfile.zlibng .
podman run --arch arm64 --rm --log-driver=none -i localhost/cpp-zlibng-amd64:latest tar -cC/z . | tar -xv
podman run --arch arm64 --rm --log-driver=none -i localhost/cpp-zlibng-amd64:latest tar -cC/z whl | tar -xv
sh:
@printf "\n\033[1;31mopening a shell in the most recently created docker image\033[0m\n"

View file

@ -0,0 +1,65 @@
#!/bin/ash
set -e
[ $1 = 1 ] && hub=1
uname -a
apk add alpine-sdk doas wget
echo permit nopass root > /etc/doas.d/u.conf
cp -pv /root/.abuild/*.pub /etc/apk/keys/ || abuild-keygen -ina
##
## yeet h265
mkdir /ffmpeg
cd /ffmpeg
base=https://github.com/alpinelinux/aports/raw/refs/heads/3.23-stable/community/ffmpeg/
wget ${base}APKBUILD
awk <APKBUILD -vb="$base" '/"/{o=0}/^source=/{o=1;next}o{print b $1}' | wget -i-
cp -pv APKBUILD /root/
# grep -E '^extern const.* FF[^ ]+ +ff_(hevc|vvc)_' libavcodec/allcodecs.c libavcodec/hwaccels.h libavcodec/bitstream_filters.c libavcodec/parsers.c libavformat/allformats.c | sed -r 's/.* ff_([^/;]*)_([^/;]*);.*/--disable-\2=\1/' | tr '\n' ' '
sed -ri 's/--enable-libx265/--disable-decoder=hevc --disable-decoder=hevc_qsv --disable-decoder=hevc_rkmpp --disable-encoder=hevc_rkmpp --disable-decoder=hevc_v4l2m2m --disable-decoder=vvc --disable-encoder=hevc_amf --disable-decoder=hevc_amf --disable-decoder=hevc_cuvid --disable-encoder=hevc_d3d12va --disable-decoder=hevc_mediacodec --disable-encoder=hevc_mediacodec --disable-encoder=hevc_mf --disable-encoder=hevc_nvenc --disable-decoder=hevc_oh --disable-encoder=hevc_oh --disable-encoder=hevc_qsv --disable-encoder=hevc_v4l2m2m --disable-encoder=hevc_vaapi --disable-encoder=hevc_videotoolbox --disable-encoder=hevc_vulkan --disable-decoder=vvc_qsv --disable-hwaccel=hevc_d3d11va --disable-hwaccel=hevc_d3d11va2 --disable-hwaccel=hevc_d3d12va --disable-hwaccel=hevc_dxva2 --disable-hwaccel=hevc_nvdec --disable-hwaccel=hevc_vaapi --disable-hwaccel=hevc_vdpau --disable-hwaccel=hevc_videotoolbox --disable-hwaccel=hevc_vulkan --disable-hwaccel=vvc_vaapi --disable-bsf=hevc_metadata --disable-bsf=hevc_mp4toannexb --disable-bsf=vvc_metadata --disable-bsf=vvc_mp4toannexb --disable-parser=hevc --disable-parser=vvc --disable-demuxer=hevc --disable-muxer=hevc --disable-demuxer=vvc --disable-muxer=vvc /;s/\bx265-dev\b//' APKBUILD
##
## yeet aac he/he+/ld (sbr/ps); keep lc only
cat >>APKBUILD <<'EOF'
prepare() {
default_prepare
tar -cC/opt/patch/ffmpeg . | tar -x
patch -p1 <aac-lc-only.patch
}
EOF
##
## shrink-ray
sed -ri 's/--enable-lib(bluray|placebo|rav1e|shaderc)/--disable-lib\1/; s/--enable-(vdpau)/--disable-\1/; s/\b(rav1e|shaderc)-dev//; s/\blib(bluray|placebo|vdpau|xfixes)-dev\b//' APKBUILD
# `- rm placebo+shaderc to drop spirv-tools (1.7 MiB apk)
sed -ri 's/--enable-libxcb/--disable-libxcb --disable-indev=xcbgrab --disable-ffplay --disable-encoder=opus /' APKBUILD
sed -ri 's/\bffplay$//; s/\bsdl2-dev\b//' APKBUILD
##
## golflympics; decode-only, super-specific for copyparty only
[ $hub ] || {
sed -ri 's/--enable-(ladspa|lv2|vaapi|vulkan)/--disable-\1/' APKBUILD
sed -ri 's/--enable-lib(aom|ass|drm|fontconfig|freetype|fribidi|harfbuzz|pulse|rist|srt|ssh|v4l2|vidstab|x264|xvid|zimg|vpl)/--disable-lib\1/' APKBUILD
sed -ri 's/\b(v4l-utils|libvpx)-dev\b//' APKBUILD # (try to) drop v4l2_m2m, and use builtin vp8/vp9 instead of libvpx for decode
sed -ri 's/(--disable-vulkan)/\1 --disable-devices --disable-hwaccels --disable-encoders --enable-encoder=flac --enable-encoder=libjxl --enable-encoder=libmp3lame --enable-encoder=libopus --enable-encoder=libwebp --enable-encoder=mjpeg --enable-encoder=pcm_s16le --enable-encoder=pcm_s16le_planar --enable-encoder=png --enable-encoder=rawvideo --enable-encoder=vnull --enable-encoder=wrapped_avframe --disable-muxers --enable-muxer=aiff --enable-muxer=apng --enable-muxer=caf --enable-muxer=ffmetadata --enable-muxer=fifo --enable-muxer=flac --enable-muxer=image2 --enable-muxer=image2pipe --enable-muxer=matroska --enable-muxer=matroska_audio --enable-muxer=mjpeg --enable-muxer=mp3 --enable-muxer=null --enable-muxer=opus --enable-muxer=pcm_s16le --enable-muxer=wav --enable-muxer=webm --enable-muxer=webp --enable-muxer=yuv4mpegpipe --disable-filters --enable-filter=anoisesrc --enable-filter=asplit --enable-filter=amerge --enable-filter=amix --enable-filter=aresample --enable-filter=crop --enable-filter=showspectrumpic --enable-filter=showwavespic --enable-filter=convolution --enable-filter=volume --enable-filter=compand --enable-filter=setsar --enable-filter=scale --disable-decoder=av1 --disable-hwaccel=v4l2_m2m --disable-decoder=h263_v4l2m2m --disable-decoder=h264_v4l2m2m --disable-decoder=mpeg1_v4l2m2m --disable-decoder=mpeg2_v4l2m2m --disable-decoder=mpeg4_v4l2m2m --disable-decoder=vc1_v4l2m2m --disable-decoder=vp8_v4l2m2m --disable-decoder=vp9_v4l2m2m --disable-decoder=subrip --disable-decoder=srt --disable-decoder=pgssub --disable-decoder=cc_dec --disable-decoder=dvdsub --disable-decoder=dvbsub --disable-decoder=ssa --disable-decoder=ass --disable-decoder=opus /' APKBUILD
# `- s/av1/libdav1d/; s/libvorbis/vorbis/; s/opus/libopus/; libvorbis and mpg123 gets pulled in by openmpt
}
p=/root/packages/$(abuild -A)
rm -rf $p
abuild -FrcK
mkdir $p/ex
mv $p/ffmpeg-d* $p/ex # dbg,dev,doc
cp -pv src/ffmpeg-*/ffbuild/config.log $p/
[ $hub ] && rm -rf $p.hub && mv $p $p.hub
cp -pv /root/.abuild/*.pub ~/packages/

View file

@ -0,0 +1,99 @@
#!/bin/bash
set -e
[ $(id -u) -eq 0 ] && {
echo dont root
exit 1
}
self=$(cd -- "$(dirname "$BASH_SOURCE")"; pwd -P)
cd "$self"
sarchs="386 amd64 arm/v7 arm64/v8 ppc64le s390x"
archs="amd64 amd64 386 arm64 arm s390x ppc64le"
err=
for x in awk jq podman python3 tar wget ; do
command -v $x >/dev/null && continue
err=1; echo ERROR: missing dependency: $x
done
[ $err ] && exit 1
for v in "$@"; do
[ "$v" = pull ] && pull=1
[ "$v" = img ] && img=1
done
[ $# -gt 0 ] || {
echo "need list of commands, for example: pull img"
exit 1
}
wt() {
printf '\033]0;%s\033\\' "$*"
[ -z "$TMUX" ] || tmux renamew "$*"
}
[ $pull ] && {
for a in $sarchs; do # arm/v6
podman pull --arch=$a alpine:latest
done
podman images --format "{{.ID}} {{.History}}" |
awk '/library\/alpine/{print$1}' |
while read id; do
tag=alpine-$(podman inspect $id | jq -r '.[]|.Architecture' | tr / -)
[ -e .tag-$tag ] && continue
touch .tag-$tag
echo tagging $tag
podman untag $id
podman tag $id $tag
done
rm .tag-*
}
[ $img ] && {
mkdir -p "$self/b"
# enable arm32 crossbuild from aarch64 (macbook or whatever)
[ $(uname -m) = aarch64 ] && [ ! -e /proc/sys/fs/binfmt_misc/qemu-arm ] &&
echo ":qemu-arm:M:0:\x7f\x45\x4c\x46\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/bin/qemu-arm-static:F" |
sudo tee >/dev/null /proc/sys/fs/binfmt_misc/register
# kill abandoned builders
ps aux | awk '/bin\/qemu-[^-]+-static/{print$2}' | xargs -r kill -9
n=0; set -x
for a in $archs; do
n=$((n+1)); wt "$n/$a"
#[ $n -le 3 ] || continue
touch b/t.$a.1.$(date +%s)
tar -c arbeidspakke.sh patch/ffmpeg |
time nice podman run \
--rm -i --pull=never -v "$self/b:/root:z" localhost/alpine-$a \
/bin/ash -c "cd /opt;tar -x;/bin/ash ./arbeidspakke.sh $n $a" 2>&1 |
tee b/log.$a
touch b/t.$a.2.$(date +%s)
done
wt -;wt ""
}
echo ok
# just-no265
# 4m18.77 x64
# 4m22.81 386
# 45m36.44 arm64
# 34m31.22 ppc64le
# 50m01.04 s390x
# golflympics
# 4:09 x86_64-hub
# 2:57 x86_64
# 2:54 x86
# 31:13 aarch64
# 22:38 armv7
# 32:17 s390x
# 24:27 ppc64le
# 2:00:35 summa summarum

View file

@ -0,0 +1,59 @@
remove all advanced aac features, leaving only aac-lc which is
no longer patent-encumbered in any relevant parts of the world
( and 99% of all aac files are lc-aac anyways so that's fine )
diff --git a/libavcodec/aac/aacdec.c b/libavcodec/aac/aacdec.c
index b8d53036d4..054c46f84e 100644
--- a/libavcodec/aac/aacdec.c
+++ b/libavcodec/aac/aacdec.c
@@ -880,9 +880,7 @@ static int decode_pce(AVCodecContext *avctx, MPEG4AudioConfig *m4ac,
*/
static int decode_ga_specific_config(AACDecContext *ac, AVCodecContext *avctx,
- GetBitContext *gb,
- int get_bit_alignment,
- MPEG4AudioConfig *m4ac,
- int channel_config)
+ GetBitContext *gb, int get_bit_alignment, MPEG4AudioConfig *m4ac, int channel_config)
{
+ if (m4ac->sbr > 0) return AVERROR_DECODER_NOT_FOUND;
int extension_flag, ret, ep_config, res_flags;
uint8_t layout_map[MAX_ELEM_ID*4][3];
@@ -961,8 +959,7 @@ static int decode_ga_specific_config(AACDecContext *ac, AVCodecContext *avctx,
static int decode_eld_specific_config(AACDecContext *ac, AVCodecContext *avctx,
- GetBitContext *gb,
- MPEG4AudioConfig *m4ac,
- int channel_config)
+ GetBitContext *gb, MPEG4AudioConfig *m4ac, int channel_config)
{
+ return AVERROR_DECODER_NOT_FOUND; // kill ELD support
int ret, ep_config, res_flags;
uint8_t layout_map[MAX_ELEM_ID*4][3];
@@ -1070,5 +1067,4 @@ static int decode_audio_specific_config_gb(AACDecContext *ac,
case AOT_AAC_LTP:
case AOT_ER_AAC_LC:
- case AOT_ER_AAC_LD:
if ((ret = decode_ga_specific_config(ac, avctx, gb, get_bit_alignment,
&oc->m4ac, m4ac->chan_config)) < 0)
@@ -1948,4 +1944,5 @@ static int decode_extension_payload(AACDecContext *ac, GetBitContext *gb, int cn
crc_flag++;
case EXT_SBR_DATA:
+ return res; // kill HE/SBR support
if (!che) {
av_log(ac->avctx, AV_LOG_ERROR, "SBR was found before the first channel element.\n");
@@ -2087,4 +2084,5 @@ static void spectral_to_sample(AACDecContext *ac, int samples)
}
if (ac->oc[1].m4ac.sbr > 0) {
+ exit(1); // kill HE/SBR support
ac->proc.sbr_apply(ac, che, type,
che->ch[0].output,
diff --git a/libavcodec/aacsbr_template.c b/libavcodec/aacsbr_template.c
index 31d2d844c4..b55f93752a 100644
--- a/libavcodec/aacsbr_template.c
+++ b/libavcodec/aacsbr_template.c
@@ -639,4 +639,5 @@ static int read_sbr_grid(AACDecContext *ac, SpectralBandReplication *sbr,
GetBitContext *gb, SBRData *ch_data)
{
+ exit(1); // kill SBR support
int i;
int bs_pointer = 0;

View file

@ -0,0 +1,26 @@
// just the signatures from the original file; all bodies/logic removed
#include <stdint.h>
#include "libavutil/common.h"
#include "libavutil/mathematics.h"
#include "libavutil/mem_internal.h"
#include "aacps.h"
#if USE_FIXED
#include "aacps_fixed_tablegen.h"
#else
#include "libavutil/internal.h"
#include "aacps_tablegen.h"
#endif /* USE_FIXED */
static void hybrid_analysis(PSDSPContext *dsp, INTFLOAT out[91][32][2],
INTFLOAT in[5][44][2], INTFLOAT L[2][38][64],
int is34, int len) {}
static void hybrid_synthesis(PSDSPContext *dsp, INTFLOAT out[2][38][64],
INTFLOAT in[91][32][2], int is34, int len) {}
static void decorrelation(PSContext *ps, INTFLOAT (*out)[32][2], const INTFLOAT (*s)[32][2], int is34) {}
int AAC_RENAME(ff_ps_apply)(PSContext *ps, INTFLOAT L[2][38][64], INTFLOAT R[2][38][64], int top) { return 0; }
av_cold void AAC_RENAME(ff_ps_init)(void) {}

View file

@ -0,0 +1,41 @@
// just the signatures from the original file; all bodies/logic removed
#define USE_FIXED 0
#include "aac.h"
#include "sbr.h"
#include "aacsbr.h"
#include "aacsbrdata.h"
#include "aacps.h"
#include "sbrdsp.h"
#include "libavutil/internal.h"
#include "libavutil/intfloat.h"
#include "libavutil/libm.h"
#include "libavutil/avassert.h"
#include "libavutil/mem_internal.h"
#include <stdint.h>
#include <float.h>
#include <math.h>
static void aacsbr_func_ptr_init(AACSBRContext *c);
static void make_bands(int16_t* bands, int start, int stop, int num_bands) {}
static void sbr_dequant(SpectralBandReplication *sbr, int id_aac) {}
static void sbr_hf_inverse_filter(SBRDSPContext *dsp,
float (*alpha0)[2], float (*alpha1)[2],
const float X_low[32][40][2], int k0) {}
static void sbr_chirp(SpectralBandReplication *sbr, SBRData *ch_data) {}
static void sbr_gain_calc(SpectralBandReplication *sbr,
SBRData *ch_data, const int e_a[2]) {}
static void sbr_hf_assemble(float Y1[38][64][2],
const float X_high[64][40][2],
SpectralBandReplication *sbr, SBRData *ch_data,
const int e_a[2]) {}
#include "aacsbr_template.c"

View file

@ -0,0 +1,45 @@
// just the signatures from the original file; all bodies/logic removed
#define USE_FIXED 1
#include "aac.h"
#include "sbr.h"
#include "aacsbr.h"
#include "aacsbrdata.h"
#include "aacps.h"
#include "sbrdsp.h"
#include "libavutil/internal.h"
#include "libavutil/libm.h"
#include "libavutil/avassert.h"
#include <stdint.h>
#include <float.h>
#include <math.h>
static void aacsbr_func_ptr_init(AACSBRContext *c);
static const int CONST_RECIP_LN2 = Q31(0.7);
static const int CONST_076923 = Q31(0.7);
static const int fixed_log_table[] = {Q31(0)};
static int fixed_log(int x) {return 1;}
static void make_bands(int16_t* bands, int start, int stop, int num_bands) {}
static void sbr_dequant(SpectralBandReplication *sbr, int id_aac) {}
static void sbr_hf_inverse_filter(SBRDSPContext *dsp,
int (*alpha0)[2], int (*alpha1)[2],
const int X_low[32][40][2], int k0) {}
static void sbr_chirp(SpectralBandReplication *sbr, SBRData *ch_data) {}
static void sbr_gain_calc(SpectralBandReplication *sbr,
SBRData *ch_data, const int e_a[2]) {}
static void sbr_hf_assemble(int Y1[38][64][2],
const int X_high[64][40][2],
SpectralBandReplication *sbr, SBRData *ch_data,
const int e_a[2]) {}
#include "aacsbr_template.c"

View file

@ -0,0 +1,16 @@
// just the signatures from the original file; all bodies/logic removed
#ifndef AVCODEC_AACSBRDATA_H
#define AVCODEC_AACSBRDATA_H
#include <stdint.h>
#include "libavutil/mem_internal.h"
#include "aac_defines.h"
static const int8_t sbr_offset[6][16] = {};
static const DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_ds)[320] = {};
static const DECLARE_ALIGNED(32, INTFLOAT, sbr_qmf_window_us)[640] = {};
#endif /* AVCODEC_AACSBRDATA_H */

24
scripts/docker/base/verchk.sh Executable file
View file

@ -0,0 +1,24 @@
#!/bin/bash
set -e
v=3.23
mkdir -p cver
rm -rf cver2
mkdir cver2
cd cver2
curl \
-Lo1 https://raw.githubusercontent.com/alpinelinux/aports/refs/heads/$v-stable/main/musl/APKBUILD \
-Lo2 https://raw.githubusercontent.com/alpinelinux/aports/refs/heads/$v-stable/main/python3/APKBUILD \
-Lo3 https://raw.githubusercontent.com/alpinelinux/aports/refs/heads/$v-stable/community/ffmpeg/APKBUILD \
;
zlib= ff=
cmp 1 ../cver/1 || zlib=1
cmp 2 ../cver/2 || zlib=1
cmp 3 ../cver/3 || ff=1
echo zlib=$zlib ff=$ff
[ $zlib ] && { make zlib; cp -pv 1 2 ../cver/; }
[ $ff ] && { make ff; cp -pv 3 ../cver/; }
rm -rf cver2

View file

@ -14,15 +14,29 @@ ised() {
tmv "$2"
}
# use custom ffmpeg if relevant
echo $1 | grep -qE 'ac|iv|dj' && (
cp -pv /z/packages/*.pub /etc/apk/keys/
cd /z/packages/$(cat /etc/apk/arch)
apk add ./ffmpeg-*.apk
cd /z/test-aac
for f in *.m4a; do ffmpeg -v 0 -i $f ${f%.*}.flac || true; done
ls -1 *.flac | tee /dev/stderr | tr '\n' ' ' | grep -qE '^(lc.flac *)?$' || {
echo ERROR: incorrect aac decoder subset
exit 1
}
)
rm -rf /z/packages /z/test-aac
# use zlib-ng if available
f=/z/base/zlib_ng-0.5.1-cp312-cp312-linux_$(cat /etc/apk/arch).whl
f=/z/whl/zlib_ng-0.5.1-cp312-cp312-linux_$(cat /etc/apk/arch).whl
[ "$1" != min ] && [ -e $f ] && {
apk add -t .bd !pyc py3-pip
rm -f /usr/lib/python3*/EXTERNALLY-MANAGED
pip install $f
apk del .bd
}
rm -rf /z/base
rm -rf /z/whl
# cleanup for flavors with python build steps (dj/iv)
rm -rf /var/cache/apk/* /root/.cache
@ -70,6 +84,11 @@ rm -rf \
/tmp/pe-* /z/copyparty-sfx.py \
ensurepip pydoc_data turtle.py turtledemo lib2to3
cd /usr/lib/python3.*/site-packages
rm -rf \
numpy/*/tests \
/usr/share/mime/packages/freedesktop.org.xml
cd /usr/lib/python3.*/site-packages/copyparty/
rm stolen/surrogateescape.py
iawk '/^[^ ]/{s=0}/^if not VENDORED:/{s=1}!s' qrkode.py

View file

@ -1,5 +1,7 @@
#!/bin/bash
set -e
self=$(cd -- "$(dirname "$BASH_SOURCE")"; pwd -P)
cd "$self"
[ $(id -u) -eq 0 ] && {
echo dont root
@ -78,6 +80,20 @@ filt=
}
[ $img ] && {
[ -e base/test-aac/lc.m4a ] || (
echo building aac smoketest
mkdir -p base/test-aac
cd base/test-aac
ffmpeg -nostdin -y -f lavfi -i sine -ac 2 -t 1 a.wav &&
fdkaac -m 3 -o lc.m4a a.wav &&
fdkaac -m 2 -p 5 -o he.m4a a.wav &&
fdkaac -m 1 -p 29 -o he2.m4a a.wav &&
fdkaac -m 3 -p 23 -o ld.m4a a.wav &&
fdkaac -m 3 -p 39 -o eld.m4a a.wav ||
echo "nevermind, failed to build test files, cannot verify aac decoding"
rm -f a.wav
)
fp=../../dist/copyparty-sfx.py
[ -e $fp ] || {
echo downloading copyparty-sfx.py ...
@ -96,7 +112,11 @@ filt=
# grab deps
rm -rf i err
mkdir i
tar -cC../.. dist/copyparty-sfx.py bin/mtag | tar -xvCi
tar -cC "$self/base" whl test-aac \
-C "$self/base/b" packages \
-C "$self/../.." bin/mtag \
-C dist copyparty-sfx.py \
| tar -xvCi
for i in $imgs; do
podman rm copyparty-$i || true # old manifest

View file

@ -23,6 +23,7 @@ v=$1; shift
printf '%s\n' "$v" | grep -qE '^[0-9\.]+$' || exit 1
grep -E "(${v//./, })" ../copyparty/__version__.py || exit 1
make -C docker/base
./make-sfx.sh nopk gz
../dist/copyparty-sfx.py --version >/dev/null

View file

@ -15,7 +15,7 @@ from copyparty.httpcli import HttpCli
from copyparty.u2idx import U2idx
from copyparty.up2k import Up2k
from tests import util as tu
from tests.util import Cfg
from tests.util import J2_ENV, Cfg
try:
from typing import Optional
@ -23,15 +23,16 @@ except:
pass
def hdr(query, uname):
h = "GET /%s HTTP/1.1\r\nPW: %s\r\nConnection: close\r\n\r\n"
return (h % (query, uname)).encode("utf-8")
def hdr(query, uname, extra=""):
h = "GET /%s HTTP/1.1\r\nPW: %s\r\nConnection: close\r\n%s\r\n"
return (h % (query, uname, extra)).encode("utf-8")
class TestDots(unittest.TestCase):
def __init__(self, *a, **ka):
super(TestDots, self).__init__(*a, **ka)
self.is_dut = True
self.j2_brw = None
def setUp(self):
self.conn: Optional[tu.VHttpConn] = None
@ -49,6 +50,13 @@ class TestDots(unittest.TestCase):
self.conn = None
self.conn = tu.VHttpConn(self.args, self.asrv, self.log, b"")
if not self.j2_brw:
zs = os.path.dirname(__file__)
with open("%s/../copyparty/web/browser.html" % (zs,), "rb") as f:
zs = f.read().decode("utf-8")
self.j2_brw = J2_ENV.from_string(zs)
self.conn.hsrv.j2["browser"] = self.j2_brw
def test_dots(self):
td = os.path.join(self.td, "vfs")
os.mkdir(td)
@ -150,8 +158,10 @@ class TestDots(unittest.TestCase):
os.chdir(td)
vcfg = []
for k in "dk dks dky fk fka dk,fk dks,fk".split():
vcfg += ["{0}:{0}:r.,u1:g,u2:c,{0}".format(k)]
zs = "dk dks=12 dky fk fka dk,fk dks=12:c,fk"
for k2 in zs.split():
k = k2.replace("=12", "").replace(":c,", ",")
vcfg += ["{0}:{0}:r.,u1:g,u2:c,{1}".format(k, k2)]
zs = "%s/s1/s2" % (k,)
os.makedirs(zs)
@ -220,6 +230,15 @@ class TestDots(unittest.TestCase):
zs = self.curl("dks/%s&ls" % (s1), "u2")[1]
self.assertIn('"s2/?k=', zs)
# parent key should not exist in response
self.assertNotIn(dk["dks"], zs)
# and not in html either
for ck in ("", "Cookie: js=y\r\n"):
zb = hdr("dks/%s" % (s1), "u2", ck)
zs = self.curl("", "", False, zb)[1]
self.assertNotIn(dk["dks"], zs)
self.assertIn('"s2/?k=', zs)
##
## dks thumbs
@ -366,7 +385,7 @@ class TestDots(unittest.TestCase):
zb = zs.encode("utf-8")
hdr = "POST /%s HTTP/1.1\r\nPW: %s\r\nConnection: close\r\nContent-Type: multipart/form-data; boundary=XD\r\nContent-Length: %d\r\n\r\n"
req = (hdr % (url, uname, len(zb))).encode("utf-8") + zb
h, b = self.curl("/" + url, uname, True, req)
h, b = self.curl("", "", True, req)
tar = tarfile.open(fileobj=io.BytesIO(b), mode="r|").getnames()
return " ".join(tar)