file-extension icons

global-option / volflag `ext_th` specifies
custom thumbnail for a given file extension
This commit is contained in:
ed 2025-02-13 18:32:01 +00:00
parent 685f08697a
commit 7e4702cf09
5 changed files with 41 additions and 19 deletions

View file

@ -664,6 +664,8 @@ enabling `multiselect` lets you click files to select them, and then shift-click
* `multiselect` is mostly intended for phones/tablets, but the `sel` option in the `[⚙️] settings` tab is better suited for desktop use, allowing selection by CTRL-clicking and range-selection with SHIFT-click, all without affecting regular clicking * `multiselect` is mostly intended for phones/tablets, but the `sel` option in the `[⚙️] settings` tab is better suited for desktop use, allowing selection by CTRL-clicking and range-selection with SHIFT-click, all without affecting regular clicking
* the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel` * the `sel` option can be made default globally with `--gsel` or per-volume with volflag `gsel`
to show `/icons/exe.png` as the thumbnail for all .exe files, `--ext-th=exe=/icons/exe.png` (optionally as a volflag)
config file example: config file example:
```yaml ```yaml
@ -678,6 +680,7 @@ config file example:
flags: flags:
dthumb # disable ALL thumbnails and audio transcoding dthumb # disable ALL thumbnails and audio transcoding
dvthumb # only disable video thumbnails dvthumb # only disable video thumbnails
ext-th: exe=/ico/exe.png # /ico/exe.png is the thumbnail of *.exe
th-covers: folder.png,folder.jpg,cover.png,cover.jpg # the default th-covers: folder.png,folder.jpg,cover.png,cover.jpg # the default
``` ```

View file

@ -1487,6 +1487,7 @@ def add_ui(ap, retry):
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("--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("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])") ap2.add_argument("--mpmc", metavar="URL", type=u, default="", help="change the mediaplayer-toggle mouse cursor; URL to a folder with {2..5}.png inside (or disable with [\033[32m.\033[0m])")
ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]") ap2.add_argument("--spinner", metavar="TXT", type=u, default="🌲", help="\033[33memoji\033[0m or \033[33memoji,css\033[0m Example: [\033[32m🥖,padding:0\033[0m]")
ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html") ap2.add_argument("--css-browser", metavar="L", type=u, default="", help="URL to additional CSS to include in the filebrowser html")

View file

@ -1406,7 +1406,7 @@ class AuthSrv(object):
flags[name] = True flags[name] = True
return return
zs = "mtp on403 on404 xbu xau xiu xbc xac xbr xar xbd xad xm xban" zs = "ext_th 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 [{}] = {} ({})"
@ -1999,7 +1999,7 @@ class AuthSrv(object):
# append additive args from argv to volflags # append additive args from argv to volflags
hooks = "xbu xau xiu xbc xac xbr xar xbd xad xm xban".split() hooks = "xbu xau xiu xbc xac xbr xar xbd xad xm xban".split()
for name in "mtp on404 on403".split() + hooks: for name in "ext_th mtp on404 on403".split() + hooks:
self._read_volflag( self._read_volflag(
vol.vpath, vol.flags, name, getattr(self.args, name), True vol.vpath, vol.flags, name, getattr(self.args, name), True
) )
@ -2030,6 +2030,16 @@ class AuthSrv(object):
ncmds.append(ocmd) ncmds.append(ocmd)
vol.flags[hn] = ncmds vol.flags[hn] = ncmds
ext_th = vol.flags["ext_th_d"] = {}
etv = "(?)"
try:
for etv in vol.flags.get("ext_th") or []:
k, v = etv.split("=")
ext_th[k] = v
except:
t = "WARNING: volume [/%s]: invalid value specified for ext-th: %s"
self.log(t % (vol.vpath, etv), 3)
# 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):
@ -2391,6 +2401,7 @@ class AuthSrv(object):
"have_del": not self.args.no_del, "have_del": not self.args.no_del,
"have_unpost": int(self.args.unpost), "have_unpost": int(self.args.unpost),
"have_emp": self.args.emp, "have_emp": self.args.emp,
"ext_th": vf.get("ext_th_d") or {},
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"), "sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
"sba_md": vf.get("md_sba") or "", "sba_md": vf.get("md_sba") or "",
"sba_lg": vf.get("lg_sba") or "", "sba_lg": vf.get("lg_sba") or "",

View file

@ -109,6 +109,7 @@ def vf_cmap() -> dict[str, str]:
for k in ( for k in (
"exp_lg", "exp_lg",
"exp_md", "exp_md",
"ext_th",
"mte", "mte",
"mth", "mth",
"mtp", "mtp",
@ -221,6 +222,7 @@ flagcats = {
"crop": "center-cropping (y/n/fy/fn)", "crop": "center-cropping (y/n/fy/fn)",
"th3x": "3x resolution (y/n/fy/fn)", "th3x": "3x resolution (y/n/fy/fn)",
"convt": "conversion timeout in seconds", "convt": "conversion timeout in seconds",
"ext_th=s=/b.png": "use /b.png as thumbnail for file-extension s",
}, },
"handlers\n(better explained in --help-handlers)": { "handlers\n(better explained in --help-handlers)": {
"on404=PY": "handle 404s by executing PY file", "on404=PY": "handle 404s by executing PY file",

View file

@ -6294,19 +6294,40 @@ var thegrid = (function () {
var html = [], var html = [],
svgs = new Set(), svgs = new Set(),
max_svgs = CHROME ? 500 : 5000, max_svgs = CHROME ? 500 : 5000,
need_ext = !r.thumbs || !!ext_th,
use_ext_th = r.thumbs && ext_th,
files = QSA('#files>tbody>tr>td:nth-child(2) a[id]'); files = QSA('#files>tbody>tr>td:nth-child(2) a[id]');
for (var a = 0, aa = files.length; a < aa; a++) { for (var a = 0, aa = files.length; a < aa; a++) {
var ao = files[a], var ao = files[a],
ohref = esc(ao.getAttribute('href')), ohref = esc(ao.getAttribute('href')),
href = ohref.split('?')[0], href = ohref.split('?')[0],
ext = '',
name = uricom_dec(vsplit(href)[1]), name = uricom_dec(vsplit(href)[1]),
ref = ao.getAttribute('id'), ref = ao.getAttribute('id'),
isdir = href.endsWith('/'), isdir = href.endsWith('/'),
ac = isdir ? ' class="dir"' : '', ac = isdir ? ' class="dir"' : '',
ihref = ohref; ihref = ohref;
if (r.thumbs) { if (need_ext && href != "#") {
var ar = href.split('.');
if (ar.length > 1)
ar.shift();
ar.reverse();
for (var b = 0; b < Math.min(2, ar.length); b++) {
if (ar[b].length > 7)
break;
ext = ar[b] + '.' + ext;
}
ext = (ext || 'unk.').slice(0, -1);
}
if (use_ext_th && ext_th[ext]) {
ihref = ext_th[ext];
}
else if (r.thumbs) {
ihref = addq(ihref, 'th=' + (have_webp ? 'w' : 'j')); ihref = addq(ihref, 'th=' + (have_webp ? 'w' : 'j'));
if (!r.crop) if (!r.crop)
ihref += 'f'; ihref += 'f';
@ -6319,22 +6340,6 @@ var thegrid = (function () {
ihref = SR + '/.cpr/ico/folder'; ihref = SR + '/.cpr/ico/folder';
} }
else { else {
var ar = href.split('.');
if (ar.length > 1)
ar = ar.slice(1);
ihref = '';
ar.reverse();
for (var b = 0; b < ar.length; b++) {
if (ar[b].length > 7)
break;
ihref = ar[b] + '.' + ihref;
}
if (!ihref) {
ihref = 'unk.';
}
var ext = ihref.slice(0, -1);
if (!svgs.has(ext)) { if (!svgs.has(ext)) {
if (svgs.size < max_svgs) if (svgs.size < max_svgs)
svgs.add(ext); svgs.add(ext);