mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
add hi-res thumbs (togglebtn/servercfg)
This commit is contained in:
parent
655f6d00f8
commit
33f41f3e61
|
@ -1170,7 +1170,8 @@ def add_thumbnail(ap):
|
|||
ap2.add_argument("--th-mt", metavar="CORES", type=int, default=CORES, help="num cpu cores to use for generating thumbnails")
|
||||
ap2.add_argument("--th-convt", metavar="SEC", type=float, default=60, help="conversion timeout in seconds (volflag=convt)")
|
||||
ap2.add_argument("--th-ram-max", metavar="GB", type=float, default=6, help="max memory usage (GiB) permitted by thumbnailer; not very accurate")
|
||||
ap2.add_argument("--th-no-crop", action="store_true", help="dynamic height; show full image by default (client can override in UI) (volflag=nocrop)")
|
||||
ap2.add_argument("--th-crop", metavar="TXT", type=u, default="y", help="crop thumbnails to 4:3 or keep dynamic height; client can override in UI unless force. [\033[32mfy\033[0m]=crop, [\033[32mfn\033[0m]=nocrop, [\033[32mfy\033[0m]=force-y, [\033[32mfn\033[0m]=force-n (volflag=crop)")
|
||||
ap2.add_argument("--th-x3", metavar="TXT", type=u, default="n", help="show thumbs at 3x resolution; client can override in UI unless force. [\033[32mfy\033[0m]=yes, [\033[32mfn\033[0m]=no, [\033[32mfy\033[0m]=force-yes, [\033[32mfn\033[0m]=force-no (volflag=th3x)")
|
||||
ap2.add_argument("--th-dec", metavar="LIBS", default="vips,pil,ff", help="image decoders, in order of preference")
|
||||
ap2.add_argument("--th-no-jpg", action="store_true", help="disable jpg output")
|
||||
ap2.add_argument("--th-no-webp", action="store_true", help="disable webp output")
|
||||
|
@ -1430,6 +1431,7 @@ def main(argv: Optional[list[str]] = None) -> None:
|
|||
deprecated: list[tuple[str, str]] = [
|
||||
("--salt", "--warksalt"),
|
||||
("--hdr-au-usr", "--idp-h-usr"),
|
||||
("--th-no-crop", "--th-crop=n"),
|
||||
]
|
||||
for dk, nk in deprecated:
|
||||
idx = -1
|
||||
|
|
|
@ -20,7 +20,6 @@ def vf_bmap() -> dict[str, str]:
|
|||
"no_thumb": "dthumb",
|
||||
"no_vthumb": "dvthumb",
|
||||
"no_athumb": "dathumb",
|
||||
"th_no_crop": "nocrop",
|
||||
}
|
||||
for k in (
|
||||
"dotsrch",
|
||||
|
@ -56,6 +55,8 @@ def vf_vmap() -> dict[str, str]:
|
|||
"re_maxage": "scan",
|
||||
"th_convt": "convt",
|
||||
"th_size": "thsize",
|
||||
"th_crop": "crop",
|
||||
"th_x3": "th3x",
|
||||
}
|
||||
for k in (
|
||||
"dbd",
|
||||
|
@ -172,7 +173,8 @@ flagcats = {
|
|||
"dathumb": "disables audio thumbnails (spectrograms)",
|
||||
"dithumb": "disables image thumbnails",
|
||||
"thsize": "thumbnail res; WxH",
|
||||
"nocrop": "disable center-cropping by default",
|
||||
"crop": "center-cropping (y/n/fy/fn)",
|
||||
"th3x": "3x resolution (y/n/fy/fn)",
|
||||
"convt": "conversion timeout in seconds",
|
||||
},
|
||||
"handlers\n(better explained in --help-handlers)": {
|
||||
|
|
|
@ -3973,7 +3973,8 @@ class HttpCli(object):
|
|||
"idx": e2d,
|
||||
"itag": e2t,
|
||||
"dsort": vf["sort"],
|
||||
"dfull": "nocrop" in vf,
|
||||
"dcrop": vf["crop"],
|
||||
"dth3x": vf["th3x"],
|
||||
"u2ts": vf["u2ts"],
|
||||
"lifetime": vn.flags.get("lifetime") or 0,
|
||||
"frand": bool(vn.flags.get("rand")),
|
||||
|
@ -4000,8 +4001,9 @@ class HttpCli(object):
|
|||
"sb_md": "" if "no_sb_md" in vf else (vf.get("md_sbf") or "y"),
|
||||
"readme": readme,
|
||||
"dgrid": "grid" in vf,
|
||||
"dfull": "nocrop" in vf,
|
||||
"dsort": vf["sort"],
|
||||
"dcrop": vf["crop"],
|
||||
"dth3x": vf["th3x"],
|
||||
"themes": self.args.themes,
|
||||
"turbolvl": self.args.turbo,
|
||||
"u2j": self.args.u2j,
|
||||
|
|
|
@ -31,7 +31,7 @@ class Ico(object):
|
|||
|
||||
w = 100
|
||||
h = 30
|
||||
if not self.args.th_no_crop and as_thumb:
|
||||
if "n" in self.args.th_crop and as_thumb:
|
||||
sw, sh = self.args.th_size.split("x")
|
||||
h = int(100.0 / (float(sw) / float(sh)))
|
||||
w = 100
|
||||
|
|
|
@ -97,8 +97,8 @@ def thumb_path(histpath: str, rem: str, mtime: float, fmt: str, ffa: set[str]) -
|
|||
|
||||
# spectrograms are never cropped; strip fullsize flag
|
||||
ext = rem.split(".")[-1].lower()
|
||||
if ext in ffa and fmt in ("wf", "jf"):
|
||||
fmt = fmt[:1]
|
||||
if ext in ffa and fmt[:2] in ("wf", "jf"):
|
||||
fmt = fmt.replace("f", "")
|
||||
|
||||
rd += "\n" + fmt
|
||||
h = hashlib.sha512(afsenc(rd)).digest()
|
||||
|
@ -200,9 +200,10 @@ class ThumbSrv(object):
|
|||
with self.mutex:
|
||||
return not self.nthr
|
||||
|
||||
def getres(self, vn: VFS) -> tuple[int, int]:
|
||||
def getres(self, vn: VFS, fmt: str) -> tuple[int, int]:
|
||||
mul = 3 if "3" in fmt else 1
|
||||
w, h = vn.flags["thsize"].split("x")
|
||||
return int(w), int(h)
|
||||
return int(w) * mul, int(h) * mul
|
||||
|
||||
def get(self, ptop: str, rem: str, mtime: float, fmt: str) -> Optional[str]:
|
||||
histpath = self.asrv.vfs.histtab.get(ptop)
|
||||
|
@ -364,7 +365,7 @@ class ThumbSrv(object):
|
|||
|
||||
def fancy_pillow(self, im: "Image.Image", fmt: str, vn: VFS) -> "Image.Image":
|
||||
# exif_transpose is expensive (loads full image + unconditional copy)
|
||||
res = self.getres(vn)
|
||||
res = self.getres(vn, fmt)
|
||||
r = max(*res) * 2
|
||||
im.thumbnail((r, r), resample=Image.LANCZOS)
|
||||
try:
|
||||
|
@ -379,7 +380,7 @@ class ThumbSrv(object):
|
|||
if rot in rots:
|
||||
im = im.transpose(rots[rot])
|
||||
|
||||
if fmt.endswith("f"):
|
||||
if "f" in fmt:
|
||||
im.thumbnail(res, resample=Image.LANCZOS)
|
||||
else:
|
||||
iw, ih = im.size
|
||||
|
@ -396,7 +397,7 @@ class ThumbSrv(object):
|
|||
im = self.fancy_pillow(im, fmt, vn)
|
||||
except Exception as ex:
|
||||
self.log("fancy_pillow {}".format(ex), "90")
|
||||
im.thumbnail(self.getres(vn))
|
||||
im.thumbnail(self.getres(vn, fmt))
|
||||
|
||||
fmts = ["RGB", "L"]
|
||||
args = {"quality": 40}
|
||||
|
@ -422,10 +423,10 @@ class ThumbSrv(object):
|
|||
def conv_vips(self, abspath: str, tpath: str, fmt: str, vn: VFS) -> None:
|
||||
self.wait4ram(0.2, tpath)
|
||||
crops = ["centre", "none"]
|
||||
if fmt.endswith("f"):
|
||||
if "f" in fmt:
|
||||
crops = ["none"]
|
||||
|
||||
w, h = self.getres(vn)
|
||||
w, h = self.getres(vn, fmt)
|
||||
kw = {"height": h, "size": "down", "intent": "relative"}
|
||||
|
||||
for c in crops:
|
||||
|
@ -454,12 +455,12 @@ class ThumbSrv(object):
|
|||
seek = [b"-ss", "{:.0f}".format(dur / 3).encode("utf-8")]
|
||||
|
||||
scale = "scale={0}:{1}:force_original_aspect_ratio="
|
||||
if fmt.endswith("f"):
|
||||
if "f" in fmt:
|
||||
scale += "decrease,setsar=1:1"
|
||||
else:
|
||||
scale += "increase,crop={0}:{1},setsar=1:1"
|
||||
|
||||
res = self.getres(vn)
|
||||
res = self.getres(vn, fmt)
|
||||
bscale = scale.format(*list(res)).encode("utf-8")
|
||||
# fmt: off
|
||||
cmd = [
|
||||
|
@ -594,7 +595,11 @@ class ThumbSrv(object):
|
|||
need = 0.2 + dur / coeff
|
||||
self.wait4ram(need, tpath)
|
||||
|
||||
fc = "[0:a:0]aresample=48000{},showspectrumpic=s=640x512,crop=780:544:70:50[o]"
|
||||
fc = "[0:a:0]aresample=48000{},showspectrumpic=s="
|
||||
if "3" in fmt:
|
||||
fc += "1280x1024,crop=1420:1056:70:48[o]"
|
||||
else:
|
||||
fc += "640x512,crop=780:544:70:48[o]"
|
||||
|
||||
if self.args.th_ff_swr:
|
||||
fco = ":filter_size=128:cutoff=0.877"
|
||||
|
|
|
@ -349,7 +349,8 @@ var Ls = {
|
|||
"tvt_edit": "open file in text editor$NHotkey: E\">✏️ edit",
|
||||
|
||||
"gt_msel": "enable file selection; ctrl-click a file to override$N$N<em>when active: doubleclick a file / folder to open it</em>$N$NHotkey: S\">multiselect",
|
||||
"gt_full": "show uncropped thumbnails\">full",
|
||||
"gt_crop": "center-crop thumbnails\">crop",
|
||||
"gt_3x": "hi-res thumbnails\">3x",
|
||||
"gt_zoom": "zoom",
|
||||
"gt_chop": "chop",
|
||||
"gt_sort": "sort by",
|
||||
|
@ -844,7 +845,8 @@ var Ls = {
|
|||
"tvt_edit": "redigér filen$NSnarvei: E\">✏️ endre",
|
||||
|
||||
"gt_msel": "markér filer istedenfor å åpne dem; ctrl-klikk filer for å overstyre$N$N<em>når aktiv: dobbelklikk en fil / mappe for å åpne</em>$N$NSnarvei: S\">markering",
|
||||
"gt_full": "ikke beskjær bildene\">full",
|
||||
"gt_crop": "beskjær ikonene så de passer bedre\">✂",
|
||||
"gt_3x": "høyere oppløsning på ikoner\">3x",
|
||||
"gt_zoom": "zoom",
|
||||
"gt_chop": "trim",
|
||||
"gt_sort": "sorter",
|
||||
|
@ -4515,7 +4517,9 @@ var thegrid = (function () {
|
|||
gfiles.innerHTML = (
|
||||
'<div id="ghead" class="ghead">' +
|
||||
'<a href="#" class="tgl btn" id="gridsel" tt="' + L.gt_msel + '</a> ' +
|
||||
'<a href="#" class="tgl btn" id="gridfull" tt="' + L.gt_full + '</a> <span>' + L.gt_zoom + ': ' +
|
||||
'<a href="#" class="tgl btn" id="gridcrop" tt="' + L.gt_crop + '</a> ' +
|
||||
'<a href="#" class="tgl btn" id="grid3x" tt="' + L.gt_3x + '</a> ' +
|
||||
'<span>' + L.gt_zoom + ': ' +
|
||||
'<a href="#" class="btn" z="-1.2" tt="Hotkey: shift-A">–</a> ' +
|
||||
'<a href="#" class="btn" z="1.2" tt="Hotkey: shift-D">+</a></span> <span>' + L.gt_chop + ': ' +
|
||||
'<a href="#" class="btn" l="-1" tt="' + L.gt_c1 + '">–</a> ' +
|
||||
|
@ -4530,7 +4534,7 @@ var thegrid = (function () {
|
|||
lfiles.parentNode.insertBefore(gfiles, lfiles);
|
||||
|
||||
var r = {
|
||||
'sz': clamp(fcfg_get('gridsz', 10), 4, 40),
|
||||
'sz': clamp(fcfg_get('gridsz', 10), 4, 80),
|
||||
'ln': clamp(icfg_get('gridln', 3), 1, 7),
|
||||
'isdirty': true,
|
||||
'bbox': null
|
||||
|
@ -4593,10 +4597,10 @@ var thegrid = (function () {
|
|||
|
||||
r.setdirty = function () {
|
||||
r.dirty = true;
|
||||
if (r.en) {
|
||||
if (r.en)
|
||||
loadgrid();
|
||||
}
|
||||
r.setvis();
|
||||
else
|
||||
r.setvis();
|
||||
};
|
||||
|
||||
function setln(v) {
|
||||
|
@ -4616,7 +4620,7 @@ var thegrid = (function () {
|
|||
|
||||
function setsz(v) {
|
||||
if (v !== undefined) {
|
||||
r.sz = clamp(v, 4, 40);
|
||||
r.sz = clamp(v, 4, 80);
|
||||
swrite('gridsz', r.sz);
|
||||
setTimeout(r.tippen, 20);
|
||||
}
|
||||
|
@ -4624,6 +4628,7 @@ var thegrid = (function () {
|
|||
document.documentElement.style.setProperty('--grid-sz', r.sz + 'em');
|
||||
}
|
||||
catch (ex) { }
|
||||
aligngriditems();
|
||||
}
|
||||
setsz();
|
||||
|
||||
|
@ -4776,8 +4781,11 @@ var thegrid = (function () {
|
|||
if (!r.dirty)
|
||||
return r.loadsel();
|
||||
|
||||
if (dfull != r.full && !sread('gridfull'))
|
||||
bcfg_upd_ui('gridfull', r.full = dfull);
|
||||
if (dcrop.startsWith('f') || !sread('gridcrop'))
|
||||
bcfg_upd_ui('gridcrop', r.crop = ('y' == dcrop.slice(-1)));
|
||||
|
||||
if (dth3x.startsWith('f') || !sread('grid3x'))
|
||||
bcfg_upd_ui('grid3x', r.x3 = ('y' == dth3x.slice(-1)));
|
||||
|
||||
var html = [],
|
||||
svgs = new Set(),
|
||||
|
@ -4796,8 +4804,10 @@ var thegrid = (function () {
|
|||
|
||||
if (r.thumbs) {
|
||||
ihref += '?th=' + (have_webp ? 'w' : 'j');
|
||||
if (r.full)
|
||||
ihref += 'f'
|
||||
if (!r.crop)
|
||||
ihref += 'f';
|
||||
if (r.x3)
|
||||
ihref += '3';
|
||||
if (href == "#")
|
||||
ihref = SR + '/.cpr/ico/' + (ref == 'moar' ? '++' : 'exit');
|
||||
}
|
||||
|
@ -4833,7 +4843,7 @@ var thegrid = (function () {
|
|||
|
||||
html.push('<a href="' + ohref + '" ref="' + ref +
|
||||
'"' + ac + ' ttt="' + esc(name) + '"><img style="height:' +
|
||||
(r.sz / 1.25) + 'em" onload="th_onload(this)" src="' +
|
||||
(r.sz / 1.25) + 'em" loading="lazy" onload="th_onload(this)" src="' +
|
||||
ihref + '" /><span' + ac + '>' + ao.innerHTML + '</span></a>');
|
||||
}
|
||||
ebi('ggrid').innerHTML = html.join('\n');
|
||||
|
@ -4884,8 +4894,29 @@ var thegrid = (function () {
|
|||
})[0];
|
||||
};
|
||||
|
||||
r.set_crop = function (en) {
|
||||
if (!dcrop.startsWith('f'))
|
||||
return r.setdirty();
|
||||
|
||||
r.crop = dcrop.startsWith('y');
|
||||
bcfg_upd_ui('gridcrop', r.crop);
|
||||
if (r.crop != en)
|
||||
toast.warn(10, L.ul_btnlk);
|
||||
};
|
||||
|
||||
r.set_x3 = function (en) {
|
||||
if (!dth3x.startsWith('f'))
|
||||
return r.setdirty();
|
||||
|
||||
r.x3 = dth3x.startsWith('y');
|
||||
bcfg_upd_ui('grid3x', r.x3);
|
||||
if (r.x3 != en)
|
||||
toast.warn(10, L.ul_btnlk);
|
||||
};
|
||||
|
||||
bcfg_bind(r, 'thumbs', 'thumbs', true, r.setdirty);
|
||||
bcfg_bind(r, 'full', 'gridfull', false, r.setdirty);
|
||||
bcfg_bind(r, 'crop', 'gridcrop', !dcrop.endsWith('n'), r.set_crop);
|
||||
bcfg_bind(r, 'x3', 'grid3x', dth3x.endsWith('y'), r.set_x3);
|
||||
bcfg_bind(r, 'sel', 'gridsel', false, r.loadsel);
|
||||
bcfg_bind(r, 'en', 'griden', dgrid, function (v) {
|
||||
v ? loadgrid() : r.setvis(true);
|
||||
|
@ -5575,11 +5606,15 @@ function aligngriditems() {
|
|||
if (/b/.test(themen + ''))
|
||||
totalgapwidth *= 2.8;
|
||||
|
||||
var val, st = ebi('ggrid').style;
|
||||
|
||||
if (((griditemcount * em2px) * gridsz) + totalgapwidth < gridwidth) {
|
||||
ebi('ggrid').style.justifyContent = 'left';
|
||||
val = 'left';
|
||||
} else {
|
||||
ebi('ggrid').style.justifyContent = treectl.hidden ? 'center' : 'space-between';
|
||||
val = treectl.hidden ? 'center' : 'space-between';
|
||||
}
|
||||
if (st.justifyContent != val)
|
||||
st.justifyContent = val;
|
||||
}
|
||||
onresize100.add(aligngriditems);
|
||||
|
||||
|
@ -6110,7 +6145,8 @@ var treectl = (function () {
|
|||
res.files[a].tags = {};
|
||||
|
||||
read_dsort(res.dsort);
|
||||
dfull = res.dfull;
|
||||
dcrop = res.dcrop;
|
||||
dth3x = res.dth3x;
|
||||
|
||||
srvinf = res.srvinf;
|
||||
try {
|
||||
|
|
|
@ -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 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_readme no_robots no_sb_md no_sb_lg no_scandir no_tarcmp no_thumb no_vthumb no_zip nrand nw q rand smb srch_dbg stats th_no_crop 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 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_readme no_robots no_sb_md no_sb_lg no_scandir no_tarcmp no_thumb no_vthumb no_zip nrand nw q rand smb srch_dbg stats th_x3 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_voldump re_dhash plain_ip"
|
||||
|
@ -156,7 +156,9 @@ class Cfg(Namespace):
|
|||
s_wr_sz=512 * 1024,
|
||||
sort="href",
|
||||
srch_hits=99999,
|
||||
th_crop="y",
|
||||
th_size="320x256",
|
||||
th_x3="n",
|
||||
u2sort="s",
|
||||
u2ts="c",
|
||||
unpost=600,
|
||||
|
|
Loading…
Reference in a new issue