From 927c3bce963eed324e5f90003e93af897f6ad365 Mon Sep 17 00:00:00 2001 From: ed Date: Sat, 6 Jul 2024 17:02:33 +0200 Subject: [PATCH] support descript.ion; makes listings 2% slower --- README.md | 4 +- copyparty/httpcli.py | 113 +++++++++++++++++++++++++++++++------------ copyparty/web/ui.css | 1 + 3 files changed, 86 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 68070d83..d418dca0 100644 --- a/README.md +++ b/README.md @@ -712,7 +712,7 @@ uploads can be given a lifetime, afer which they expire / self-destruct the feature must be enabled per-volume with the `lifetime` [upload rule](#upload-rules) which sets the upper limit for how long a file gets to stay on the server -clients can specify a shorter expiration time using the [up2k ui](#uploading) -- the relevant options become visible upon navigating into a folder with `lifetimes` enabled -- or by using the `life` [upload modifier](#write) +clients can specify a shorter expiration time using the [up2k ui](#uploading) -- the relevant options become visible upon navigating into a folder with `lifetimes` enabled -- or by using the `life` [upload modifier](./docs/devnotes.md#write) specifying a custom expiration time client-side will affect the timespan in which unposts are permitted, so keep an eye on the estimates in the up2k ui @@ -880,6 +880,8 @@ see [./srv/expand/](./srv/expand/) for usage and examples * files named `.prologue.html` / `.epilogue.html` will be rendered before/after directory listings unless `--no-logues` +* files named `descript.ion` / `DESCRIPT.ION` are parsed and displayed in the file listing, or as the epilogue if nonstandard + * files named `README.md` / `readme.md` will be rendered after directory listings unless `--no-readme` (but `.epilogue.html` takes precedence) * `README.md` and `*logue.html` can contain placeholder values which are replaced server-side before embedding into directory listings; see `--help-exp` diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index 41722116..344e9466 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -3007,6 +3007,43 @@ class HttpCli(object): self.log(t % (zs, req, self.req, ap), 6) return False + def _add_logues( + self, vn: VFS, abspath: str, lnames: Optional[dict[str, str]] + ) -> tuple[list[str], str]: + logues = ["", ""] + if not self.args.no_logues: + for n, fn in enumerate([".prologue.html", ".epilogue.html"]): + if lnames is not None and fn not in lnames: + continue + fn = os.path.join(abspath, fn) + if bos.path.exists(fn): + with open(fsenc(fn), "rb") as f: + logues[n] = f.read().decode("utf-8") + if "exp" in vn.flags: + logues[n] = self._expand( + logues[n], vn.flags.get("exp_lg") or [] + ) + + readme = "" + if not self.args.no_readme and not logues[1]: + if lnames is None: + fns = ["README.md", "readme.md"] + elif "readme.md" in lnames: + fns = [lnames["readme.md"]] + else: + fns = [] + + for fn in fns: + fn = os.path.join(abspath, fn) + if bos.path.isfile(fn): + with open(fsenc(fn), "rb") as f: + readme = f.read().decode("utf-8") + break + if readme and "exp" in vn.flags: + readme = self._expand(readme, vn.flags.get("exp_md") or []) + + return logues, readme + def _expand(self, txt: str, phs: list[str]) -> str: for ph in phs: if ph.startswith("hdr."): @@ -4399,29 +4436,6 @@ class HttpCli(object): tpl = "browser2" is_js = False - logues = ["", ""] - if not self.args.no_logues: - for n, fn in enumerate([".prologue.html", ".epilogue.html"]): - fn = os.path.join(abspath, fn) - if bos.path.exists(fn): - with open(fsenc(fn), "rb") as f: - logues[n] = f.read().decode("utf-8") - if "exp" in vn.flags: - logues[n] = self._expand( - logues[n], vn.flags.get("exp_lg") or [] - ) - - readme = "" - if not self.args.no_readme and not logues[1]: - for fn in ["README.md", "readme.md"]: - fn = os.path.join(abspath, fn) - if bos.path.isfile(fn): - with open(fsenc(fn), "rb") as f: - readme = f.read().decode("utf-8") - break - if readme and "exp" in vn.flags: - readme = self._expand(readme, vn.flags.get("exp_md") or []) - vf = vn.flags unlist = vf.get("unlist", "") ls_ret = { @@ -4440,8 +4454,6 @@ class HttpCli(object): "frand": bool(vn.flags.get("rand")), "unlist": unlist, "perms": perms, - "logues": logues, - "readme": readme, } cgv = { "ls0": None, @@ -4459,7 +4471,6 @@ class HttpCli(object): "have_zip": (not self.args.no_zip), "have_unpost": int(self.args.unpost), "sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"), - "readme": readme, "dgrid": "grid" in vf, "dgsel": "gsel" in vf, "dsort": vf["sort"], @@ -4482,7 +4493,6 @@ class HttpCli(object): "have_b_u": (self.can_write and self.uparam.get("b") == "u"), "sb_lg": "" if "no_sb_lg" in vf else (vf.get("lg_sbf") or "y"), "url_suf": url_suf, - "logues": logues, "title": html_escape("%s %s" % (self.args.bname, self.vpath), crlf=True), "srv_info": srv_infot, "dtheme": self.args.theme, @@ -4502,6 +4512,10 @@ class HttpCli(object): j2a["no_prism"] = True if not self.can_read and not is_dk: + logues, readme = self._add_logues(abspath, vn, None) + ls_ret["logues"] = j2a["logues"] = logues + ls_ret["readme"] = cgv["readme"] = readme + if is_ls: return self.tx_ls(ls_ret) @@ -4558,6 +4572,8 @@ class HttpCli(object): ): ls_names = exclude_dotfiles(ls_names) + lnames = {x.lower(): x for x in ls_names} + add_dk = vf.get("dk") add_fk = vf.get("fk") fk_alg = 2 if "fka" in vf else 1 @@ -4747,9 +4763,45 @@ class HttpCli(object): else: taglist = list(tagset) + logues, readme = self._add_logues(vn, abspath, lnames) + ls_ret["logues"] = j2a["logues"] = logues + ls_ret["readme"] = cgv["readme"] = readme + if not files and not dirs and not readme and not logues[0] and not logues[1]: logues[1] = "this folder is empty" + if "descript.ion" in lnames and os.path.isfile( + os.path.join(abspath, lnames["descript.ion"]) + ): + rem = [] + with open(os.path.join(abspath, lnames["descript.ion"]), "rb") as f: + for bln in [x.strip() for x in f]: + try: + if bln.endswith(b"\x04\xc2"): + # multiline comment; replace literal r"\n" with " // " + bln = bln.replace(br"\\n", b" // ")[:-2] + ln = bln.decode("utf-8", "replace") + if ln.startswith('"'): + fn, desc = ln.split('" ', 1) + fn = fn[1:] + else: + fn, desc = ln.split(" ", 1) + fe = next( + (x for x in files if x["name"].lower() == fn.lower()), None + ) + if fe: + fe["tags"]["descript.ion"] = desc + else: + t = "
  • %s %s
  • " + rem.append(t % (html_escape(fn), html_escape(desc))) + except: + pass + if "descript.ion" not in taglist: + taglist.insert(0, "descript.ion") + if rem and not logues[1]: + t = "

    descript.ion

    " + if is_ls: ls_ret["dirs"] = dirs ls_ret["files"] = files @@ -4819,10 +4871,9 @@ class HttpCli(object): self.conn.hsrv.j2[tpl] = j2env.get_template(tname) thumb = "" is_pic = is_vid = is_au = False - covernames = self.args.th_coversd - for fn in ls_names: - if fn.lower() in covernames: - thumb = fn + for fn in self.args.th_coversd: + if fn in lnames: + thumb = lnames[fn] break if og_fn: ext = og_fn.split(".")[-1].lower() diff --git a/copyparty/web/ui.css b/copyparty/web/ui.css index eecfc7cf..8cf930f7 100644 --- a/copyparty/web/ui.css +++ b/copyparty/web/ui.css @@ -184,6 +184,7 @@ html { padding: 1.5em 2em; border-width: .5em 0; } +.logue code, #modalc code, #tt code { color: #eee;