pregen html_head when static

This commit is contained in:
ed 2025-09-29 21:47:53 +00:00
parent d08e872062
commit 435db14798
16 changed files with 50 additions and 20 deletions

View file

@ -1776,6 +1776,7 @@ def add_ui(ap, retry: int):
ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include in the filebrowser html") ap2.add_argument("--js-browser", metavar="L", type=u, default="", help="URL to additional JS to include in the filebrowser html")
ap2.add_argument("--js-other", metavar="L", type=u, default="", help="URL to additional JS to include in all other pages") ap2.add_argument("--js-other", metavar="L", type=u, default="", help="URL to additional JS to include in all other pages")
ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages (except for basic-browser); can be @PATH to send the contents of a file at PATH, and/or begin with %% to render as jinja2 template (volflag=html_head)") ap2.add_argument("--html-head", metavar="TXT", type=u, default="", help="text to append to the <head> of all HTML pages (except for basic-browser); can be @PATH to send the contents of a file at PATH, and/or begin with %% to render as jinja2 template (volflag=html_head)")
ap2.add_argument("--html-head-s", metavar="T", type=u, default="", help="text to append to the <head> of all HTML pages (except for basic-browser); similar to (and can be combined with) --html-head but only accepts static text (volflag=html_head_s)")
ap2.add_argument("--ih", action="store_true", help="if a folder contains index.html, show that instead of the directory listing by default (can be changed in the client settings UI, or add ?v to URL for override)") ap2.add_argument("--ih", action="store_true", help="if a folder contains index.html, show that instead of the directory listing by default (can be changed in the client settings UI, or add ?v to URL for override)")
ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext") ap2.add_argument("--textfiles", metavar="CSV", type=u, default="txt,nfo,diz,cue,readme", help="file extensions to present as plaintext")
ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)") ap2.add_argument("--txt-max", metavar="KiB", type=int, default=64, help="max size of embedded textfiles on ?doc= (anything bigger will be lazy-loaded by JS)")

View file

@ -2493,6 +2493,31 @@ 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)
zs = str(vol.flags.get("html_head") or "")
if zs and zs[:1] in "%@":
vol.flags["html_head_d"] = zs
head_s = str(vol.flags.get("html_head_s") or "")
else:
zs2 = str(vol.flags.get("html_head_s") or "")
if zs2 and zs:
head_s = "%s\n%s\n" % (zs2.strip(), zs.strip())
else:
head_s = zs2 or zs
if head_s and not head_s.endswith("\n"):
head_s += "\n"
if "norobots" in vol.flags:
head_s += META_NOBOTS
if head_s:
vol.flags["html_head_s"] = head_s
else:
vol.flags.pop("html_head_s", None)
if not vol.flags.get("html_head_d"):
vol.flags.pop("html_head_d", None)
vol.check_landmarks() vol.check_landmarks()
# d2d drops all database features for a volume # d2d drops all database features for a volume

View file

@ -91,6 +91,7 @@ def vf_vmap() -> dict[str, str]:
"forget_ip", "forget_ip",
"hsortn", "hsortn",
"html_head", "html_head",
"html_head_s",
"lg_sbf", "lg_sbf",
"md_sbf", "md_sbf",
"lg_sba", "lg_sba",
@ -303,6 +304,7 @@ flagcats = {
"hsortn": "number of sort-rules to add to media URLs", "hsortn": "number of sort-rules to add to media URLs",
"unlist": "dont list files matching REGEX", "unlist": "dont list files matching REGEX",
"html_head=TXT": "includes TXT in the <head>, or @PATH for file at PATH", "html_head=TXT": "includes TXT in the <head>, or @PATH for file at PATH",
"html_head_s=TXT": "additional static text in the html <head>",
"tcolor=#fc0": "theme color (a hint for webbrowsers, discord, etc.)", "tcolor=#fc0": "theme color (a hint for webbrowsers, discord, etc.)",
"nodirsz": "don't show total folder size", "nodirsz": "don't show total folder size",
"du_who=all": "show disk-usage info to everyone", "du_who=all": "show disk-usage info to everyone",

View file

@ -286,10 +286,9 @@ class HttpCli(object):
zs += "&" if "?" in zs else "?" zs += "&" if "?" in zs else "?"
ka["js"] = zs ka["js"] = zs
zso = self.vn.flags.get("html_head") if "html_head_d" in self.vn.flags:
if zso:
ka["this"] = self ka["this"] = self
self._build_html_head(zso, ka) self._build_html_head(ka)
ka["html_head"] = self.html_head ka["html_head"] = self.html_head
return tpl.render(**ka) # type: ignore return tpl.render(**ka) # type: ignore
@ -758,9 +757,11 @@ class HttpCli(object):
self.s.settimeout(self.args.s_tbody or None) self.s.settimeout(self.args.s_tbody or None)
if "norobots" in vn.flags: if "norobots" in vn.flags:
self.html_head += META_NOBOTS
self.out_headers["X-Robots-Tag"] = "noindex, nofollow" self.out_headers["X-Robots-Tag"] = "noindex, nofollow"
if "html_head_s" in vn.flags:
self.html_head += vn.flags["html_head_s"]
try: try:
cors_k = self._cors() cors_k = self._cors()
if self.mode in ("GET", "HEAD"): if self.mode in ("GET", "HEAD"):
@ -931,8 +932,8 @@ class HttpCli(object):
no304 = self.cookies.get("no304") no304 = self.cookies.get("no304")
return no304 == "y" or (self.args.no304 == 2 and no304 != "n") return no304 == "y" or (self.args.no304 == 2 and no304 != "n")
def _build_html_head(self, maybe_html: Any, kv: dict[str, Any]) -> None: def _build_html_head(self, kv: dict[str, Any]) -> None:
html = str(maybe_html) html = str(self.vn.flags["html_head_d"])
is_jinja = html[:2] in "%@%" is_jinja = html[:2] in "%@%"
if is_jinja: if is_jinja:
html = html.replace("%", "", 1) html = html.replace("%", "", 1)
@ -5032,10 +5033,9 @@ class HttpCli(object):
zs += "&" if "?" in zs else "?" zs += "&" if "?" in zs else "?"
targs["js"] = zs targs["js"] = zs
zfv = self.vn.flags.get("html_head") if "html_head_d" in self.vn.flags:
if zfv:
targs["this"] = self targs["this"] = self
self._build_html_head(zfv, targs) self._build_html_head(targs)
targs["html_head"] = self.html_head targs["html_head"] = self.html_head
zs = template.render(**targs).encode("utf-8", "replace") zs = template.render(**targs).encode("utf-8", "replace")

View file

@ -1142,7 +1142,7 @@ class Up2k(object):
ft = "\033[0;32m{}{:.0}" ft = "\033[0;32m{}{:.0}"
ff = "\033[0;35m{}{:.0}" ff = "\033[0;35m{}{:.0}"
fv = "\033[0;36m{}:\033[90m{}" fv = "\033[0;36m{}:\033[90m{}"
zs = "bcasechk du_iwho ext_th_d html_head put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v" zs = "bcasechk du_iwho ext_th_d html_head html_head_d html_head_s put_name2 mv_re_r mv_re_t rm_re_r rm_re_t srch_re_dots srch_re_nodot zipmax zipmaxn_v zipmaxs_v"
fx = set(zs.split()) fx = set(zs.split())
fd = vf_bmap() fd = vf_bmap()
fd.update(vf_cmap()) fd.update(vf_cmap())

View file

@ -9,7 +9,7 @@
<meta name="theme-color" content="#{{ tcolor }}"> <meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/browser.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/browser.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
{%- if css %} {%- if css %}
<link rel="stylesheet" media="screen" href="{{ css }}_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ css }}_={{ ts }}">
{%- endif %} {%- endif %}

View file

@ -10,7 +10,7 @@
<meta name="theme-color" content="#{{ tcolor }}"> <meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>

View file

@ -9,7 +9,7 @@
{%- if edit %} {%- if edit %}
<link rel="stylesheet" href="{{ r }}/.cpr/md2.css?_={{ ts }}"> <link rel="stylesheet" href="{{ r }}/.cpr/md2.css?_={{ ts }}">
{%- endif %} {%- endif %}
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>
<div id="mn"></div> <div id="mn"></div>

View file

@ -8,7 +8,7 @@
<link rel="stylesheet" href="{{ r }}/.cpr/mde.css?_={{ ts }}"> <link rel="stylesheet" href="{{ r }}/.cpr/mde.css?_={{ ts }}">
<link rel="stylesheet" href="{{ r }}/.cpr/deps/mini-fa.css?_={{ ts }}"> <link rel="stylesheet" href="{{ r }}/.cpr/deps/mini-fa.css?_={{ ts }}">
<link rel="stylesheet" href="{{ r }}/.cpr/deps/easymde.css?_={{ ts }}"> <link rel="stylesheet" href="{{ r }}/.cpr/deps/easymde.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>
<div id="mw"> <div id="mw">

View file

@ -8,7 +8,7 @@
<meta name="viewport" content="width=device-width, initial-scale=0.8"> <meta name="viewport" content="width=device-width, initial-scale=0.8">
<meta name="theme-color" content="#{{ tcolor }}"> <meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/msg.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/msg.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>

View file

@ -10,7 +10,7 @@
<meta name="theme-color" content="#{{ tcolor }}"> <meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/rups.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/rups.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>

View file

@ -10,7 +10,7 @@
<meta name="theme-color" content="#{{ tcolor }}"> <meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/shares.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>

View file

@ -9,7 +9,7 @@
<meta name="theme-color" content="#{{ tcolor }}"> <meta name="theme-color" content="#{{ tcolor }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>

View file

@ -10,7 +10,7 @@
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/splash.css?_={{ ts }}">
<link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}"> <link rel="stylesheet" media="screen" href="{{ r }}/.cpr/ui.css?_={{ ts }}">
<style>ul{padding-left:1.3em}li{margin:.4em 0}.txa{float:right;margin:0 0 0 1em}</style> <style>ul{padding-left:1.3em}li{margin:.4em 0}.txa{float:right;margin:0 0 0 1em}</style>
{{- html_head }} {{ html_head }}
</head> </head>
<body> <body>

View file

@ -64,6 +64,8 @@ if you give it the value `@ASDF` it will try to open a file named ASDF and send
if the value starts with `%` it will assume a jinja2 template and expand it; the template has access to the `HttpCli` object through a property named `this` as well as everything in `j2a` and the stuff added by `self.j2s`; see [browser.html](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/web/browser.html) for inspiration or look under the hood in [httpcli.py](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/httpcli.py) if the value starts with `%` it will assume a jinja2 template and expand it; the template has access to the `HttpCli` object through a property named `this` as well as everything in `j2a` and the stuff added by `self.j2s`; see [browser.html](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/web/browser.html) for inspiration or look under the hood in [httpcli.py](https://github.com/9001/copyparty/blob/hovudstraum/copyparty/httpcli.py)
there is also `--html-head-s` and volflag `html_head_s` to add a plain static bit of text, possibly in addition to `--html-head`
# translations # translations

View file

@ -164,7 +164,7 @@ class Cfg(Namespace):
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" 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()}) ka.update(**{k: 0 for k in ex.split()})
ex = "ah_alg bname chdir chmod_f chpw_db doctitle df exit favico ipa html_head idp_login idp_logout lg_sba lg_sbf 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 shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR" ex = "ah_alg bname chdir chmod_f chpw_db doctitle df exit favico ipa html_head html_head_d html_head_s idp_login idp_logout lg_sba lg_sbf 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 shr tcolor textfiles txt_eol unlist vname xff_src zipmaxt R RS SR"
ka.update(**{k: "" for k in ex.split()}) ka.update(**{k: "" for k in ex.split()})
ex = "ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url spinner" ex = "ban_403 ban_404 ban_422 ban_pw ban_pwc ban_url spinner"