From 36f2c446af64aeca0ad015562cd9e3fa2a94e736 Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 3 May 2024 00:11:40 +0000 Subject: [PATCH] opengraph stuff: * template-based title formatting * picture embeds are no longer ant-sized * `--og-color` sets accent color; default #333 * `--og-s-title` forces default title, ignoring e2t * add a music indicator to song titles because discord doesn't --- README.md | 4 ++-- copyparty/__main__.py | 7 ++++++- copyparty/authsrv.py | 5 +++++ copyparty/cfg.py | 5 +++++ copyparty/httpcli.py | 33 ++++++++++++++++++++++++++------- copyparty/web/browser.html | 2 +- copyparty/web/md.html | 2 +- copyparty/web/mde.html | 2 +- copyparty/web/msg.html | 2 +- copyparty/web/splash.html | 2 +- copyparty/web/svcs.html | 2 +- tests/util.py | 4 ++-- 12 files changed, 52 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 9adf38db..46cfa25f 100644 --- a/README.md +++ b/README.md @@ -1082,9 +1082,9 @@ note that this disables hotlinking because the opengraph spec demands it; to sne you can also hotlink files regardless by appending `?raw` to the url -if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object) +NOTE: because discord (and maybe others) strip query args such as `?raw` in opengraph tags, any links which require a filekey or dirkey will not work -because discord (and maybe others) strip query args such as `?raw`, opengraph is incompatible with filekeys and dirkeys +if you want to entirely replace the copyparty response with your own jinja2 template, give the template filepath to `--og-tpl` or volflag `og_tpl` (all members of `HttpCli` are available through the `this` object) ## file indexing diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 57da50f9..c83cd482 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1264,9 +1264,14 @@ def add_og(ap): ap2.add_argument("--og-tpl", metavar="PATH", type=u, default="", help="do not return the regular copyparty html, but instead load the jinja2 template at \033[33mPATH\033[0m (if path contains 'EXT' then EXT will be replaced with the requested file's extension) (volflag=og_tpl)") ap2.add_argument("--og-no-head", action="store_true", help="do not automatically add OG entries into (useful if you're doing this yourself in a template or such) (volflag=og_no_head)") ap2.add_argument("--og-th", metavar="FMT", type=u, default="jf3", help="thumbnail format; j=jpeg, jf=jpeg-uncropped, jf3=jpeg-uncropped-large, w=webm, ... (volflag=og_th)") - ap2.add_argument("--og-title", metavar="TXT", type=u, default="", help="fallback title if there is nothing in the \033[33m-e2t\033[0m database (volflag=og_site)") + ap2.add_argument("--og-title", metavar="TXT", type=u, default="", help="fallback title if there is nothing in the \033[33m-e2t\033[0m database (volflag=og_title)") + ap2.add_argument("--og-title-a", metavar="T", type=u, default="🎵 {{ artist }} - {{ title }}", help="audio title format; takes any metadata key (volflag=og_title_a)") + ap2.add_argument("--og-title-v", metavar="T", type=u, default="{{ title }}", help="video title format; takes any metadata key (volflag=og_title_v)") + ap2.add_argument("--og-title-i", metavar="T", type=u, default="{{ title }}", help="image title format; takes any metadata key (volflag=og_title_i)") + ap2.add_argument("--og-s-title", action="store_true", help="force default title; do not read from tags (volflag=og_s_title)") ap2.add_argument("--og-desc", metavar="TXT", type=u, default="", help="description text; same for all files, disable with [\033[32m-\033[0m] (volflag=og_desc)") ap2.add_argument("--og-site", metavar="TXT", type=u, default="", help="sitename; defaults to \033[33m--name\033[0m, disable with [\033[32m-\033[0m] (volflag=og_site)") + ap2.add_argument("--tcolor", metavar="RGB", type=u, default="333", help="accent color (3 or 6 hex digits); may also affect safari and/or android-chrome (volflag=tcolor)") ap2.add_argument("--uqe", action="store_true", help="query-string parceling; translate a request for \033[33m/foo/.uqe/BASE64\033[0m into \033[33m/foo?TEXT\033[0m, or \033[33m/foo/?TEXT\033[0m if the first character in \033[33mTEXT\033[0m is a slash. Automatically enabled for \033[33m--og\033[0m") diff --git a/copyparty/authsrv.py b/copyparty/authsrv.py index e2a95aa3..e6b35a0c 100644 --- a/copyparty/authsrv.py +++ b/copyparty/authsrv.py @@ -1442,6 +1442,7 @@ class AuthSrv(object): elif "" not in mount: # there's volumes but no root; make root inaccessible vfs = VFS(self.log_func, "", "", AXS(), {}) + vfs.flags["tcolor"] = self.args.tcolor vfs.flags["d2d"] = True maxdepth = 0 @@ -1780,6 +1781,10 @@ class AuthSrv(object): if vol.flags.get("og"): self.args.uqe = True + zs = str(vol.flags.get("tcolor", "")) + if len(zs) == 3: # fc5 => ffcc55 + vol.flags["tcolor"] = "".join([x*2 for x in zs]) + for k1, k2 in IMPLICATIONS: if k1 in vol.flags: vol.flags[k2] = True diff --git a/copyparty/cfg.py b/copyparty/cfg.py index a5da4dcc..d8f42a0e 100644 --- a/copyparty/cfg.py +++ b/copyparty/cfg.py @@ -41,6 +41,7 @@ def vf_bmap() -> dict[str, str]: "no_sb_lg", "og", "og_no_head", + "og_s_title", "rand", "xdev", "xlink", @@ -71,11 +72,15 @@ def vf_vmap() -> dict[str, str]: "og_site", "og_th", "og_title", + "og_title_a", + "og_title_v", + "og_title_i", "og_tpl", "og_ua", "mv_retry", "rm_retry", "sort", + "tcolor", "unlist", "u2abort", "u2ts", diff --git a/copyparty/httpcli.py b/copyparty/httpcli.py index ff82daa7..7fc3c570 100644 --- a/copyparty/httpcli.py +++ b/copyparty/httpcli.py @@ -220,6 +220,7 @@ class HttpCli(object): ka["favico"] = self.args.favico ka["s_name"] = self.args.bname ka["s_doctitle"] = self.args.doctitle + ka["tcolor"] = self.vn.flags["tcolor"] zso = self.vn.flags.get("html_head") if zso: @@ -4807,13 +4808,11 @@ class HttpCli(object): if not vn.flags.get("og_no_head"): ogh = {"twitter:card": "summary"} + title = str(vn.flags.get("og_title") or "") + if thumb: ogh["og:image"] = j2a["og_thumb"] - zso = vn.flags.get("og_title") - if zso: - ogh["og:title"] = str(zso) - zso = vn.flags.get("og_desc") or "" if zso != "-": ogh["og:description"] = str(zso) @@ -4824,15 +4823,16 @@ class HttpCli(object): tagmap = {} if is_au: + title = str(vn.flags.get("og_title_a") or "") ogh["og:type"] = "music.song" ogh["og:audio"] = j2a["og_raw"] tagmap = { - "title": "og:title", "artist": "og:music:musician", "album": "og:music:album", ".dur": "og:music:duration", } elif is_vid: + title = str(vn.flags.get("og_title_v") or "") ogh["og:type"] = "video.other" ogh["og:video"] = j2a["og_raw"] tagmap = { @@ -4840,8 +4840,25 @@ class HttpCli(object): ".dur": "og:video:duration", } elif is_pic: - ogh["og:type"] = "video.other" - ogh["og:image"] = j2a["og_raw"] + title = str(vn.flags.get("og_title_i") or "") + ogh["og:type"] = "website" + ogh["twitter:card"] = "photo" + ogh["twitter:image:src"] = ogh["og:image"] = j2a["og_raw"] + + try: + for k, v in file["tags"].items(): + zs = "{{ %s }}" % (k,) + title = title.replace(zs, str(v)) + except: + pass + title = re.sub(r"\{\{ [^}]+ \}\}", "", title) + while title.startswith(" - "): + title = title[3:] + while title.endswith(" - "): + title = title[:3] + + if vn.flags.get("og_s_title"): + title = str(vn.flags.get("og_title") or "") for tag, hname in tagmap.items(): try: @@ -4852,6 +4869,8 @@ class HttpCli(object): except: pass + ogh["og:title"] = title + zs = '\t' oghs = [zs % (k, html_escape(str(v))) for k, v in ogh.items()] zs = self.html_head + "\n%s\n" % ("\n".join(oghs),) diff --git a/copyparty/web/browser.html b/copyparty/web/browser.html index 76f6fcca..e479fa0c 100644 --- a/copyparty/web/browser.html +++ b/copyparty/web/browser.html @@ -6,7 +6,7 @@ {{ title }} - + {{ html_head }} diff --git a/copyparty/web/md.html b/copyparty/web/md.html index 1ea1909f..78ab505b 100644 --- a/copyparty/web/md.html +++ b/copyparty/web/md.html @@ -3,7 +3,7 @@ 📝 {{ title }} - + {%- if edit %} diff --git a/copyparty/web/mde.html b/copyparty/web/mde.html index 31618851..e95508ba 100644 --- a/copyparty/web/mde.html +++ b/copyparty/web/mde.html @@ -3,7 +3,7 @@ 📝 {{ title }} - + diff --git a/copyparty/web/msg.html b/copyparty/web/msg.html index 910bc3ae..002b6558 100644 --- a/copyparty/web/msg.html +++ b/copyparty/web/msg.html @@ -6,7 +6,7 @@ {{ s_doctitle }} - + {{ html_head }} diff --git a/copyparty/web/splash.html b/copyparty/web/splash.html index 1828afec..840a05a2 100644 --- a/copyparty/web/splash.html +++ b/copyparty/web/splash.html @@ -6,7 +6,7 @@ {{ s_doctitle }} - + {{ html_head }} diff --git a/copyparty/web/svcs.html b/copyparty/web/svcs.html index b560b379..6d25b9c9 100644 --- a/copyparty/web/svcs.html +++ b/copyparty/web/svcs.html @@ -6,7 +6,7 @@ {{ s_doctitle }} - + diff --git a/tests/util.py b/tests/util.py index 01161e28..d9944b70 100644 --- a/tests/util.py +++ b/tests/util.py @@ -110,7 +110,7 @@ class Cfg(Namespace): def __init__(self, a=None, v=None, c=None, **ka0): ka = {} - ex = "daw dav_auth dav_inf dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid hardlink ih ihead magic never_symlink nid nih no_acode no_athumb no_dav no_dedup no_del no_dupe no_lifetime no_logues no_mv no_pipe no_readme no_robots no_sb_md no_sb_lg no_scandir no_tarcmp no_thumb no_vthumb no_zip nrand nw og og_no_head q rand smb srch_dbg stats uqe vague_403 vc ver xdev xlink xvol" + ex = "daw dav_auth dav_inf dav_mac dav_rt e2d e2ds e2dsa e2t e2ts e2tsr e2v e2vu e2vp early_ban ed emp exp force_js getmod grid hardlink ih ihead magic never_symlink nid nih no_acode no_athumb no_dav no_dedup no_del no_dupe no_lifetime no_logues no_mv no_pipe no_readme no_robots no_sb_md no_sb_lg no_scandir no_tarcmp no_thumb no_vthumb no_zip nrand nw og og_no_head og_s_title q rand smb srch_dbg stats uqe vague_403 vc ver xdev xlink xvol" ka.update(**{k: False for k in ex.split()}) ex = "dotpart dotsrch no_dhash no_fastboot no_rescan no_sendfile no_snap no_voldump re_dhash plain_ip" @@ -128,7 +128,7 @@ class Cfg(Namespace): ex = "db_act df k304 loris re_maxage rproxy rsp_jtr rsp_slp s_wr_slp snap_wri theme themes turbo" ka.update(**{k: 0 for k in ex.split()}) - ex = "ah_alg bname doctitle exit favico idp_h_usr html_head lg_sbf log_fk md_sbf name og_desc og_site og_th og_title textfiles unlist vname R RS SR" + ex = "ah_alg bname doctitle exit favico idp_h_usr html_head lg_sbf log_fk md_sbf name og_desc og_site og_th og_title og_title_a og_title_v og_title_i tcolor textfiles unlist vname R RS SR" ka.update(**{k: "" for k in ex.split()}) ex = "grp on403 on404 xad xar xau xban xbd xbr xbu xiu xm"