mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 17:12:13 -06:00
option to show upload timestamps in directory listing;
enable with -mte +.ip_at or volflag mte=+.ip_at worst-case performance impact: 18%
This commit is contained in:
parent
2048b7538e
commit
4b5a0787ab
|
@ -27,6 +27,8 @@ from .authsrv import expand_config_file, re_vol, split_cfg_ln, upgrade_cfg_fmt
|
||||||
from .cfg import flagcats, onedash
|
from .cfg import flagcats, onedash
|
||||||
from .svchub import SvcHub
|
from .svchub import SvcHub
|
||||||
from .util import (
|
from .util import (
|
||||||
|
DEF_MTE,
|
||||||
|
DEF_MTH,
|
||||||
IMPLICATIONS,
|
IMPLICATIONS,
|
||||||
JINJA_VER,
|
JINJA_VER,
|
||||||
PYFTPD_VER,
|
PYFTPD_VER,
|
||||||
|
@ -1132,10 +1134,8 @@ def add_db_metadata(ap):
|
||||||
ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such")
|
ap2.add_argument("--mtag-v", action="store_true", help="verbose tag scanning; print errors from mtp subprocesses and such")
|
||||||
ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/ffprobe parsers")
|
ap2.add_argument("--mtag-vv", action="store_true", help="debug mtp settings and mutagen/ffprobe parsers")
|
||||||
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping")
|
ap2.add_argument("-mtm", metavar="M=t,t,t", type=u, action="append", help="add/replace metadata mapping")
|
||||||
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.)",
|
ap2.add_argument("-mte", metavar="M,M,M", type=u, help="tags to index/display (comma-sep.); either an entire replacement list, or add/remove stuff on the default-list with +foo or /bar", default=DEF_MTE)
|
||||||
default="circle,album,.tn,artist,title,.bpm,key,.dur,.q,.vq,.aq,vc,ac,fmt,res,.fps,ahash,vhash,up_ip,.up_at")
|
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.); assign/add/remove same as -mte", default=DEF_MTH)
|
||||||
ap2.add_argument("-mth", metavar="M,M,M", type=u, help="tags to hide by default (comma-sep.)",
|
|
||||||
default=".vq,.aq,vc,ac,fmt,res,.fps")
|
|
||||||
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag M using program BIN to parse the file")
|
ap2.add_argument("-mtp", metavar="M=[f,]BIN", type=u, action="append", help="read tag M using program BIN to parse the file")
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -21,11 +21,13 @@ from .util import (
|
||||||
META_NOBOTS,
|
META_NOBOTS,
|
||||||
SQLITE_VER,
|
SQLITE_VER,
|
||||||
UNPLICATIONS,
|
UNPLICATIONS,
|
||||||
|
ODict,
|
||||||
Pebkac,
|
Pebkac,
|
||||||
absreal,
|
absreal,
|
||||||
afsenc,
|
afsenc,
|
||||||
get_df,
|
get_df,
|
||||||
humansize,
|
humansize,
|
||||||
|
odfusion,
|
||||||
relchk,
|
relchk,
|
||||||
statdir,
|
statdir,
|
||||||
uncyg,
|
uncyg,
|
||||||
|
@ -1477,13 +1479,14 @@ class AuthSrv(object):
|
||||||
|
|
||||||
# default tag cfgs if unset
|
# default tag cfgs if unset
|
||||||
if "mte" not in vol.flags:
|
if "mte" not in vol.flags:
|
||||||
vol.flags["mte"] = self.args.mte
|
vol.flags["mte"] = self.args.mte.copy()
|
||||||
elif vol.flags["mte"].startswith("+"):
|
else:
|
||||||
vol.flags["mte"] = ",".join(
|
vol.flags["mte"] = odfusion(self.args.mte, vol.flags["mte"])
|
||||||
x for x in [self.args.mte, vol.flags["mte"][1:]] if x
|
|
||||||
)
|
|
||||||
if "mth" not in vol.flags:
|
if "mth" not in vol.flags:
|
||||||
vol.flags["mth"] = self.args.mth
|
vol.flags["mth"] = self.args.mth.copy()
|
||||||
|
else:
|
||||||
|
vol.flags["mth"] = odfusion(self.args.mth, vol.flags["mth"])
|
||||||
|
|
||||||
# append additive args from argv to volflags
|
# append additive args from argv to volflags
|
||||||
hooks = "xbu xau xiu xbr xar xbd xad xm xban".split()
|
hooks = "xbu xau xiu xbr xar xbd xad xm xban".split()
|
||||||
|
@ -1584,12 +1587,12 @@ class AuthSrv(object):
|
||||||
if local:
|
if local:
|
||||||
local_only_mtp[a] = True
|
local_only_mtp[a] = True
|
||||||
|
|
||||||
local_mte = {}
|
local_mte = ODict()
|
||||||
for a in vol.flags.get("mte", "").split(","):
|
for a in vol.flags.get("mte", {}).keys():
|
||||||
local = True
|
local = True
|
||||||
all_mte[a] = True
|
all_mte[a] = True
|
||||||
local_mte[a] = True
|
local_mte[a] = True
|
||||||
for b in self.args.mte.split(","):
|
for b in self.args.mte.keys():
|
||||||
if not a or not b:
|
if not a or not b:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ from .util import (
|
||||||
HTTPCODE,
|
HTTPCODE,
|
||||||
META_NOBOTS,
|
META_NOBOTS,
|
||||||
MultipartParser,
|
MultipartParser,
|
||||||
|
ODict,
|
||||||
Pebkac,
|
Pebkac,
|
||||||
UnrecvEOF,
|
UnrecvEOF,
|
||||||
absreal,
|
absreal,
|
||||||
|
@ -1971,8 +1972,7 @@ class HttpCli(object):
|
||||||
self.log("q#: {} ({:.2f}s)".format(msg, idx.p_dur))
|
self.log("q#: {} ({:.2f}s)".format(msg, idx.p_dur))
|
||||||
|
|
||||||
order = []
|
order = []
|
||||||
cfg = self.args.mte.split(",")
|
for t in self.args.mte:
|
||||||
for t in cfg:
|
|
||||||
if t in taglist:
|
if t in taglist:
|
||||||
order.append(t)
|
order.append(t)
|
||||||
for t in taglist:
|
for t in taglist:
|
||||||
|
@ -4051,6 +4051,9 @@ class HttpCli(object):
|
||||||
ap = vn.canonical(rem)
|
ap = vn.canonical(rem)
|
||||||
return self.tx_file(ap) # is no-cache
|
return self.tx_file(ap) # is no-cache
|
||||||
|
|
||||||
|
mte = vn.flags.get("mte", {})
|
||||||
|
add_up_at = ".up_at" in mte
|
||||||
|
is_admin = self.can_admin
|
||||||
tagset: set[str] = set()
|
tagset: set[str] = set()
|
||||||
for fe in files:
|
for fe in files:
|
||||||
fn = fe["name"]
|
fn = fe["name"]
|
||||||
|
@ -4078,24 +4081,38 @@ class HttpCli(object):
|
||||||
self.log(t.format(rd, fn, min_ex()))
|
self.log(t.format(rd, fn, min_ex()))
|
||||||
break
|
break
|
||||||
|
|
||||||
fe["tags"] = {k: v for k, v in r}
|
tags = {k: v for k, v in r}
|
||||||
|
|
||||||
if self.can_admin:
|
if is_admin:
|
||||||
q = "select ip, at from up where rd=? and fn=?"
|
q = "select ip, at from up where rd=? and fn=?"
|
||||||
try:
|
try:
|
||||||
zs1, zs2 = icur.execute(q, erd_efn).fetchone()
|
zs1, zs2 = icur.execute(q, erd_efn).fetchone()
|
||||||
fe["tags"]["up_ip"] = zs1
|
if zs1:
|
||||||
fe["tags"][".up_at"] = zs2
|
tags["up_ip"] = zs1
|
||||||
|
if zs2:
|
||||||
|
tags[".up_at"] = zs2
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
elif add_up_at:
|
||||||
|
q = "select at from up where rd=? and fn=?"
|
||||||
|
try:
|
||||||
|
(zs1,) = icur.execute(q, erd_efn).fetchone()
|
||||||
|
if zs1:
|
||||||
|
tags[".up_at"] = zs1
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
_ = [tagset.add(k) for k in fe["tags"]]
|
_ = [tagset.add(k) for k in tags]
|
||||||
|
fe["tags"] = tags
|
||||||
|
|
||||||
if icur:
|
if icur:
|
||||||
mte = vn.flags.get("mte") or "up_ip,.up_at"
|
lmte = list(mte)
|
||||||
taglist = [k for k in mte.split(",") if k in tagset]
|
if self.can_admin:
|
||||||
|
lmte += ["up_ip", ".up_at"]
|
||||||
|
|
||||||
|
taglist = [k for k in lmte if k in tagset]
|
||||||
for fe in dirs:
|
for fe in dirs:
|
||||||
fe["tags"] = {}
|
fe["tags"] = ODict()
|
||||||
else:
|
else:
|
||||||
taglist = list(tagset)
|
taglist = list(tagset)
|
||||||
|
|
||||||
|
@ -4142,7 +4159,7 @@ class HttpCli(object):
|
||||||
j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
|
j2a["txt_ext"] = self.args.textfiles.replace(",", " ")
|
||||||
|
|
||||||
if "mth" in vn.flags:
|
if "mth" in vn.flags:
|
||||||
j2a["def_hcols"] = vn.flags["mth"].split(",")
|
j2a["def_hcols"] = list(vn.flags["mth"])
|
||||||
|
|
||||||
html = self.j2s(tpl, **j2a)
|
html = self.j2s(tpl, **j2a)
|
||||||
self.reply(html.encode("utf-8", "replace"))
|
self.reply(html.encode("utf-8", "replace"))
|
||||||
|
|
|
@ -39,13 +39,17 @@ from .util import (
|
||||||
FFMPEG_URL,
|
FFMPEG_URL,
|
||||||
VERSIONS,
|
VERSIONS,
|
||||||
Daemon,
|
Daemon,
|
||||||
|
DEF_MTE,
|
||||||
|
DEF_MTH,
|
||||||
Garda,
|
Garda,
|
||||||
HLog,
|
HLog,
|
||||||
HMaccas,
|
HMaccas,
|
||||||
|
ODict,
|
||||||
alltrace,
|
alltrace,
|
||||||
ansi_re,
|
ansi_re,
|
||||||
min_ex,
|
min_ex,
|
||||||
mp,
|
mp,
|
||||||
|
odfusion,
|
||||||
pybin,
|
pybin,
|
||||||
start_log_thrs,
|
start_log_thrs,
|
||||||
start_stackmon,
|
start_stackmon,
|
||||||
|
@ -433,6 +437,12 @@ class SvcHub(object):
|
||||||
zs = al.xff_src.replace(" ", "").replace(".", "\\.").replace(",", "|")
|
zs = al.xff_src.replace(" ", "").replace(".", "\\.").replace(",", "|")
|
||||||
al.xff_re = re.compile("^(?:" + zs + ")")
|
al.xff_re = re.compile("^(?:" + zs + ")")
|
||||||
|
|
||||||
|
mte = ODict.fromkeys(DEF_MTE.split(","), True)
|
||||||
|
al.mte = odfusion(mte, al.mte)
|
||||||
|
|
||||||
|
mth = ODict.fromkeys(DEF_MTH.split(","), True)
|
||||||
|
al.mth = odfusion(mth, al.mth)
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def _setlimits(self) -> None:
|
def _setlimits(self) -> None:
|
||||||
|
|
|
@ -642,10 +642,7 @@ class Up2k(object):
|
||||||
if self.stop:
|
if self.stop:
|
||||||
break
|
break
|
||||||
|
|
||||||
en: set[str] = set()
|
en = set(vol.flags.get("mte", {}))
|
||||||
if "mte" in vol.flags:
|
|
||||||
en = set(vol.flags["mte"].split(","))
|
|
||||||
|
|
||||||
self.entags[vol.realpath] = en
|
self.entags[vol.realpath] = en
|
||||||
|
|
||||||
if "e2d" in vol.flags:
|
if "e2d" in vol.flags:
|
||||||
|
|
|
@ -36,6 +36,14 @@ from .__version__ import S_BUILD_DT, S_VERSION
|
||||||
from .stolen import surrogateescape
|
from .stolen import surrogateescape
|
||||||
|
|
||||||
|
|
||||||
|
if sys.version_info >= (3, 7) or (
|
||||||
|
sys.version_info >= (3, 6) and platform.python_implementation() == "CPython"
|
||||||
|
):
|
||||||
|
ODict = dict
|
||||||
|
else:
|
||||||
|
from collections import OrderedDict as ODict
|
||||||
|
|
||||||
|
|
||||||
def _ens(want: str) -> tuple[int, ...]:
|
def _ens(want: str) -> tuple[int, ...]:
|
||||||
ret: list[int] = []
|
ret: list[int] = []
|
||||||
for v in want.split():
|
for v in want.split():
|
||||||
|
@ -261,6 +269,11 @@ EXTS["vnd.mozilla.apng"] = "png"
|
||||||
MAGIC_MAP = {"jpeg": "jpg"}
|
MAGIC_MAP = {"jpeg": "jpg"}
|
||||||
|
|
||||||
|
|
||||||
|
DEF_MTE = "circle,album,.tn,artist,title,.bpm,key,.dur,.q,.vq,.aq,vc,ac,fmt,res,.fps,ahash,vhash"
|
||||||
|
|
||||||
|
DEF_MTH = ".vq,.aq,vc,ac,fmt,res,.fps"
|
||||||
|
|
||||||
|
|
||||||
REKOBO_KEY = {
|
REKOBO_KEY = {
|
||||||
v: ln.split(" ", 1)[0]
|
v: ln.split(" ", 1)[0]
|
||||||
for ln in """
|
for ln in """
|
||||||
|
@ -1774,6 +1787,21 @@ def exclude_dotfiles(filepaths: list[str]) -> list[str]:
|
||||||
return [x for x in filepaths if not x.split("/")[-1].startswith(".")]
|
return [x for x in filepaths if not x.split("/")[-1].startswith(".")]
|
||||||
|
|
||||||
|
|
||||||
|
def odfusion(base: ODict[str, bool], oth: str) -> ODict[str, bool]:
|
||||||
|
# merge an "ordered set" (just a dict really) with another list of keys
|
||||||
|
ret = base.copy()
|
||||||
|
if oth.startswith("+"):
|
||||||
|
for k in oth[1:].split(","):
|
||||||
|
ret[k] = True
|
||||||
|
elif oth[:1] in ("-", "/"):
|
||||||
|
for k in oth[1:].split(","):
|
||||||
|
ret.pop(k, None)
|
||||||
|
else:
|
||||||
|
ret = ODict.fromkeys(oth.split(","), True)
|
||||||
|
|
||||||
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def ipnorm(ip: str) -> str:
|
def ipnorm(ip: str) -> str:
|
||||||
if ":" in ip:
|
if ":" in ip:
|
||||||
# assume /64 clients; drop 4 groups
|
# assume /64 clients; drop 4 groups
|
||||||
|
|
Loading…
Reference in a new issue