Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4dca1cf8f4 | ||
|
|
edba7fffd3 | ||
|
|
21a96bcfe8 | ||
|
|
2d322dd48e | ||
|
|
df6d4df4f8 | ||
|
|
5aa893973c |
@@ -1605,7 +1605,7 @@ config file example:
|
|||||||
w: * # anyone can upload here
|
w: * # anyone can upload here
|
||||||
rw: ed # only user "ed" can read-write
|
rw: ed # only user "ed" can read-write
|
||||||
flags:
|
flags:
|
||||||
e2ds: # filesystem indexing is required for many of these:
|
e2ds # filesystem indexing is required for many of these:
|
||||||
sz: 1k-3m # accept upload only if filesize in this range
|
sz: 1k-3m # accept upload only if filesize in this range
|
||||||
df: 4g # free disk space cannot go lower than this
|
df: 4g # free disk space cannot go lower than this
|
||||||
vmaxb: 1g # volume can never exceed 1 GiB
|
vmaxb: 1g # volume can never exceed 1 GiB
|
||||||
@@ -1662,6 +1662,8 @@ this can instead be kept in a single place using the `--hist` argument, or the `
|
|||||||
|
|
||||||
by default, the per-volume `up2k.db` sqlite3-database for `-e2d` and `-e2t` is stored next to the thumbnails according to the `--hist` option, but the global-option `--dbpath` and/or volflag `dbpath` can be used to put the database somewhere else
|
by default, the per-volume `up2k.db` sqlite3-database for `-e2d` and `-e2t` is stored next to the thumbnails according to the `--hist` option, but the global-option `--dbpath` and/or volflag `dbpath` can be used to put the database somewhere else
|
||||||
|
|
||||||
|
if your storage backend is unreliable (NFS or bad HDDs), you can specify one or more "landmarks" to look for before doing anything database-related. A landmark is a file which is always expected to exist inside the volume. This avoids spurious filesystem rescans in the event of an outage. One line per landmark (see example below)
|
||||||
|
|
||||||
note:
|
note:
|
||||||
* putting the hist-folders on an SSD is strongly recommended for performance
|
* putting the hist-folders on an SSD is strongly recommended for performance
|
||||||
* markdown edits are always stored in a local `.hist` subdirectory
|
* markdown edits are always stored in a local `.hist` subdirectory
|
||||||
@@ -1679,6 +1681,8 @@ config file example:
|
|||||||
flags:
|
flags:
|
||||||
hist: - # restore the default (/mnt/nas/pics/.hist/)
|
hist: - # restore the default (/mnt/nas/pics/.hist/)
|
||||||
hist: /mnt/nas/cache/pics/ # can be absolute path
|
hist: /mnt/nas/cache/pics/ # can be absolute path
|
||||||
|
landmark: me.jpg # /mnt/nas/pics/me.jpg must be readable to enable db
|
||||||
|
landmark: info/a.txt^=ok # and this textfile must start with "ok"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# Maintainer: icxes <dev.null@need.moe>
|
# Maintainer: icxes <dev.null@need.moe>
|
||||||
pkgname=copyparty
|
pkgname=copyparty
|
||||||
pkgver="1.18.2"
|
pkgver="1.18.3"
|
||||||
pkgrel=1
|
pkgrel=1
|
||||||
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
pkgdesc="File server with accelerated resumable uploads, dedup, WebDAV, FTP, TFTP, zeroconf, media indexer, thumbnails++"
|
||||||
arch=("any")
|
arch=("any")
|
||||||
@@ -22,7 +22,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")
|
source=("https://github.com/9001/${pkgname}/releases/download/v${pkgver}/${pkgname}-${pkgver}.tar.gz")
|
||||||
backup=("etc/${pkgname}.d/init" )
|
backup=("etc/${pkgname}.d/init" )
|
||||||
sha256sums=("7bcd6fad7c1612a29320e9eb5e8f1bf3852c35df03a04ecb348536028ce31a37")
|
sha256sums=("aa12f4779cf5c014cc9503798ac63872dac840ca91ddf122daa6befb4c883d48")
|
||||||
|
|
||||||
build() {
|
build() {
|
||||||
cd "${srcdir}/${pkgname}-${pkgver}"
|
cd "${srcdir}/${pkgname}-${pkgver}"
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"url": "https://github.com/9001/copyparty/releases/download/v1.18.2/copyparty-sfx.py",
|
"url": "https://github.com/9001/copyparty/releases/download/v1.18.3/copyparty-sfx.py",
|
||||||
"version": "1.18.2",
|
"version": "1.18.3",
|
||||||
"hash": "sha256-l6rZlZG7y25ds23ZqBA6BjzYY8WLTMAmfsGoWeYt0mQ="
|
"hash": "sha256-INqErls4gyhBAlDlY1vfNboKrrqHmeiyB+RAuuYRISQ="
|
||||||
}
|
}
|
||||||
@@ -1550,6 +1550,7 @@ def add_ui(ap, retry):
|
|||||||
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
ap2.add_argument("--nsort", action="store_true", help="default-enable natural sort of filenames with leading numbers (volflag=nsort)")
|
||||||
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
|
ap2.add_argument("--hsortn", metavar="N", type=int, default=2, help="number of sorting rules to include in media URLs by default (volflag=hsortn)")
|
||||||
ap2.add_argument("--see-dots", action="store_true", help="default-enable seeing dotfiles; only takes effect if user has the necessary permissions")
|
ap2.add_argument("--see-dots", action="store_true", help="default-enable seeing dotfiles; only takes effect if user has the necessary permissions")
|
||||||
|
ap2.add_argument("--qdel", metavar="LVL", type=int, default=2, help="number of confirmations to show when deleting files (2/1/0)")
|
||||||
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
ap2.add_argument("--unlist", metavar="REGEX", type=u, default="", help="don't show files matching \033[33mREGEX\033[0m in file list. Purely cosmetic! Does not affect API calls, just the browser. Example: [\033[32m\\.(js|css)$\033[0m] (volflag=unlist)")
|
||||||
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
ap2.add_argument("--favico", metavar="TXT", type=u, default="c 000 none" if retry else "🎉 000 none", help="\033[33mfavicon-text\033[0m [ \033[33mforeground\033[0m [ \033[33mbackground\033[0m ] ], set blank to disable")
|
||||||
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)")
|
ap2.add_argument("--ext-th", metavar="E=VP", type=u, action="append", help="use thumbnail-image \033[33mVP\033[0m for file-extension \033[33mE\033[0m, example: [\033[32mexe=/.res/exe.png\033[0m] (volflag=ext_th)")
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
# coding: utf-8
|
# coding: utf-8
|
||||||
|
|
||||||
VERSION = (1, 18, 3)
|
VERSION = (1, 18, 4)
|
||||||
CODENAME = "logtail"
|
CODENAME = "logtail"
|
||||||
BUILD_DT = (2025, 7, 21)
|
BUILD_DT = (2025, 7, 25)
|
||||||
|
|
||||||
S_VERSION = ".".join(map(str, VERSION))
|
S_VERSION = ".".join(map(str, VERSION))
|
||||||
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
S_BUILD_DT = "{0:04d}-{1:02d}-{2:02d}".format(*BUILD_DT)
|
||||||
|
|||||||
@@ -386,20 +386,20 @@ class VFS(object):
|
|||||||
self.adot: dict[str, list[str]] = {}
|
self.adot: dict[str, list[str]] = {}
|
||||||
self.js_ls = {}
|
self.js_ls = {}
|
||||||
self.js_htm = ""
|
self.js_htm = ""
|
||||||
|
self.all_vols: dict[str, VFS] = {} # flattened recursive
|
||||||
|
self.all_nodes: dict[str, VFS] = {} # also jumpvols/shares
|
||||||
|
|
||||||
if realpath:
|
if realpath:
|
||||||
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
|
rp = realpath + ("" if realpath.endswith(os.sep) else os.sep)
|
||||||
vp = vpath + ("/" if vpath else "")
|
vp = vpath + ("/" if vpath else "")
|
||||||
self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
|
self.histpath = os.path.join(realpath, ".hist") # db / thumbcache
|
||||||
self.dbpath = self.histpath
|
self.dbpath = self.histpath
|
||||||
self.all_vols = {vpath: self} # flattened recursive
|
self.all_vols[vpath] = self
|
||||||
self.all_nodes = {vpath: self} # also jumpvols/shares
|
self.all_nodes[vpath] = self
|
||||||
self.all_aps = [(rp, [self])]
|
self.all_aps = [(rp, [self])]
|
||||||
self.all_vps = [(vp, self)]
|
self.all_vps = [(vp, self)]
|
||||||
else:
|
else:
|
||||||
self.histpath = self.dbpath = ""
|
self.histpath = self.dbpath = ""
|
||||||
self.all_vols = {}
|
|
||||||
self.all_nodes = {}
|
|
||||||
self.all_aps = []
|
self.all_aps = []
|
||||||
self.all_vps = []
|
self.all_vps = []
|
||||||
|
|
||||||
@@ -868,6 +868,53 @@ class VFS(object):
|
|||||||
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
def check_landmarks(self) -> bool:
|
||||||
|
if self.dbv:
|
||||||
|
return True
|
||||||
|
|
||||||
|
vps = self.flags.get("landmark") or []
|
||||||
|
if not vps:
|
||||||
|
return True
|
||||||
|
|
||||||
|
failed = ""
|
||||||
|
for vp in vps:
|
||||||
|
if "^=" in vp:
|
||||||
|
vp, zs = vp.split("^=", 1)
|
||||||
|
expect = zs.encode("utf-8")
|
||||||
|
else:
|
||||||
|
expect = b""
|
||||||
|
|
||||||
|
if self.log:
|
||||||
|
t = "checking [/%s] landmark [%s]"
|
||||||
|
self.log("vfs", t % (self.vpath, vp), 6)
|
||||||
|
|
||||||
|
ap = "?"
|
||||||
|
try:
|
||||||
|
ap = self.canonical(vp)
|
||||||
|
with open(ap, "rb") as f:
|
||||||
|
buf = f.read(4096)
|
||||||
|
if not buf.startswith(expect):
|
||||||
|
t = "file [%s] does not start with the expected bytes %s"
|
||||||
|
failed = t % (ap, expect)
|
||||||
|
break
|
||||||
|
except Exception as ex:
|
||||||
|
t = "%r while trying to read [%s] => [%s]"
|
||||||
|
failed = t % (ex, vp, ap)
|
||||||
|
break
|
||||||
|
|
||||||
|
if not failed:
|
||||||
|
return True
|
||||||
|
|
||||||
|
if self.log:
|
||||||
|
t = "WARNING: landmark verification failed; %s; will now disable up2k database for volume [/%s]"
|
||||||
|
self.log("vfs", t % (failed, self.vpath), 3)
|
||||||
|
|
||||||
|
for rm in "e2d e2t e2v".split():
|
||||||
|
self.flags = {k: v for k, v in self.flags.items() if not k.startswith(rm)}
|
||||||
|
self.flags["d2d"] = True
|
||||||
|
self.flags["d2t"] = True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
if WINDOWS:
|
if WINDOWS:
|
||||||
re_vol = re.compile(r"^([a-zA-Z]:[\\/][^:]*|[^:]*):([^:]*):(.*)$")
|
re_vol = re.compile(r"^([a-zA-Z]:[\\/][^:]*|[^:]*):([^:]*):(.*)$")
|
||||||
@@ -1501,7 +1548,7 @@ class AuthSrv(object):
|
|||||||
flags[name] = True
|
flags[name] = True
|
||||||
return
|
return
|
||||||
|
|
||||||
zs = "ext_th mtp on403 on404 xbu xau xiu xbc xac xbr xar xbd xad xm xban"
|
zs = "ext_th landmark mtp on403 on404 xbu xau xiu xbc xac xbr xar xbd xad xm xban"
|
||||||
if name not in zs.split():
|
if name not in zs.split():
|
||||||
if value is True:
|
if value is True:
|
||||||
t = "└─add volflag [{}] = {} ({})"
|
t = "└─add volflag [{}] = {} ({})"
|
||||||
@@ -2237,6 +2284,8 @@ class AuthSrv(object):
|
|||||||
t = "WARNING: volume [/%s]: invalid value specified for ext-th: %s"
|
t = "WARNING: volume [/%s]: invalid value specified for ext-th: %s"
|
||||||
self.log(t % (vol.vpath, etv), 3)
|
self.log(t % (vol.vpath, etv), 3)
|
||||||
|
|
||||||
|
vol.check_landmarks()
|
||||||
|
|
||||||
# d2d drops all database features for a volume
|
# d2d drops all database features for a volume
|
||||||
for grp, rm in [["d2d", "e2d"], ["d2t", "e2t"], ["d2d", "e2v"]]:
|
for grp, rm in [["d2d", "e2d"], ["d2t", "e2t"], ["d2d", "e2v"]]:
|
||||||
if not vol.flags.get(grp, False):
|
if not vol.flags.get(grp, False):
|
||||||
@@ -2670,6 +2719,7 @@ class AuthSrv(object):
|
|||||||
"def_hcols": list(vf.get("mth") or []),
|
"def_hcols": list(vf.get("mth") or []),
|
||||||
"unlist0": vf.get("unlist") or "",
|
"unlist0": vf.get("unlist") or "",
|
||||||
"see_dots": self.args.see_dots,
|
"see_dots": self.args.see_dots,
|
||||||
|
"dqdel": self.args.qdel,
|
||||||
"dgrid": "grid" in vf,
|
"dgrid": "grid" in vf,
|
||||||
"dgsel": "gsel" in vf,
|
"dgsel": "gsel" in vf,
|
||||||
"dnsort": "nsort" in vf,
|
"dnsort": "nsort" in vf,
|
||||||
|
|||||||
@@ -222,6 +222,7 @@ flagcats = {
|
|||||||
"d2d": "disables all database stuff, overrides -e2*",
|
"d2d": "disables all database stuff, overrides -e2*",
|
||||||
"hist=/tmp/cdb": "puts thumbnails and indexes at that location",
|
"hist=/tmp/cdb": "puts thumbnails and indexes at that location",
|
||||||
"dbpath=/tmp/cdb": "puts indexes at that location",
|
"dbpath=/tmp/cdb": "puts indexes at that location",
|
||||||
|
"landmark=foo": "disable db if file foo doesn't exist",
|
||||||
"scan=60": "scan for new files every 60sec, same as --re-maxage",
|
"scan=60": "scan for new files every 60sec, same as --re-maxage",
|
||||||
"nohash=\\.iso$": "skips hashing file contents if path matches *.iso",
|
"nohash=\\.iso$": "skips hashing file contents if path matches *.iso",
|
||||||
"noidx=\\.iso$": "fully ignores the contents at paths matching *.iso",
|
"noidx=\\.iso$": "fully ignores the contents at paths matching *.iso",
|
||||||
|
|||||||
@@ -5573,7 +5573,7 @@ class HttpCli(object):
|
|||||||
db.commit()
|
db.commit()
|
||||||
db.close()
|
db.close()
|
||||||
|
|
||||||
self.conn.hsrv.broker.ask("reload", False, False).get()
|
self.conn.hsrv.broker.ask("reload", False, True).get()
|
||||||
|
|
||||||
self.redirect("", "?idp")
|
self.redirect("", "?idp")
|
||||||
return True
|
return True
|
||||||
@@ -5657,7 +5657,7 @@ class HttpCli(object):
|
|||||||
|
|
||||||
cur.connection.commit()
|
cur.connection.commit()
|
||||||
if reload:
|
if reload:
|
||||||
self.conn.hsrv.broker.ask("reload", False, False).get()
|
self.conn.hsrv.broker.ask("reload", False, True).get()
|
||||||
self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
|
self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
|
||||||
|
|
||||||
self.redirect("", "?shares")
|
self.redirect("", "?shares")
|
||||||
@@ -5749,7 +5749,7 @@ class HttpCli(object):
|
|||||||
cur.execute(q, (skey, fn))
|
cur.execute(q, (skey, fn))
|
||||||
|
|
||||||
cur.connection.commit()
|
cur.connection.commit()
|
||||||
self.conn.hsrv.broker.ask("reload", False, False).get()
|
self.conn.hsrv.broker.ask("reload", False, True).get()
|
||||||
self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
|
self.conn.hsrv.broker.ask("up2k.wake_rescanner").get()
|
||||||
|
|
||||||
fn = quotep(fns[0]) if len(fns) == 1 else ""
|
fn = quotep(fns[0]) if len(fns) == 1 else ""
|
||||||
|
|||||||
@@ -1379,6 +1379,10 @@ class Up2k(object):
|
|||||||
t = "volume /%s at [%s] is empty; will not be indexed as this could be due to an offline filesystem"
|
t = "volume /%s at [%s] is empty; will not be indexed as this could be due to an offline filesystem"
|
||||||
self.log(t % (vol.vpath, rtop), 6)
|
self.log(t % (vol.vpath, rtop), 6)
|
||||||
return True, False
|
return True, False
|
||||||
|
if not vol.check_landmarks():
|
||||||
|
t = "volume /%s at [%s] will not be indexed due to bad landmarks"
|
||||||
|
self.log(t % (vol.vpath, rtop), 6)
|
||||||
|
return True, False
|
||||||
|
|
||||||
n_add, _, _ = self._build_dir(
|
n_add, _, _ = self._build_dir(
|
||||||
db,
|
db,
|
||||||
|
|||||||
@@ -1974,7 +1974,7 @@ def rand_name(fdir: str, fn: str, rnd: int) -> str:
|
|||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|
||||||
def gen_filekey(alg: int, salt: str, fspath: str, fsize: int, inode: int) -> str:
|
def _gen_filekey(alg: int, salt: str, fspath: str, fsize: int, inode: int) -> str:
|
||||||
if alg == 1:
|
if alg == 1:
|
||||||
zs = "%s %s %s %s" % (salt, fspath, fsize, inode)
|
zs = "%s %s %s %s" % (salt, fspath, fsize, inode)
|
||||||
else:
|
else:
|
||||||
@@ -1984,6 +1984,13 @@ def gen_filekey(alg: int, salt: str, fspath: str, fsize: int, inode: int) -> str
|
|||||||
return ub64enc(hashlib.sha512(zb).digest()).decode("ascii")
|
return ub64enc(hashlib.sha512(zb).digest()).decode("ascii")
|
||||||
|
|
||||||
|
|
||||||
|
def _gen_filekey_w(alg: int, salt: str, fspath: str, fsize: int, inode: int) -> str:
|
||||||
|
return _gen_filekey(alg, salt, fspath.replace("/", "\\"), fsize, inode)
|
||||||
|
|
||||||
|
|
||||||
|
gen_filekey = _gen_filekey_w if ANYWIN else _gen_filekey
|
||||||
|
|
||||||
|
|
||||||
def gen_filekey_dbg(
|
def gen_filekey_dbg(
|
||||||
alg: int,
|
alg: int,
|
||||||
salt: str,
|
salt: str,
|
||||||
|
|||||||
@@ -226,6 +226,7 @@ var Ls = {
|
|||||||
"ct_csel": 'use CTRL and SHIFT for file selection in grid-view">sel',
|
"ct_csel": 'use CTRL and SHIFT for file selection in grid-view">sel',
|
||||||
"ct_ihop": 'when the image viewer is closed, scroll down to the last viewed file">g⮯',
|
"ct_ihop": 'when the image viewer is closed, scroll down to the last viewed file">g⮯',
|
||||||
"ct_dots": 'show hidden files (if server permits)">dotfiles',
|
"ct_dots": 'show hidden files (if server permits)">dotfiles',
|
||||||
|
"ct_qdel": 'when deleting files, only ask for confirmation once">qdel',
|
||||||
"ct_dir1st": 'sort folders before files">📁 first',
|
"ct_dir1st": 'sort folders before files">📁 first',
|
||||||
"ct_nsort": 'natural sort (for filenames with leading digits)">nsort',
|
"ct_nsort": 'natural sort (for filenames with leading digits)">nsort',
|
||||||
"ct_readme": 'show README.md in folder listings">📜 readme',
|
"ct_readme": 'show README.md in folder listings">📜 readme',
|
||||||
@@ -850,6 +851,7 @@ var Ls = {
|
|||||||
"ct_csel": 'bruk tastene CTRL og SHIFT for markering av filer i ikonvisning">merk',
|
"ct_csel": 'bruk tastene CTRL og SHIFT for markering av filer i ikonvisning">merk',
|
||||||
"ct_ihop": 'bla ned til sist viste bilde når bildeviseren lukkes">g⮯',
|
"ct_ihop": 'bla ned til sist viste bilde når bildeviseren lukkes">g⮯',
|
||||||
"ct_dots": 'vis skjulte filer (gitt at serveren tillater det)">.synlig',
|
"ct_dots": 'vis skjulte filer (gitt at serveren tillater det)">.synlig',
|
||||||
|
"ct_qdel": 'sletteknappen spør bare én gang om bekreftelse">hurtig🗑️',
|
||||||
"ct_dir1st": 'sorter slik at mapper kommer foran filer">📁 først',
|
"ct_dir1st": 'sorter slik at mapper kommer foran filer">📁 først',
|
||||||
"ct_nsort": 'naturlig sortering (forstår tall i filnavn)">nsort',
|
"ct_nsort": 'naturlig sortering (forstår tall i filnavn)">nsort',
|
||||||
"ct_readme": 'vis README.md nedenfor filene">📜 readme',
|
"ct_readme": 'vis README.md nedenfor filene">📜 readme',
|
||||||
@@ -1474,6 +1476,7 @@ var Ls = {
|
|||||||
"ct_csel": '在网格视图中使用 CTRL 和 SHIFT 进行文件选择">CTRL',
|
"ct_csel": '在网格视图中使用 CTRL 和 SHIFT 进行文件选择">CTRL',
|
||||||
"ct_ihop": '当图像查看器关闭时,滚动到最后查看的文件">滚动',
|
"ct_ihop": '当图像查看器关闭时,滚动到最后查看的文件">滚动',
|
||||||
"ct_dots": '显示隐藏文件(如果服务器允许)">隐藏文件',
|
"ct_dots": '显示隐藏文件(如果服务器允许)">隐藏文件',
|
||||||
|
"ct_qdel": '删除文件时,只需确认一次">快删', //m
|
||||||
"ct_dir1st": '在文件之前排序文件夹">📁 排序',
|
"ct_dir1st": '在文件之前排序文件夹">📁 排序',
|
||||||
"ct_nsort": '正确排序以数字开头的文件名">数字排序', //m
|
"ct_nsort": '正确排序以数字开头的文件名">数字排序', //m
|
||||||
"ct_readme": '在文件夹列表中显示 README.md">📜 readme',
|
"ct_readme": '在文件夹列表中显示 README.md">📜 readme',
|
||||||
@@ -2090,6 +2093,7 @@ ebi('op_cfg').innerHTML = (
|
|||||||
' <a id="csel" class="tgl btn" href="#" tt="' + L.ct_csel + '</a>\n' +
|
' <a id="csel" class="tgl btn" href="#" tt="' + L.ct_csel + '</a>\n' +
|
||||||
' <a id="ihop" class="tgl btn" href="#" tt="' + L.ct_ihop + '</a>\n' +
|
' <a id="ihop" class="tgl btn" href="#" tt="' + L.ct_ihop + '</a>\n' +
|
||||||
' <a id="dotfiles" class="tgl btn" href="#" tt="' + L.ct_dots + '</a>\n' +
|
' <a id="dotfiles" class="tgl btn" href="#" tt="' + L.ct_dots + '</a>\n' +
|
||||||
|
' <a id="qdel" class="tgl btn" href="#" tt="' + L.ct_qdel + '</a>\n' +
|
||||||
' <a id="dir1st" class="tgl btn" href="#" tt="' + L.ct_dir1st + '</a>\n' +
|
' <a id="dir1st" class="tgl btn" href="#" tt="' + L.ct_dir1st + '</a>\n' +
|
||||||
' <a id="nsort" class="tgl btn" href="#" tt="' + L.ct_nsort + '</a>\n' +
|
' <a id="nsort" class="tgl btn" href="#" tt="' + L.ct_nsort + '</a>\n' +
|
||||||
' <a id="ireadme" class="tgl btn" href="#" tt="' + L.ct_readme + '</a>\n' +
|
' <a id="ireadme" class="tgl btn" href="#" tt="' + L.ct_readme + '</a>\n' +
|
||||||
@@ -5453,7 +5457,16 @@ var fileman = (function () {
|
|||||||
deleter();
|
deleter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var asks = r.qdel ? 1 : 2;
|
||||||
|
if (dqdel === 0)
|
||||||
|
asks -= 1;
|
||||||
|
|
||||||
|
if (!asks)
|
||||||
|
return deleter();
|
||||||
|
|
||||||
modal.confirm('<h6 style="color:#900">' + L.danger + '</h6>\n<b>' + L.fd_warn1.format(vps.length) + '</b><ul>' + uricom_adec(vps, true).join('') + '</ul>', function () {
|
modal.confirm('<h6 style="color:#900">' + L.danger + '</h6>\n<b>' + L.fd_warn1.format(vps.length) + '</b><ul>' + uricom_adec(vps, true).join('') + '</ul>', function () {
|
||||||
|
if (asks === 1)
|
||||||
|
return deleter();
|
||||||
modal.confirm(L.fd_warn2, deleter, null);
|
modal.confirm(L.fd_warn2, deleter, null);
|
||||||
}, null);
|
}, null);
|
||||||
};
|
};
|
||||||
@@ -5814,6 +5827,8 @@ var fileman = (function () {
|
|||||||
r.bus.onmessage();
|
r.bus.onmessage();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bcfg_bind(r, 'qdel', 'qdel', dqdel == 1);
|
||||||
|
|
||||||
bren.onclick = r.rename;
|
bren.onclick = r.rename;
|
||||||
bdel.onclick = r.delete;
|
bdel.onclick = r.delete;
|
||||||
bcut.onclick = r.cut;
|
bcut.onclick = r.cut;
|
||||||
|
|||||||
@@ -1,3 +1,24 @@
|
|||||||
|
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||||
|
# 2025-0721-2307 `v1.18.3` drop the umask
|
||||||
|
|
||||||
|
## 🧪 new features
|
||||||
|
|
||||||
|
* #181 the default chmod (unix-permissions) of new files and folders can now be changed 9921c43e
|
||||||
|
* `--chmod-d` or volflag `chmod_d` sets directory permissions; default is 755
|
||||||
|
* `--chmod-f` or volflag `chmod_f` sets file permissions; default is usually 644 (OS-defined)
|
||||||
|
* see `--help-chmod` which explains the numbers
|
||||||
|
|
||||||
|
## 🩹 bugfixes
|
||||||
|
|
||||||
|
* #179 couldn't combine `--shr` (shares) and `--xvol` (symlink-guard) 0f0f8d90
|
||||||
|
* #180 gallery buttons could still be clicked when faded-out 8c32b0e7
|
||||||
|
* rss-feeds were slightly busted when combined with rp-loc (location-based proxying) 56d3bcf5
|
||||||
|
* music-playback within search-results no longer jumps into the next folder at end-of-list 9bc4c5d2
|
||||||
|
* video-playback on iOS now behaves like on all other platforms 78605d9a
|
||||||
|
* (it would force-switch into fullscreen because that's their default)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀
|
||||||
# 2025-0707-1419 `v1.18.2` idp-vol persistence
|
# 2025-0707-1419 `v1.18.2` idp-vol persistence
|
||||||
|
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ var tl_browser = {
|
|||||||
"file-manager",
|
"file-manager",
|
||||||
["G", "toggle list / grid view"],
|
["G", "toggle list / grid view"],
|
||||||
["T", "toggle thumbnails / icons"],
|
["T", "toggle thumbnails / icons"],
|
||||||
["🡅 A/D", "thumbnail size"],
|
["⇧ A/D", "thumbnail size"],
|
||||||
["ctrl-K", "delete selected"],
|
["ctrl-K", "delete selected"],
|
||||||
["ctrl-X", "cut selection to clipboard"],
|
["ctrl-X", "cut selection to clipboard"],
|
||||||
["ctrl-C", "copy selection to clipboard"],
|
["ctrl-C", "copy selection to clipboard"],
|
||||||
@@ -131,9 +131,9 @@ var tl_browser = {
|
|||||||
|
|
||||||
"file-list-sel",
|
"file-list-sel",
|
||||||
["space", "toggle file selection"],
|
["space", "toggle file selection"],
|
||||||
["🡑/🡓", "move selection cursor"],
|
["↑/↓", "move selection cursor"],
|
||||||
["ctrl 🡑/🡓", "move cursor and viewport"],
|
["ctrl ↑/↓", "move cursor and viewport"],
|
||||||
["🡅 🡑/🡓", "select prev/next file"],
|
["⇧ ↑/↓", "select prev/next file"],
|
||||||
["ctrl-A", "select all files / folders"],
|
["ctrl-A", "select all files / folders"],
|
||||||
], [
|
], [
|
||||||
"navigation",
|
"navigation",
|
||||||
@@ -156,7 +156,7 @@ var tl_browser = {
|
|||||||
["Home/End", "first/last pic"],
|
["Home/End", "first/last pic"],
|
||||||
["F", "fullscreen"],
|
["F", "fullscreen"],
|
||||||
["R", "rotate clockwise"],
|
["R", "rotate clockwise"],
|
||||||
["🡅 R", "rotate ccw"],
|
["⇧ R", "rotate ccw"],
|
||||||
["S", "select pic"],
|
["S", "select pic"],
|
||||||
["Y", "download pic"],
|
["Y", "download pic"],
|
||||||
], [
|
], [
|
||||||
@@ -312,6 +312,7 @@ var tl_browser = {
|
|||||||
"ct_csel": 'use CTRL and SHIFT for file selection in grid-view">sel',
|
"ct_csel": 'use CTRL and SHIFT for file selection in grid-view">sel',
|
||||||
"ct_ihop": 'when the image viewer is closed, scroll down to the last viewed file">g⮯',
|
"ct_ihop": 'when the image viewer is closed, scroll down to the last viewed file">g⮯',
|
||||||
"ct_dots": 'show hidden files (if server permits)">dotfiles',
|
"ct_dots": 'show hidden files (if server permits)">dotfiles',
|
||||||
|
"ct_qdel": 'when deleting files, only ask for confirmation once">qdel',
|
||||||
"ct_dir1st": 'sort folders before files">📁 first',
|
"ct_dir1st": 'sort folders before files">📁 first',
|
||||||
"ct_nsort": 'natural sort (for filenames with leading digits)">nsort',
|
"ct_nsort": 'natural sort (for filenames with leading digits)">nsort',
|
||||||
"ct_readme": 'show README.md in folder listings">📜 readme',
|
"ct_readme": 'show README.md in folder listings">📜 readme',
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ class Cfg(Namespace):
|
|||||||
ex = "ah_cli ah_gen css_browser dbpath hist ipu js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua ua_nodoc ua_nozip"
|
ex = "ah_cli ah_gen css_browser dbpath hist ipu js_browser js_other mime mimes no_forget no_hash no_idx nonsus_urls og_tpl og_ua ua_nodoc ua_nozip"
|
||||||
ka.update(**{k: None for k in ex.split()})
|
ka.update(**{k: None for k in ex.split()})
|
||||||
|
|
||||||
ex = "hash_mt hsortn safe_dedup srch_time tail_fd tail_rate u2abort u2j u2sz"
|
ex = "hash_mt hsortn qdel safe_dedup srch_time tail_fd tail_rate u2abort u2j u2sz"
|
||||||
ka.update(**{k: 1 for k in ex.split()})
|
ka.update(**{k: 1 for k in ex.split()})
|
||||||
|
|
||||||
ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who"
|
ex = "au_vol dl_list mtab_age reg_cap s_thead s_tbody tail_tmax tail_who th_convt ups_who zip_who"
|
||||||
|
|||||||
Reference in New Issue
Block a user