Compare commits

..

No commits in common. "hovudstraum" and "v1.20.13" have entirely different histories.

44 changed files with 64 additions and 348 deletions

View file

@ -120,7 +120,6 @@ built in Norway 🇳🇴 with contributions from [not-norway](https://github.com
* [packages](#packages) - the party might be closer than you think
* [arch package](#arch-package) - `pacman -S copyparty` (in [arch linux extra](https://archlinux.org/packages/extra/any/copyparty/))
* [fedora package](#fedora-package) - does not exist yet
* [gentoo ::guru package](#gentoo-guru-package) - `emerge www-servers/copyparty::guru` (in [::guru](https://wiki.gentoo.org/wiki/Project:GURU))
* [homebrew formulae](#homebrew-formulae) - `brew install copyparty ffmpeg`
* [nix package](#nix-package) - `nix profile install github:9001/copyparty`
* [nixos module](#nixos-module)
@ -184,7 +183,7 @@ enable thumbnails (images/audio/video), media indexing, and audio transcoding by
* **Alpine:** `apk add py3-pillow ffmpeg`
* **Debian:** `apt install --no-install-recommends python3-pil ffmpeg`
* **Fedora:** rpmfusion + `dnf install python3-pillow ffmpeg --allowerasing`
* **FreeBSD:** `pkg install py311-sqlite3 py311-pillow ffmpeg`
* **FreeBSD:** `pkg install py39-sqlite3 py39-pillow ffmpeg`
* **MacOS:** `port install py-Pillow ffmpeg`
* **MacOS** (alternative): `brew install pillow ffmpeg`
* **Windows:** `python -m pip install --user -U Pillow`
@ -608,12 +607,10 @@ and if you want to use config files instead of commandline args (good!) then her
hiding specific subfolders by mounting another volume on top of them
for example `-v /mnt::r -v /var/empty:web/certs:` (note: no permissions) mounts the server folder `/mnt` as the webroot, but another volume is mounted at `/web/certs` -- so visitors can only see the contents of `/mnt` and `/mnt/web` (at URLs `/` and `/web`), but not `/mnt/web/certs` because URL `/web/certs` is mapped to `/var/empty`
for example `-v /mnt::r -v /var/empty:web/certs:r` mounts the server folder `/mnt` as the webroot, but another volume is mounted at `/web/certs` -- so visitors can only see the contents of `/mnt` and `/mnt/web` (at URLs `/` and `/web`), but not `/mnt/web/certs` because URL `/web/certs` is mapped to `/var/empty`
the example config file right above this section may explain this better; the first volume `/` is mapped to `/srv` which means http://127.0.0.1:3923/music would try to read `/srv/music` on the server filesystem, but since there's another volume at `/music` mapped to `/mnt/music` then it'll go to `/mnt/music` instead
so, to shadow a file/folder, define a volume but leave out the `accs:` section
> this also works for single files, because files can also be volumes
@ -2588,23 +2585,6 @@ after installing, start either the system service or the user service and naviga
does not exist yet; there are rumours that it is being packaged! keep an eye on this space...
## gentoo ::guru package
`emerge www-servers/copyparty::guru` (in [::guru](https://wiki.gentoo.org/wiki/Project:GURU))
but first enable the `::guru` repo;
```bash
emerge -an app-eselect/eselect-repository
eselect repository enable guru
emerge --sync guru
```
to start the service as a user:
* OpenRC: `rc-service -U copyparty start && rc-update -U add copyparty default`
* systemd: [todo]
## homebrew formulae
`brew install copyparty ffmpeg` -- https://formulae.brew.sh/formula/copyparty
@ -2749,12 +2729,6 @@ services.copyparty = {
};
# you may increase the open file limit for the process
openFilesLimit = 8192;
# override the package used by the module to add dependencies, e.g. for hooks
package = pkgs.copyparty.override {
# provides exiftool for bin/hooks/image-noexif.py
extraPackages = [ pkgs.exiftool ];
};
};
```

View file

@ -1,36 +0,0 @@
# /!\ Warning: be careful, as webdav clients often generate a large number of 404 requets.
# In your `jail.local`, add:
# [copyparty]
# enabled = true
# logtimezone = UTC
# logpath = /path/to/log/file # or keep the default value if you're using systemd
# Create the `copyparty.conf` file in `filter.d` with the following:
# [Definition]
# failregex = ^ <ADDR>$
# ignoreregex =
# datepattern = ^fail2ban: %%Y-%%m-%%dT%%H:%%M:%%S
# First check `--dont-ban`, and if it doesn't match, log the line to be intercepted by fail2ban.
from datetime import datetime, UTC
def main(cli, vn="", rem=""):
now = datetime.now(UTC).isoformat()[:19]
msg = "\nfail2ban: %s %s"
if not vn and not rem:
# got called by --xban
cli["log"](msg % (now, cli["ip"]), 3)
return {"rc": 0}
cond = cli.args.dont_ban
if (
cond == "any"
or (cond == "auth" and cli.uname != "*")
or (cond == "aa" and cli.avol)
or (cond == "av" and cli.can_admin)
or (cond == "rw" and cli.can_read and cli.can_write)
):
return ""
cli.log(msg % (now, cli.ip), 3)
return ""

View file

@ -22,11 +22,10 @@ each plugin must define a `main()` which takes 3 arguments;
* [redirect.py](redirect.py) sends an HTTP 301 or 302, redirecting the client to another page/file
* [randpic.py](randpic.py) redirects `/foo/bar/randpic.jpg` to a random pic in `/foo/bar/`
* [sorry.py](sorry.py) replies with a custom message instead of the usual 404
* [sorry.py](answer.py) replies with a custom message instead of the usual 404
* [nooo.py](nooo.py) replies with an endless noooooooooooooo
* [never404.py](never404.py) 100% guarantee that 404 will never be a thing again as it automatically creates dummy files whenever necessary
* [caching-proxy.py](caching-proxy.py) transforms copyparty into a squid/varnish knockoff
* [404-to-fail2ban.py](404-to-fail2ban.py) creates 404 logs for fail2ban
## on403

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.13"
pkgver="1.20.12"
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=("b2af9250f7ef97a5df26df412ee082c6d2be0f0cd31d579b4fbb6aa2f3e5c271")
sha256sums=("3acb98e9c577245517db92e77519caeac8a3e382dbc8704ec4a8701c7d58ba76")
build() {
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"

View file

@ -2,7 +2,7 @@
pkgname=copyparty
pkgver=1.20.13
pkgver=1.20.12
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=("b2af9250f7ef97a5df26df412ee082c6d2be0f0cd31d579b4fbb6aa2f3e5c271")
sha256sums=("3acb98e9c577245517db92e77519caeac8a3e382dbc8704ec4a8701c7d58ba76")
build() {
cd "${srcdir}/${pkgname}-${pkgver}/copyparty/web"

View file

@ -1,5 +1,5 @@
{
"url": "https://github.com/9001/copyparty/releases/download/v1.20.13/copyparty-1.20.13.tar.gz",
"version": "1.20.13",
"hash": "sha256-sq+SUPfvl6XfJt9BLuCCxtK+DwzTHVebT7tqovPlwnE="
"url": "https://github.com/9001/copyparty/releases/download/v1.20.12/copyparty-1.20.12.tar.gz",
"version": "1.20.12",
"hash": "sha256-OsuY6cV3JFUX25LndRnK6sij44LbyHBOxKhwHH1YunY="
}

View file

@ -38,7 +38,5 @@
accs:
rw: * # everyone gets read-write access, but
rwmda: ed # the user "ed" gets read-write-move-delete-admin
flags:
e2ds # enable filesystem-scanning for this volume only
# uid: 1000 # If you're running as root, you can change the owner of this volume here
# gid: 1000 # If you're running as root, you can change the group of this volume here

View file

@ -49,5 +49,3 @@
accs:
rw: * # everyone gets read-write access, but
rwmda: ed # the user "ed" gets read-write-move-delete-admin
flags:
e2ds # enable filesystem-scanning for this volume only

View file

@ -44,14 +44,6 @@ ANYWIN = WINDOWS or sys.platform in ["msys", "cygwin"]
MACOS = platform.system() == "Darwin"
FREEBSD = platform.system() == "FreeBSD"
OPENBSD = platform.system() == "OpenBSD"
ANYBSD = FREEBSD or OPENBSD
UNIX = MACOS or ANYBSD
GRAAL = platform.python_implementation() == "GraalVM"
EXE = bool(getattr(sys, "frozen", False))

View file

@ -1520,7 +1520,6 @@ def add_smb(ap):
ap2.add_argument("--smb-nwa-1", action="store_true", help="truncate directory listings to 64kB (~400 files); avoids impacket-0.11 bug, fixes impacket-0.12 performance")
ap2.add_argument("--smb-nwa-2", action="store_true", help="disable impacket workaround for filecopy globs")
ap2.add_argument("--smba", action="store_true", help="small performance boost: disable per-account permissions, enables account coalescing instead (if one user has write/delete-access, then everyone does)")
ap2.add_argument("--smb6", action="store_true", help="enable IPv6")
ap2.add_argument("--smbv", action="store_true", help="verbose")
ap2.add_argument("--smbvv", action="store_true", help="verboser")
ap2.add_argument("--smbvvv", action="store_true", help="verbosest")
@ -1869,10 +1868,8 @@ def add_ui(ap, retry: int):
ap2.add_argument("--gsel", action="store_true", help="select files in grid by ctrl-click (volflag=gsel)")
ap2.add_argument("--localtime", action="store_true", help="default to local timezone instead of UTC")
ap2.add_argument("--ui-filesz", metavar="FMT", type=u, default="1", help="default filesize format; one of these: 0, 1, 2, 2c, 3, 3c, 4, 4c, 5, 5c, fuzzy (see UI)")
ap2.add_argument("--gauto", metavar="PERCENT", type=int, default=0, help="switch to gridview if more than \033[33mPERCENT\033[0m of files are pics/vids; 0=disabled")
ap2.add_argument("--rcm", metavar="TXT", default="yy", help="rightclick-menu; two yes/no options: 1st y/n is enable-custom-menu, 2nd y/n is enable-double")
ap2.add_argument("--lang", metavar="LANG", type=u, default="eng", help="language, for example \033[32meng\033[0m / \033[32mnor\033[0m / ...")
ap2.add_argument("--glang", action="store_true", help="guess the browser's default language, otherwise fall back to \033[33m--lang\033[0m")
ap2.add_argument("--theme", metavar="NUM", type=int, default=0, help="default theme to use (0..%d)" % (THEMES - 1,))
ap2.add_argument("--themes", metavar="NUM", type=int, default=THEMES, help="number of themes installed")
ap2.add_argument("--au-vol", metavar="0-100", type=int, default=50, choices=range(0, 101), help="default audio/video volume percent")

View file

@ -3258,7 +3258,6 @@ class AuthSrv(object):
"idxh": int(self.args.ih),
"dutc": not self.args.localtime,
"dfszf": self.args.ui_filesz.strip("-"),
"dgauto": self.args.gauto,
"themes": self.args.themes,
"turbolvl": self.args.turbo,
"nosubtle": self.args.nosubtle,
@ -3274,7 +3273,7 @@ class AuthSrv(object):
for zs in zs.split():
if vf.get(zs):
js_htm[zs] = 1
zs = "glang notooltips"
zs = "notooltips"
for zs in zs.split():
if getattr(self.args, zs, False):
js_htm[zs] = 1

View file

@ -7,7 +7,7 @@ import os
import re
import time
from .__init__ import ANYWIN, FREEBSD, MACOS, UNIX
from .__init__ import ANYWIN, MACOS
from .authsrv import AXS, VFS, AuthSrv
from .bos import bos
from .util import chkcmd, json_hesc, min_ex, undot
@ -88,7 +88,7 @@ class Fstab(object):
def _from_sp_mount(self) -> dict[str, str]:
sptn = r"^.*? on (.*) type ([^ ]+) \(.*"
if MACOS or FREEBSD:
if MACOS:
sptn = r"^.*? on (.*) \(([^ ]+), .*"
ptn = re.compile(sptn)
@ -118,7 +118,7 @@ class Fstab(object):
def build_tab(self) -> None:
self.log("inspecting mtab for changes")
dtab = self._from_sp_mount() if UNIX else self._from_proc()
dtab = self._from_sp_mount() if MACOS else self._from_proc()
# keep empirically-correct values if mounttab unchanged
srctab = str(sorted(dtab.items()))
@ -130,7 +130,7 @@ class Fstab(object):
try:
fuses = [mp for mp, fs in dtab.items() if fs == "fuseblk"]
if not fuses or UNIX:
if not fuses or MACOS:
raise Exception()
try:
so, _ = chkcmd(["lsblk", "-nrfo", "FSTYPE,MOUNTPOINT"]) # centos6

View file

@ -154,7 +154,7 @@ _ = (argparse, threading)
USED4SEC = {"usedforsecurity": False} if sys.version_info > (3, 9) else {}
ALL_COOKIES = "cplng cppwd cppws dots idxh js k304 no304".split()
ALL_COOKIES = "k304 no304 js idxh dots cppwd cppws".split()
BADXFF = " due to dangerous misconfiguration (the http-header specified by --xff-hdr was received from an untrusted reverse-proxy)"
BADXFF2 = ". Some copyparty features are now disabled as a safety measure.\n\n\n"
@ -1800,11 +1800,7 @@ class HttpCli(object):
topdir = {"vp": "", "st": st}
fgen: Iterable[dict[str, Any]] = []
if stat.S_ISDIR(st.st_mode):
depth = self.headers.get("depth", "infinity").lower()
else:
depth = "0"
if depth == "infinity":
# allow depth:0 from unmapped root, but require read-axs otherwise
if not self.can_read and (self.vpath or self.asrv.vfs.realpath):
@ -1813,6 +1809,12 @@ class HttpCli(object):
self.log(t, 3)
raise Pebkac(401, t)
if not stat.S_ISDIR(topdir["st"].st_mode):
t = "depth:infinity can only be used on folders; %r is 0o%o"
t = t % ("/" + self.vpath, topdir["st"])
self.log(t, 3)
raise Pebkac(400, t)
if not self.args.dav_inf:
self.log("client wants --dav-inf", 3)
zb = b'<?xml version="1.0" encoding="utf-8"?>\n<D:error xmlns:D="DAV:"><D:propfind-finite-depth/></D:error>'
@ -1833,7 +1835,7 @@ class HttpCli(object):
wrap=False,
)
elif depth == "0":
elif depth == "0" or not stat.S_ISDIR(st.st_mode):
if depth == "0" and not self.vpath and not vn.realpath:
# rootless server; give dummy listing
self.can_read = True
@ -3719,12 +3721,12 @@ class HttpCli(object):
fdir = fdir_base
fname = sanitize_fn(p_file or "")
abspath = os.path.join(fdir, fname)
suffix = "-%.6f-%s" % (time.time(), dip)
if p_file and not nullwrite:
if rnd:
fname = rand_name(fdir, fname, rnd)
abspath = os.path.join(fdir, fname)
open_args = {"fdir": fdir, "suffix": suffix, "vf": vfs.flags}
if "replace" in self.uparam or "replace" in self.headers:
@ -3742,7 +3744,7 @@ class HttpCli(object):
tnam = fname = os.devnull
fdir = abspath = ""
if xbu and abspath:
if xbu:
at = time.time() - lifetime
hr = runhook(
self.log,
@ -3790,7 +3792,7 @@ class HttpCli(object):
else:
open_args["fdir"] = fdir
if abspath:
if p_file and not nullwrite:
bos.makedirs(fdir, vf=vfs.flags)
# reserve destination filename
@ -3828,14 +3830,6 @@ class HttpCli(object):
finally:
f.close()
self.conn.nbyte += sz
if not abspath:
files.append(
(sz, sha_hex, sha_b64, p_file or "(discarded)", fname, "")
)
tabspath = ""
continue
if lim:
lim.nup(self.ip)
lim.bup(self.ip, sz)
@ -3846,12 +3840,15 @@ class HttpCli(object):
lim.chk_bup(self.ip)
lim.chk_nup(self.ip)
except:
if not nullwrite:
wunlink(self.log, tabspath, vfs.flags)
wunlink(self.log, abspath, vfs.flags)
fname = os.devnull
raise
if not nullwrite:
atomic_move(self.log, tabspath, abspath, vfs.flags)
tabspath = ""
at = time.time() - lifetime
@ -3906,7 +3903,9 @@ class HttpCli(object):
abspath = ap2
sz = bos.path.getsize(abspath)
files.append((sz, sha_hex, sha_b64, p_file, fname, abspath))
files.append(
(sz, sha_hex, sha_b64, p_file or "(discarded)", fname, abspath)
)
dbv, vrem = vfs.get_dbv(rem)
self.conn.hsrv.broker.say(
"up2k.hash_file",
@ -3920,6 +3919,7 @@ class HttpCli(object):
self.uname,
True,
)
self.conn.nbyte += sz
except Pebkac:
self.parser.drop()

View file

@ -22,7 +22,7 @@ from .__init__ import TYPE_CHECKING, EnvParams
from .authsrv import AuthSrv # typechk
from .httpcli import HttpCli
from .u2idx import U2idx
from .util import HMaccas, NetMap, min_ex, shut_socket
from .util import HMaccas, NetMap, shut_socket
if True: # pylint: disable=using-constant-test
from typing import Optional, Pattern, Union
@ -194,12 +194,12 @@ class HttpConn(object):
except Exception as ex:
em = str(ex)
if "ALERT_" in em:
self.log("client refused our TLS cert or config: " + em, c=6)
if "ALERT_CERTIFICATE_UNKNOWN" in em:
# android-chrome keeps doing this
pass
else:
t = "https-handshake failed, probably due to client:\n"
self.log(t + min_ex(), c=5)
self.log("handshake\033[0m " + em, c=5)
return

View file

@ -89,15 +89,13 @@ class SMB(object):
smbserver.isInFileJail = self._is_in_file_jail
self._disarm()
zs = " " if self.args.smb6 else ":"
ip = next((x for x in self.args.smb_i if zs not in x), None)
ip = next((x for x in self.args.smb_i if ":" not in x), None)
if not ip:
self.log("smb", "IPv6 not enabled with --smb6; listening on 0.0.0.0", 3)
self.log("smb", "IPv6 not supported for SMB; listening on 0.0.0.0", 3)
ip = "0.0.0.0"
port = int(self.args.smb_port)
kw = {"ipv6": True} if ":" in ip else {}
srv = smbserver.SimpleSMBServer(listenAddress=ip, listenPort=port, **kw)
srv = smbserver.SimpleSMBServer(listenAddress=ip, listenPort=port)
try:
if self.accs:
srv.setAuthCallback(self._auth_cb)
@ -123,7 +121,6 @@ class SMB(object):
self.srv = srv
self.stop = srv.stop
ip = "[%s]" % (ip,) if kw else ip
self.log("smb", "listening @ {}:{}".format(ip, port))
def nlog(self, msg: str, c: Union[int, str] = 0) -> None:

View file

@ -7,7 +7,7 @@ import socket
import sys
import time
from .__init__ import ANYWIN, OPENBSD, PY2, TYPE_CHECKING, UNIX, unicode
from .__init__ import ANYWIN, PY2, TYPE_CHECKING, unicode
from .cert import gencert
from .qrkode import QrCode, qr2png, qr2svg, qr2txt, qrgen
from .util import (
@ -510,13 +510,6 @@ class TcpSrv(object):
return eps
def _extdevs_nix(self) -> Generator[str, None, None]:
if UNIX:
so, _ = chkcmd(["netstat", "-nrf", "inet"])
for ln in so.split("\n"):
if not ln.startswith("default"):
continue
yield ln.split()[7] if OPENBSD else ln.split()[3]
return
with open("/proc/net/route", "rb") as f:
next(f)
for ln in f:

View file

@ -491,12 +491,13 @@ font woff woff2 otf ttf
for v in vs.strip().split():
MIMES[v] = "{}/{}".format(k, v)
for ln in """text md=plain js=javascript ass=plain ssa=plain txt=plain
for ln in """text md=plain txt=plain js=javascript
application 7z=x-7z-compressed tar=x-tar bz2=x-bzip2 gz=gzip rar=x-rar-compressed zst=zstd xz=x-xz lz=lzip cpio=x-cpio
application msi=x-ms-installer cab=vnd.ms-cab-compressed rpm=x-rpm crx=x-chrome-extension
application epub=epub+zip mobi=x-mobipocket-ebook lit=x-ms-reader rss=rss+xml atom=atom+xml torrent=x-bittorrent
application p7s=pkcs7-signature dcm=dicom shx=vnd.shx shp=vnd.shp dbf=x-dbf gml=gml+xml gpx=gpx+xml amf=x-amf
application swf=x-shockwave-flash m3u=vnd.apple.mpegurl db3=vnd.sqlite3 sqlite=vnd.sqlite3
text ass=plain ssa=plain
image jpg=jpeg xpm=x-xpixmap psd=vnd.adobe.photoshop jpf=jpx tif=tiff ico=x-icon djvu=vnd.djvu
image heics=heic-sequence heifs=heif-sequence hdr=vnd.radiance svg=svg+xml
image arw=x-sony-arw cr2=x-canon-cr2 crw=x-canon-crw dcr=x-kodak-dcr dng=x-adobe-dng erf=x-epson-erf
@ -1501,7 +1502,8 @@ class Garda(object):
return 0, ip
if ":" in ip:
ip = ipnorm(ip)
# assume /64 clients; drop 4 groups
ip = IPv6Address(ip).exploded[:-20]
if prev and self.uniq:
if self.prev.get(ip) == prev:
@ -2444,8 +2446,8 @@ def odfusion(
def ipnorm(ip: str) -> str:
if ":" in ip:
# assume /56 clients; drop final 72 bits
return str(IPv6Network(ip + "/56", strict=False).network_address)
# assume /64 clients; drop 4 groups
return IPv6Address(ip).exploded[:-20]
return ip

View file

@ -2,7 +2,7 @@
var J_BRW = 1;
if (window.dgauto === undefined)
if (window.rw_edit === undefined)
alert('FATAL ERROR: receiving stale data from the server; this may be due to a broken reverse-proxy (stuck cache). Try restarting copyparty and press CTRL-SHIFT-R in the browser');
var XHR = XMLHttpRequest;
@ -228,7 +228,6 @@ if (1)
"cl_hpick": "tap on column headers to hide in the table below",
"cl_hcancel": "column hiding aborted",
"cl_rcm": "right-click menu",
"cl_gauto": "autogrid",
"ct_grid": '田 the grid',
"ct_ttips": '◔ ◡ ◔"> tooltips',
@ -283,8 +282,6 @@ if (1)
"tt_dynt": "autogrow as tree expands",
"tt_wrap": "word wrap",
"tt_hover": "reveal overflowing lines on hover$N( breaks scrolling unless mouse $N&nbsp; cursor is in the left gutter )",
"tt_gauto": "display as grid or list depending on folder contents",
"tt_gathr": "use grid if this percentage of files are pics/vids",
"ml_pmode": "at end of folder...",
"ml_btns": "cmds",
@ -716,54 +713,6 @@ var L = Ls[lang] || Ls.eng, LANGS = [];
for (var a = 0; a < LANGN.length; a++)
LANGS.push(LANGN[a][0]);
if (window.glang && navigator.languages && !/\bcplng=/.test(document.cookie))
(function() {
var lmap = [
["eng", /^en/i],
["nor", /^n[ob]/i],
["chi", /^zh-cn/i],
["cze", /^cs/i],
["deu", /^de/i],
["epo", /^eo/i],
["fin", /^fi/i],
["fra", /^fr/i],
["grc", /^el/i],
["hun", /^hu/i],
["ita", /^it/i],
["jpn", /^ja/i],
["kor", /^ko/i],
["nld", /^nl/i],
["nno", /^nn/i],
["pol", /^pl/i],
["por", /^pt/i],
["rus", /^ru/i],
["spa", /^es/i],
["swe", /^sv/i],
["tur", /^tr/i],
["ukr", /^uk/i],
["vie", /^vi/i],
];
for (var a = 0; a < navigator.languages.length; a++) {
for (var b = 0; b < lmap.length; b++) {
var n = lmap[b][0];
if (!lmap[b][1].test(navigator.languages[a]) || !has(LANGS, n))
continue;
if (Ls[n]) {
lang = n;
L = Ls[n];
return;
}
if (window.stop)
window.stop();
document.body.innerHTML = 'Loading ' + n;
setck("cplng=" + n, location.reload.bind(location));
crashed = true;
throw 1;
}
}
})();
function langtest() {
var n = LANGS.length - 1;
@ -772,9 +721,7 @@ function langtest() {
}
function langtest2() {
for (var a = 0; a < LANGS.length; a++) {
if (!Ls[LANGS[a]]) continue;
for (var b = a + 1; b < LANGS.length; b++) {
if (!Ls[LANGS[b]]) continue;
var i1 = Object.keys(Ls[LANGS[a]]).length > Object.keys(Ls[LANGS[b]]).length ? a : b,
i2 = i1 == a ? b : a,
t1 = Ls[LANGS[i1]],
@ -788,7 +735,6 @@ for (var a = 0; a < LANGS.length; a++) {
}
}
}
langtest2();
@ -990,13 +936,6 @@ ebi('op_cfg').innerHTML = (
' </div>\n' +
'</div>\n' +
'<div>\n' +
' <h3>' + L.cl_gauto + '</h3>\n' +
' <div>\n' +
' <a id="gauto" class="tgl btn" href="#" tt="' + L.tt_gauto + '">' + L.enable + '</a>\n' +
' <input type="text" id="ga_thresh" value="" ' + NOAC + ' style="width:1.5em" tt="' + L.tt_gathr + '" />' +
' </div>\n' +
'</div>\n' +
'<div>\n' +
' <h3>' + L.cl_hfsz + '</h3>\n' +
' <div><select id="fszfmt">\n' +
' <option value="0">0 ┃ 1234567</option>\n' +
@ -1216,7 +1155,9 @@ onresize100.add(read_sbw, true);
function check_image_support(format, uri) {
var cached = window['have_' + format] = sread('have_' + format);
var cached
= window['have_' + format]
= sread('have_' + format);
if (cached !== null)
return;
@ -1778,9 +1719,7 @@ function MPlayer() {
if (!tid || tid.indexOf('af-') !== 0)
continue;
tid = tid.slice(1);
if (r.tracks[tid])
order.push(tid);
order.push(tid.slice(1));
}
r.order = order;
r.shuffle();
@ -5618,16 +5557,6 @@ var thegrid = (function () {
r.setvis();
};
r.autogrid = function (res) {
var ni = 0;
var nf = res.files.length;
for (var a = 0; a < nf; a++)
if (img_re.test('.' + res.files[a].ext))
ni++;
if (nf)
thegrid.en = 100 * ni / nf >= r.gathr;
};
function setln(v) {
if (v) {
r.ln += v;
@ -6015,17 +5944,6 @@ var thegrid = (function () {
pbar.onresize();
vbar.onresize();
});
bcfg_bind(r, 'gaen', 'gauto', !!dgauto, function(v) {
if (r.en && sread("griden") != 1) {
r.en = false;
r.setvis(true);
}
});
ebi('ga_thresh').value = r.gathr = icfg_get('ga_thresh', dgauto || 70);
ebi('ga_thresh').oninput = function (e) {
var n = parseInt(this.value);
swrite('ga_thresh', r.gathr = (isNum(n) ? n : 0) || 70);
};
ebi('wtgrid').onclick = ebi('griden').onclick;
return r;
@ -7738,9 +7656,6 @@ var treectl = (function () {
}
}
if (thegrid.gaen && sread('griden') != 1)
thegrid.autogrid(res);
if (url) setTimeout(asdf, 1); else asdf();
}

View file

@ -221,7 +221,6 @@ Ls.chi = {
"cl_hpick": "在下方文件列表中点击某列表头即可从表中隐去该列",
"cl_hcancel": "列隐藏操作已中止",
"cl_rcm": "右键菜单",
"cl_gauto": "自动网格", //m
"ct_grid": '田 网格',
"ct_ttips": '◔ ◡ ◔"> 提示',
@ -276,8 +275,6 @@ Ls.chi = {
"tt_dynt": "自动随着目录树展开而变宽",
"tt_wrap": "自动换行",
"tt_hover": "悬停时完整显示出写不下的文字$N启用后鼠标光标只有$N&nbsp; 位于左边线上才滚得动)",
"tt_gauto": "根据文件夹内容以网格或列表显示", //m
"tt_gathr": "当此比例的文件为图片/视频时使用网格", //m
"ml_pmode": "文件夹播完后",
"ml_btns": "命令",

View file

@ -225,7 +225,6 @@ Ls.cze = {
"cl_hpick": "klepněte na záhlaví sloupců pro skrytí v tabulce níže",
"cl_hcancel": "skrývání sloupců zrušeno",
"cl_rcm": "kontextová nabídka", //m
"cl_gauto": "auto mřížka", //m
"ct_grid": '田 mřížka',
"ct_ttips": '◔ ◡ ◔"> nápovědy',
@ -280,8 +279,6 @@ Ls.cze = {
"tt_dynt": "automaticky rozrůstat jak se strom rozšiřuje",
"tt_wrap": "zalomení řádků",
"tt_hover": "odhalit přetékající řádky při najetí$N( ruší posun pokud kurzor myši $N&nbsp; není v levém okraji )",
"tt_gauto": "zobrazit jako mřížku nebo seznam podle obsahu složky", //m
"tt_gathr": "použít mřížku, pokud toto procento souborů tvoří obrázky/videa", //m
"ml_pmode": "na konci složky...",
"ml_btns": "příkazy",

View file

@ -221,7 +221,6 @@ Ls.deu = {
"cl_hpick": "zum Verstecken, tippe auf Spaltenüberschriften in der Tabelle unten",
"cl_hcancel": "Spaltenbearbeitung abgebrochen",
"cl_rcm": "Rechtsklick-Menü",
"cl_gauto": "auto-raster", //m
"ct_grid": '田 Das Raster&trade;',
"ct_ttips": '◔ ◡ ◔"> Tooltips',
@ -276,8 +275,6 @@ Ls.deu = {
"tt_dynt": "autom. wachsen wenn Baum wächst",
"tt_wrap": "Zeilenumbruch",
"tt_hover": "Beim Hovern überlange Zeilen anzeigen$N(Scrollen funktioniert nicht ausser $N&nbsp; Cursor ist im linken Gutter)",
"tt_gauto": "je nach ordnerinhalt als raster oder liste anzeigen", //m
"tt_gathr": "raster verwenden, wenn dieser prozentsatz der dateien bilder/videos sind", //m
"ml_pmode": "am Ende des Ordners...",
"ml_btns": "cmds",

View file

@ -221,7 +221,6 @@ Ls.epo = {
"cl_hpick": "alklaki la kapojn de kolumnoj por kasi en la suban tabelon",
"cl_hcancel": "kaŝado de kolumno nuligita",
"cl_rcm": "dekstra-klaka menuo",
"cl_gauto": "aŭto田",
"ct_grid": '田 krado',
"ct_ttips": '◔ ◡ ◔"> ŝpruchelpiloj',
@ -276,8 +275,6 @@ Ls.epo = {
"tt_dynt": "aŭtomate pligrandigi panelon",
"tt_wrap": "linifaldo",
"tt_hover": "montri kompletajn nomojn sur musumo$N( paneas rulumadon, se la kursoro de muso $N&nbsp; ne estas en la maldekstra malplenaĵo )",
"tt_gauto": "montri kiel krado aŭ listo laŭ dosieruja enhavo",
"tt_gathr": "uzi kradon se ĉi tiu elcento da dosieroj estas bildoj/filmetoj",
"ml_pmode": "je la fino de dosierujo...",
"ml_btns": "komandoj",

View file

@ -221,7 +221,6 @@ Ls.fin = {
"cl_hpick": "napauta sarakeotsikoita piilottaaksesi alla olevassa taulukossa",
"cl_hcancel": "sarakkeiden piilotus peruttu",
"cl_rcm": "hiiren pikavalikko",
"cl_gauto": "auto田", //m
"ct_grid": '田 kuvanäkymä',
"ct_ttips": '◔ ◡ ◔"> vihjelaatikot',
@ -276,8 +275,6 @@ Ls.fin = {
"tt_dynt": "kasvata automaattisesti hakemistosyvyyden kasvaessa",
"tt_wrap": "rivitys",
"tt_hover": "paljasta ylivuotavat rivit leijutettaessa$N( rikkoo vierityksen ellei hiiri $N&nbsp; ole vasemmassa marginaalissa )",
"tt_gauto": "näytä ruudukkona tai listana kansion sisällön mukaan", //m
"tt_gathr": "käytä ruudukkoa jos tämä prosentti tiedostoista on kuvia/videoita", //m
"ml_pmode": "hakemiston lopussa...",
"ml_btns": "komennot",

View file

@ -221,7 +221,6 @@ Ls.fra = {
"cl_hpick": "cliquez sur les en-têtes de colonnes pour les masquer dans le tableau ci-dessous",
"cl_hcancel": "masquage des colonnes annulé",
"cl_rcm": "menu contextuel", //m
"cl_gauto": "auto-grille", //m
"ct_grid": '田 grille',
"ct_ttips": '◔ ◡ ◔"> infobulles',
@ -276,8 +275,6 @@ Ls.fra = {
"tt_dynt": "croissance automatique à mesure que l'arborescence s'étend",
"tt_wrap": "retour à la ligne",
"tt_hover": "révéler les lignes débordantes au survol$N( interrompt le défilement à moins que le curseur de la souris ne soit dans la gouttière gauche )",
"tt_gauto": "afficher en grille ou liste selon le contenu du dossier", //m
"tt_gathr": "utiliser la grille si ce pourcentage de fichiers sont des images/vidéos", //m
"ml_pmode": "à la fin du dossier…",
"ml_btns": "cmds",

View file

@ -221,7 +221,6 @@ Ls.grc = {
"cl_hpick": "πάτησε στις κεφαλίδες στηλών για να τις κρύψεις στον πίνακα παρακάτω",
"cl_hcancel": "η απόκρυψη στηλών ακυρώθηκε",
"cl_rcm": "μενού δεξιού κλικ", //m
"cl_gauto": "αυτόματο田", //m
"ct_grid": '田 το πλέγμα',
"ct_ttips": '◔ ◡ ◔"> συμβουλές εργαλείων',
@ -276,8 +275,6 @@ Ls.grc = {
"tt_dynt": "αυτόματη επέκταση καθώς επεκτείνεται το δέντρο διαδρομών",
"tt_wrap": "αναδίπλωση λέξεων",
"tt_hover": "αποκάλυψη των γραμμών που ξεπερνούν το πλάτος με το ποντίκι πάνω τους$N( σπάει το scroll εκτός αν το ποντίκι $N&nbsp; είναι στην αριστερή στήλη )",
"tt_gauto": "εμφάνιση ως πλέγμα ή λίστα ανάλογα με τα περιεχόμενα του φακέλου", //m
"tt_gathr": "χρήση πλέγματος αν αυτό το ποσοστό αρχείων είναι εικόνες/βίντεο", //m
"ml_pmode": "στο τέλος του φακέλου...",
"ml_btns": "εντολές",

View file

@ -222,7 +222,6 @@ Ls.hun = {
"cl_hpick": 'kattints az oszlopfejlécre az elrejtéshez',
"cl_hcancel": 'elrejtés megszakítva',
"cl_rcm": 'jobb-klikkes menü',
"cl_gauto": "auto田", //m
"ct_grid": '田 rács nézet',
"ct_ttips": '◔ ◡ ◔"> segítő szövegek',
@ -277,8 +276,6 @@ Ls.hun = {
"tt_dynt": 'automatikus méretezés nyitáskor',
"tt_wrap": 'sortörés',
"tt_hover": 'túl hosszú sorok mutatása rámutatáskor',
"tt_gauto": "megjelenítés rácsban vagy listában a mappa tartalmától függően", //m
"tt_gathr": "rács használata, ha a fájlok ezen százaléka kép/videó", //m
"ml_pmode": 'mappa végén...',
"ml_btns": 'gombok',

View file

@ -221,7 +221,6 @@ Ls.ita = {
"cl_hpick": "tocca le intestazioni delle colonne per nascondere nella tabella sottostante",
"cl_hcancel": "nascondere colonne annullato",
"cl_rcm": "menu contestuale", //m
"cl_gauto": "auto田", //m
"ct_grid": '田 griglia',
"ct_ttips": '◔ ◡ ◔"> tooltip',
@ -276,8 +275,6 @@ Ls.ita = {
"tt_dynt": "crescita automatica mentre l'albero si espande",
"tt_wrap": "a capo parola",
"tt_hover": "rivela righe che traboccano al passaggio del mouse$N( interrompe lo scorrimento a meno che il cursore $N&nbsp; del mouse non sia nella grondaia sinistra )",
"tt_gauto": "mostra come griglia o lista in base al contenuto della cartella", //m
"tt_gathr": "usa la griglia se questa percentuale di file sono immagini/video", //m
"ml_pmode": "alla fine della cartella...",
"ml_btns": "comandi",

View file

@ -221,7 +221,6 @@ Ls.jpn = {
"cl_hpick": "下の表で非表示にするには列ヘッダーをタップします",
"cl_hcancel": "列の非表示を解除",
"cl_rcm": "右クリックメニュー",
"cl_gauto": "自動グリッド", //m
"ct_grid": '田 グリッド',
"ct_ttips": '◔ ◡ ◔"> ツールチップ',
@ -276,8 +275,6 @@ Ls.jpn = {
"tt_dynt": "ツリーが拡大するにつれて自動的に増加",
"tt_wrap": "単語の折り返し",
"tt_hover": "ホバーすると溢れた線を表示する$N( マウスを押さない限りスクロールが中断されます $N&nbsp; カーソルは左余白です )",
"tt_gauto": "フォルダー内容に応じてグリッドまたはリスト表示", //m
"tt_gathr": "この割合のファイルが画像/動画ならグリッドを使用", //m
"ml_pmode": "フォルダの末尾...",
"ml_btns": "コマンド",

View file

@ -221,7 +221,6 @@ Ls.kor = {
"cl_hpick": "아래 테이블에서 숨기고 싶은 열의 헤더를 탭하세요",
"cl_hcancel": "열 숨기기가 중단되었습니다",
"cl_rcm": "우클릭 메뉴", //m
"cl_gauto": "자동 田", //m
"ct_grid": "田 그리드",
"ct_ttips": '◔ ◡ ◔"> 도움말',
@ -276,8 +275,6 @@ Ls.kor = {
"tt_dynt": "트리가 확장될 때 자동으로 너비 증가",
"tt_wrap": "자동 줄 바꿈",
"tt_hover": "마우스를 올리면 넘어가는 줄 표시$N(마우스 커서가 왼쪽 여백에$N&nbsp; 있지 않으면 스크롤이 깨짐)",
"tt_gauto": "폴더 내용에 따라 그리드 또는 목록으로 표시", //m
"tt_gathr": "파일 중 이 비율이 이미지/동영상이면 그리드 사용", //m
"ml_pmode": "폴더 끝에서...",
"ml_btns": "명령",

View file

@ -221,7 +221,6 @@ Ls.nld = {
"cl_hpick": "Tik op de kolomkoppen om ze in de onderstaande tabel te verbergen",
"cl_hcancel": "Kolumn verbergen geannuleerd",
"cl_rcm": "Rechtermuisknopmenu", //m
"cl_gauto": "auto田", //m
"ct_grid": '田 grid',
"ct_ttips": '◔ ◡ ◔"> tooltips',
@ -276,8 +275,6 @@ Ls.nld = {
"tt_dynt": "Automatisch groeien naarmate de directoryboom zich uitbreidt",
"tt_wrap": "Automatische terugloop",
"tt_hover": "Laat overlopenden lijnen zien bij zweven$N(stopt het scrollen tenzij de muis in de linker gedeelte van het scherm is)",
"tt_gauto": "weergeven als grid of lijst afhankelijk van mapinhoud", //m
"tt_gathr": "gebruik grid als dit percentage bestanden afbeeldingen/video's zijn", //m
"ml_pmode": "Aan het einde van de map...",
"ml_btns": "Cmds",

View file

@ -218,7 +218,6 @@ Ls.nno = {
"cl_hpick": "klikk på overskrifta åt kolonnene du ønskjer å skjule i tabellen nedanfor",
"cl_hcancel": "kolonne-skjuling avbrote",
"cl_rcm": "høgreklikkmeny",
"cl_gauto": "auto田",
"ct_grid": '田 ikon',
"ct_ttips": 'vis hjelpetekst ved å holde musa over ting"> tips',
@ -273,8 +272,6 @@ Ls.nno = {
"tt_dynt": "øk bredda på panelet ettersom treet utvider seg",
"tt_wrap": "linjebryting",
"tt_hover": "vis heile mappenamnet når musepeikaren treff mappa$N( gjer diverre at scrollhjulet fusker dersom musepeikaren ikkje finn seg i grøfta )",
"tt_gauto": "byt visingsmodus (liste/ikon) avhengig av mappeinnhald",
"tt_gathr": "vis som ikon når denne prosentdelen er bilete/videoar",
"ml_pmode": "ved enden av mappa",
"ml_btns": "knapper",

View file

@ -218,7 +218,6 @@ Ls.nor = {
"cl_hpick": "klikk på overskriften til kolonnene du ønsker å skjule i tabellen nedenfor",
"cl_hcancel": "kolonne-skjuling avbrutt",
"cl_rcm": "høyreklikkmeny",
"cl_gauto": "auto田",
"ct_grid": '田 ikoner',
"ct_ttips": 'vis hjelpetekst ved å holde musen over ting"> tips',
@ -273,8 +272,6 @@ Ls.nor = {
"tt_dynt": "øk bredden på panelet ettersom treet utvider seg",
"tt_wrap": "linjebryting",
"tt_hover": "vis hele mappenavnet når musepekeren treffer mappen$N( gjør dessverre at scrollhjulet fusker dersom musepekeren ikke befinner seg i grøfta )",
"tt_gauto": "bytt visningsmodus (liste/ikoner) avhengig av mappeinnhold",
"tt_gathr": "vis som ikoner når denne prosentandelen er bilder/videoer",
"ml_pmode": "ved enden av mappen",
"ml_btns": "knapper",

View file

@ -224,7 +224,6 @@ Ls.pol = {
"cl_hpick": "kliknij nagłówki kolumn, aby ukryć je w tabeli niżej",
"cl_hcancel": "ukrywanie kolumn przerwane",
"cl_rcm": "menu kontekstowe", //m
"cl_gauto": "auto田", //m
"ct_grid": '田 siatka',
"ct_ttips": '◔ ◡ ◔"> podpowiedzi',
@ -279,8 +278,6 @@ Ls.pol = {
"tt_dynt": "rozszerzaj panel wraz z drzewem",
"tt_wrap": "zawijaj tekst",
"tt_hover": "pokazuj za długie linie po najechaniu kursorem$N( psuje przewijanie gdy $N&nbsp; kursor nie jest w lewym marginesie )",
"tt_gauto": "wyświetl jako siatkę lub listę w zależności od zawartości folderu", //m
"tt_gathr": "użyj siatki, jeśli ten procent plików to obrazy/wideo", //m
"ml_pmode": "na końcu folderu...",
"ml_btns": "komendy",

View file

@ -221,7 +221,6 @@ Ls.por = {
"cl_hpick": "toque nos cabeçalhos das colunas para ocultá-los na tabela abaixo",
"cl_hcancel": "ocultar coluna abortado",
"cl_rcm": "menu de clique direito",
"cl_gauto": "auto田", //m
"ct_grid": '田 a grade',
"ct_ttips": '◔ ◡ ◔"> dicas de ferramentas',
@ -276,8 +275,6 @@ Ls.por = {
"tt_dynt": "crescer automaticamente à medida que a árvore se expande",
"tt_wrap": "quebra de linha",
"tt_hover": "revelar linhas transbordando ao passar o mouse$N( quebra a rolagem a menos que o cursor do mouse $N&nbsp; esteja na margem esquerda )",
"tt_gauto": "exibir como grade ou lista dependendo do conteúdo da pasta", //m
"tt_gathr": "usar grade se esta porcentagem de arquivos for imagens/vídeos", //m
"ml_pmode": "ao final da pasta...",
"ml_btns": "comandos",

View file

@ -221,7 +221,6 @@ Ls.rus = {
"cl_hpick": "нажмите на заголовки столбцов, чтобы скрыть их в таблице ниже",
"cl_hcancel": "скрытие столбца отменено",
"cl_rcm": "контекстное меню", //m
"cl_gauto": "авто田", //m
"ct_grid": '田 сетка',
"ct_ttips": '◔ ◡ ◔"> подсказки',
@ -276,8 +275,6 @@ Ls.rus = {
"tt_dynt": "автоматическое расширение панели",
"tt_wrap": "перенос слов",
"tt_hover": "раскрывать обрезанные строки при наведении$N( ломает скроллинг, если $N&nbsp; курсор не в пустоте слева )",
"tt_gauto": "показывать как сетку или список в зависимости от содержимого папки", //m
"tt_gathr": "использовать сетку, если этот процент файлов — изображения/видео", //m
"ml_pmode": "в конце папки...",
"ml_btns": "команды",

View file

@ -220,7 +220,6 @@ Ls.spa = {
"cl_hpick": "toca en las cabeceras de columna para ocultarlas en la tabla de abajo",
"cl_hcancel": "ocultación de columna cancelada",
"cl_rcm": "menú contextual", //m
"cl_gauto": "auto田", //m
"ct_grid": '田 cuadrícula',
"ct_ttips": '◔ ◡ ◔"> tooltips',
@ -275,8 +274,6 @@ Ls.spa = {
"tt_dynt": "crecimiento automático a medida que el árbol se expande",
"tt_wrap": "ajuste de línea",
"tt_hover": "revelar líneas que se desbordan al pasar el ratón$N( rompe el desplazamiento a menos que el $N&nbsp; cursor esté en el margen izquierdo )",
"tt_gauto": "mostrar como cuadrícula o lista según el contenido de la carpeta", //m
"tt_gathr": "usar cuadrícula si este porcentaje de archivos son imágenes/videos", //m
"ml_pmode": "al final de la carpeta...",
"ml_btns": "acciones",

View file

@ -221,7 +221,6 @@ Ls.swe = {
"cl_hpick": "tryck på en kolumntitel för att dölja den i filvyn",
"cl_hcancel": "kolumndöljning avbruten",
"cl_rcm": "högerklicksmeny", //m
"cl_gauto": "auto田", //m
"ct_grid": '田 rutnätet',
"ct_ttips": '◔ ◡ ◔"> tips',
@ -276,8 +275,6 @@ Ls.swe = {
"tt_dynt": "väx vyn när trädet expanderar",
"tt_wrap": "automatisk radbrytning",
"tt_hover": "visa överlånga rader när muspekaren hovrar över dem$N( skrollhjulet fungerar ej såvida inte pekaren$Nstår till vänster )",
"tt_gauto": "visa som rutnät eller lista beroende på mappens innehåll", //m
"tt_gathr": "använd rutnät om denna andel filer är bilder/videor", //m
"ml_pmode": "vid mappens slut...",
"ml_btns": "komm.",

View file

@ -221,7 +221,6 @@ Ls.tur = {
"cl_hpick": "aşağıdaki tabloda gizlemek için sütun başlıklarına dokunun",
"cl_hcancel": "sütun gizleme iptal edildi",
"cl_rcm": "sağ tık menüsü", //m
"cl_gauto": "otomatik田", //m
"ct_grid": '田 ızgara',
"ct_ttips": '◔ ◡ ◔"> ipuçları',
@ -276,8 +275,6 @@ Ls.tur = {
"tt_dynt": "ağaç genişledikçe otomatik büyüt",
"tt_wrap": "kelime sarma",
"tt_hover": "fare ile üzerine gelindiğinde taşan satırları göster$N( fare imleci sol kenarda değilse kaydırmayı bozar )",
"tt_gauto": "klasör içeriğine bağlı olarak ızgara veya liste olarak göster", //m
"tt_gathr": "dosyaların bu yüzdesi resim/video ise ızgara kullan", //m
"ml_pmode": "klasör sonunda...",
"ml_btns": "komutlar",

View file

@ -221,7 +221,6 @@ Ls.ukr = {
"cl_hpick": "натисніть на заголовки стовпців, щоб приховати їх у таблиці нижче",
"cl_hcancel": "приховання стовпців скасовано",
"cl_rcm": "контекстне меню", //m
"cl_gauto": "авто田", //m
"ct_grid": '田 сітка',
"ct_ttips": '◔ ◡ ◔"> підказки',
@ -276,8 +275,6 @@ Ls.ukr = {
"tt_dynt": "автоматично збільшуватися при розширенні дерева",
"tt_wrap": "перенесення слів",
"tt_hover": "показувати переповнені рядки при наведенні$N( порушує прокрутку, якщо курсор $N&nbsp; миші не знаходиться в лівому відступі )",
"tt_gauto": "показувати як сітку або список залежно від вмісту папки", //m
"tt_gathr": "використовувати сітку, якщо цей відсоток файлів — зображення/відео", //m
"ml_pmode": "в кінці папки...",
"ml_btns": "команди",

View file

@ -221,7 +221,6 @@ Ls.vie = {
"cl_hpick": "chạm vào tiêu đề cột để ẩn trong bảng bên dưới",
"cl_hcancel": "đã hủy việc ẩn cột",
"cl_rcm": "menu chuột phải", //m
"cl_gauto": "lưới tự động", //m
// settings / tuỳ chọn
"ct_grid": '田 chế độ lưới',
@ -280,8 +279,6 @@ Ls.vie = {
"tt_dynt": "tự mở rộng khi cây mở rộng",
"tt_wrap": "ngắt dòng",
"tt_hover": "hiện thị dòng tràn khi rê chuột$N( không cuộn được nếu $N&nbsp; con trỏ chuột nằm ngoài cột trái )",
"tt_gauto": "hiển thị dạng lưới hoặc danh sách tùy theo nội dung thư mục", //m
"tt_gathr": "dùng lưới nếu tỷ lệ tệp này là ảnh/video", //m
"ml_pmode": "ở cuối thư mục...",
"ml_btns": "lệnh",

View file

@ -359,48 +359,6 @@ for the `re`pack to work, first run one of the sfx'es once to unpack it
**note:** you can also just download and run [/scripts/copyparty-repack.sh](https://github.com/9001/copyparty/blob/hovudstraum/scripts/copyparty-repack.sh) -- this will grab the latest copyparty release from github and do a few repacks; works on linux/macos (and windows with msys2 or WSL)
# dependencies
## vendored dependencies
some third-party code has been vendored into the git repo; some for convenience, some because they have been lightly hacked to fit copyparty's usecase better:
* inside the folder [/copyparty/stolen](https://github.com/9001/copyparty/tree/hovudstraum/copyparty/stolen) is python-libraries which runs on the serverside:
* `surrogateescape.py` (BSD2) can be removed; only needed for python2 support
* `qrcodegen.py` (MIT) can be removed and replaced with a systemwide install of the original [qrcodegen.py](https://github.com/nayuki/QR-Code-generator/blob/daa3114/python/qrcodegen.py);
* modifications: removed code/features that copyparty does not need/use
* `ifaddr` (BSD2) can be removed and replaced with a systemwide install of the original [ifaddr](https://github.com/ifaddr/ifaddr);
* modifications: support python2, support s390x / irix32 / graal
* `dnslib` (MIT) may be deleted and replaced with a systemwide install of the original [dnslib](https://github.com/paulc/dnslib/), HOWEVER:
* will cause problems for mDNS in some network environments; 6c1cf68bca7376c6291c3cfe710ebd5bd5ed3e6c + 94d1924fa97e5faaf1ebfd85cae73faebcb89fa1
* inside the folder `/copyparty/web/deps` (only in distributed archives/builds) is [fuse.py](https://github.com/fusepy/fusepy/blob/master/fuse.py), to make it downloadable from the connect-page on the web-ui
* inside the folder `/copyparty/web` (only in distributed archives/builds) is a collection of javascript libraries (produced by [deps-docker](https://github.com/9001/copyparty/tree/hovudstraum/scripts/deps-docker)) which are used clientside by the web-UI:
* [marked.js](https://github.com/markedjs/marked/releases) (MIT) powers the markdown editor, and has been [patched](https://github.com/9001/copyparty/blob/hovudstraum/scripts/deps-docker/marked-ln.patch) to include the line-numbers of each input line, to enable scroll-sync between the editor and the preview-pane. This patch is [not strictly necessary anymore](https://github.com/markedjs/marked/issues/2134) but I haven't gotten around to making the change yet
* [easyMDE](https://github.com/Ionaru/easy-markdown-editor/) (MIT), the alternative markdown editor, has the same [patch](https://github.com/9001/copyparty/blob/hovudstraum/scripts/deps-docker/easymde-ln.patch) to enable scroll-sync, and also some [size-golfing](https://github.com/9001/copyparty/blob/hovudstraum/scripts/deps-docker/easymde.patch)
* [codemirror5](https://github.com/codemirror/codemirror5/) (MIT) has no noteworthy changes, and has only been [size-golfed](https://github.com/9001/copyparty/blob/hovudstraum/scripts/deps-docker/codemirror.patch), could have been used as-is
* [DOMPurify](https://github.com/cure53/DOMPurify) (Apache2) is used as-is
* [hash-wasm](https://github.com/Daninet/hash-wasm/) (MIT) is used entirely as-is
* [asmcrypto.js](https://github.com/openpgpjs/asmcrypto.js/) (MIT) is abandoned software, and used almost as-is (slightly golfed for size); it is probably fine to exclude/remove this, since it will only break support for uploading from really old browsers (IE10/IE11) using up2k (the "fancy uploader")
* [prism.js](https://github.com/PrismJS/prism/) (MIT) is built with a [selection of languages](https://github.com/9001/copyparty/blob/hovudstraum/scripts/deps-docker/genprism.py); there is an assumption about the exact subset of languages elsewhere in copyparty, but there shouldn't be any big consequences of replacing it with a different build if that exists in Fedora
* an old version of [SourceCodePro](https://github.com/adobe-fonts/source-code-pro) (OFL-1.1), is size-reduced to [only the necessary characters](https://github.com/9001/copyparty/blob/41ed559faabdc180efc37fd027e7f1bb2d14d174/scripts/deps-docker/mini-fa.sh#L30-L31). There will be subtle layout issues if this is replaced with a newer version, because they changed some line-heights or something in later versions, but shouldn't be a big issue
* an old version of [font-awesome](https://github.com/FortAwesome/Font-Awesome) (OFL-1.1), size-reduced to [only the necessary icons](https://github.com/9001/copyparty/blob/hovudstraum/scripts/deps-docker/mini-fa.sh). I believe a newer version should also work.
## optional dependencies
explained in the [main readme](https://github.com/9001/copyparty/tree/hovudstraum#optional-dependencies), but a quick recap:
* recommended python libraries: `argon2-cffi paramiko pyftpdlib pyopenssl pillow rawpy pyzmq` [python-magic](https://pypi.org/project/python-magic/)
* only recommended on Windows: `psutil` (not very useful on Linux)
* NOT recommended: `impacket` because the feature it enables is a security nightmare
* NOT recommended: `mutagen` because ffmpeg produces better results (albeit slower)
* NOT recommended: `pyvips` because converting to jxl is extremely RAM-heavy
* NOT recommended: `pillow-heif` due to [legal reasons](https://github.com/9001/copyparty/blob/hovudstraum/docs/bad-codecs.md)
* recommended programs: `ffmpeg ffprobe cfssl cfssljson cfssl-certinfo`
* FFmpeg powers audio transcoding, and thumbnails of formats not covered by pillow/pyvips
# building
## dev env setup

View file

@ -38,5 +38,3 @@
accs:
rw: * # everyone gets read-write access, but
rwmda: ed # the user "ed" gets read-write-move-delete-admin
flags:
e2ds # enable filesystem-scanning for this volume only

View file

@ -777,7 +777,7 @@ symbol legend,
# briefly considered
* [pydio](https://github.com/pydio/cells): go/agpl3, looks great, fantastic ux -- but needs mariadb, systemwide install, SSO is 3280€/year
* [pydio](https://github.com/pydio/cells): python/agpl3, looks great, fantastic ux -- but needs mariadb, systemwide install
* [gossa](https://github.com/pldubouilh/gossa): go/mit, minimalistic, basic file upload, text editor, mkdir and rename (no delete/move)

View file

@ -78,10 +78,8 @@ def get_ramdisk():
return ret
for vol in ["/dev/shm", "/Volumes/cptd"]: # nosec (singleton test)
try:
if os.path.exists(vol):
return subdir(vol)
except:
pass
if os.path.exists("/Volumes"):
sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
@ -163,7 +161,7 @@ class Cfg(Namespace):
ex = "ac_convt au_vol dl_list du_iwho mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt th_qv th_qvx ups_who ver_iwho zip_who"
ka.update(**{k: 9 for k in ex.split()})
ex = "ctl_re db_act forget_ip gauto idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
ex = "ctl_re db_act forget_ip idp_cookie idp_store k304 loris no304 nosubtle qr_pin qr_wait re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo u2ow zipmaxn zipmaxs"
ka.update(**{k: 0 for k in ex.split()})
ex = "ah_alg bname chdir chmod_f chpw_db db_xattr doctitle df epilogues exit favico fika ipa ipar html_head html_head_d html_head_s idp_login idp_logout lg_sba lg_sbf log_date log_fk md_sba md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i opds_exts preadmes prologues readmes shr shr1 shr_site site smsg tcolor textfiles th_pregen txt_eol ufavico ufavico_h unlist up_site vc_url vname xff_src zipmaxt R RS SR"