From cc4a0636953ed96dd2efa4bd2fc3d98e4cfed096 Mon Sep 17 00:00:00 2001 From: ed Date: Sun, 10 Apr 2022 22:59:45 +0200 Subject: [PATCH] thumbnails: per-decoder filetype config --- copyparty/__main__.py | 7 +++++ copyparty/httpsrv.py | 3 ++ copyparty/th_cli.py | 15 ++++++--- copyparty/th_srv.py | 73 ++++++++++++++++++------------------------- 4 files changed, 52 insertions(+), 46 deletions(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 22a9bea0..5795a4a1 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -509,6 +509,13 @@ def run_argparse(argv, formatter): ap2.add_argument("--th-clean", metavar="SEC", type=int, default=43200, help="cleanup interval; 0=disabled") ap2.add_argument("--th-maxage", metavar="SEC", type=int, default=604800, help="max folder age") ap2.add_argument("--th-covers", metavar="N,N", type=u, default="folder.png,folder.jpg,cover.png,cover.jpg", help="folder thumbnails to stat for") + # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html + # https://github.com/libvips/libvips + # ffmpeg -formats + ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="bmp,dib,gif,icns,ico,jpg,jpeg,jp2,jpx,pcx,png,pbm,pgm,ppm,pnm,sgi,tga,tif,tiff,webp,xbm,dds,xpm,heif,heifs,heic,heics,avif,avifs", help="image formats to decode using pillow") + ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="jpg,jpeg,jp2,jpx,jxl,tif,tiff,png,webp,heic,avif,fit,fits,fts,exr,pdf,svg,hdr,ppm,pgm,pfm,gif,nii,dzi", help="image formats to decode using pyvips") + ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="av1,asf,avi,flv,m4v,mkv,mjpeg,mjpg,mpg,mpeg,mpg2,mpeg2,h264,avc,mts,h265,hevc,mov,3gp,mp4,ts,mpegts,nut,ogv,ogm,rm,vob,webm,wmv", help="video formats to decode using ffmpeg") + ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,m4a,ogg,opus,flac,alac,mp3,mp2,ac3,dts,wma,ra,wav,aif,aiff,au,alaw,ulaw,mulaw,amr,gsm,ape,tak,tta,wv,mpc", help="audio formats to decode using ffmpeg") ap2 = ap.add_argument_group('transcoding options') ap2.add_argument("--no-acode", action="store_true", help="disable audio transcoding") diff --git a/copyparty/httpsrv.py b/copyparty/httpsrv.py index 1cc7bee7..7d3642ac 100644 --- a/copyparty/httpsrv.py +++ b/copyparty/httpsrv.py @@ -70,6 +70,9 @@ class HttpSrv(object): self.cb_ts = 0 self.cb_v = 0 + x = self.broker.put(True, "thumbsrv.getcfg") + self.th_cfg = x.get() + env = jinja2.Environment() env.loader = jinja2.FileSystemLoader(os.path.join(E.mod, "web")) self.j2 = { diff --git a/copyparty/th_cli.py b/copyparty/th_cli.py index 431f2f3c..8de4700f 100644 --- a/copyparty/th_cli.py +++ b/copyparty/th_cli.py @@ -4,7 +4,7 @@ from __future__ import print_function, unicode_literals import os from .util import Cooldown -from .th_srv import thumb_path, THUMBABLE, FMT_FFV, FMT_FFA, HAVE_WEBP +from .th_srv import thumb_path, HAVE_WEBP from .bos import bos @@ -18,6 +18,13 @@ class ThumbCli(object): # cache on both sides for less broker spam self.cooldown = Cooldown(self.args.th_poke) + c = hsrv.th_cfg + self.thumbable = c["thumbable"] + self.fmt_pil = c["pil"] + self.fmt_vips = c["vips"] + self.fmt_ffv = c["ffv"] + self.fmt_ffa = c["ffa"] + d = next((x for x in self.args.th_dec if x in ("vips", "pil")), None) self.can_webp = HAVE_WEBP or d == "vips" @@ -26,15 +33,15 @@ class ThumbCli(object): def get(self, ptop, rem, mtime, fmt): ext = rem.rsplit(".")[-1].lower() - if ext not in THUMBABLE: + if ext not in self.thumbable: return None - is_vid = ext in FMT_FFV + is_vid = ext in self.fmt_ffv if is_vid and self.args.no_vthumb: return None want_opus = fmt in ("opus", "caf") - is_au = ext in FMT_FFA + is_au = ext in self.fmt_ffa if is_au: if want_opus: if self.args.no_acode: diff --git a/copyparty/th_srv.py b/copyparty/th_srv.py index 53872490..c00c5331 100644 --- a/copyparty/th_srv.py +++ b/copyparty/th_srv.py @@ -54,37 +54,6 @@ try: except: HAVE_VIPS = False -# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html -# https://github.com/libvips/libvips -# ffmpeg -formats -FMT_PIL = "bmp dib gif icns ico jpg jpeg jp2 jpx pcx png pbm pgm ppm pnm sgi tga tif tiff webp xbm dds xpm" -FMT_VIPS = "jpg jpeg jp2 jpx jxl tif tiff png webp heic avif fit fits fts exr pdf svg hdr ppm pgm pfm gif nii dzi" -FMT_FFV = "av1 asf avi flv m4v mkv mjpeg mjpg mpg mpeg mpg2 mpeg2 h264 avc mts h265 hevc mov 3gp mp4 ts mpegts nut ogv ogm rm vob webm wmv" -FMT_FFA = "aac m4a ogg opus flac alac mp3 mp2 ac3 dts wma ra wav aif aiff au alaw ulaw mulaw amr gsm ape tak tta wv mpc" - -if HAVE_HEIF: - FMT_PIL += " heif heifs heic heics" - -if HAVE_AVIF: - FMT_PIL += " avif avifs" - -FMT_PIL, FMT_VIPS, FMT_FFV, FMT_FFA = [ - {x: True for x in y.split(" ") if x} for y in [FMT_PIL, FMT_VIPS, FMT_FFV, FMT_FFA] -] - - -THUMBABLE = {} - -if HAVE_PIL: - THUMBABLE.update(FMT_PIL) - -if HAVE_FFMPEG and HAVE_FFPROBE: - THUMBABLE.update(FMT_FFV) - THUMBABLE.update(FMT_FFA) - -if HAVE_VIPS: - THUMBABLE.update(FMT_VIPS) - def thumb_path(histpath, rem, mtime, fmt): # base16 = 16 = 256 @@ -113,8 +82,6 @@ def thumb_path(histpath, rem, mtime, fmt): class ThumbSrv(object): def __init__(self, hub): - global THUMBABLE - self.hub = hub self.asrv = hub.asrv self.args = hub.args @@ -155,17 +122,30 @@ class ThumbSrv(object): t.daemon = True t.start() - THUMBABLE = {} + self.fmt_pil = {x: True for x in self.args.th_r_pil.split(",")} + self.fmt_vips = {x: True for x in self.args.th_r_vips.split(",")} + self.fmt_ffv = {x: True for x in self.args.th_r_ffv.split(",")} + self.fmt_ffa = {x: True for x in self.args.th_r_ffa.split(",")} + + if not HAVE_HEIF: + for f in "heif heifs heic heics".split(" "): + self.fmt_pil.pop(f, None) + + if not HAVE_AVIF: + for f in "avif avifs".split(" "): + self.fmt_pil.pop(f, None) + + self.thumbable = {} if "pil" in self.args.th_dec: - THUMBABLE.update(FMT_PIL) + self.thumbable.update(self.fmt_pil) if "vips" in self.args.th_dec: - THUMBABLE.update(FMT_VIPS) + self.thumbable.update(self.fmt_vips) if "ff" in self.args.th_dec: - THUMBABLE.update(FMT_FFV) - THUMBABLE.update(FMT_FFA) + self.thumbable.update(self.fmt_ffv) + self.thumbable.update(self.fmt_ffa) def log(self, msg, c=0): self.log_func("thumb", msg, c) @@ -227,6 +207,15 @@ class ThumbSrv(object): return None + def getcfg(self): + return { + "thumbable": self.thumbable, + "pil": self.fmt_pil, + "vips": self.fmt_vips, + "ffv": self.fmt_ffv, + "ffa": self.fmt_ffa, + } + def worker(self): while not self.stopping: task = self.q.get() @@ -240,13 +229,13 @@ class ThumbSrv(object): for lib in self.args.th_dec: if fun: break - elif lib == "pil" and ext in FMT_PIL: + elif lib == "pil" and ext in self.fmt_pil: fun = self.conv_pil - elif lib == "vips" and ext in FMT_VIPS: + elif lib == "vips" and ext in self.fmt_vips: fun = self.conv_vips - elif lib == "ff" and ext in FMT_FFV: + elif lib == "ff" and ext in self.fmt_ffv: fun = self.conv_ffmpeg - elif lib == "ff" and ext in FMT_FFA: + elif lib == "ff" and ext in self.fmt_ffa: if tpath.endswith(".opus") or tpath.endswith(".caf"): fun = self.conv_opus else: