From 4d15dd6e17be11be841d48b3c51834a31623054e Mon Sep 17 00:00:00 2001 From: ed Date: Fri, 15 Nov 2024 21:33:37 +0000 Subject: [PATCH] cbz thumbnails --- copyparty/__main__.py | 6 +++--- copyparty/mtag.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/copyparty/__main__.py b/copyparty/__main__.py index 5d281d9d..4e9f3f50 100644 --- a/copyparty/__main__.py +++ b/copyparty/__main__.py @@ -1352,12 +1352,12 @@ def add_thumbnail(ap): # https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html # https://github.com/libvips/libvips # ffmpeg -hide_banner -demuxers | awk '/^ D /{print$2}' | while IFS= read -r x; do ffmpeg -hide_banner -h demuxer=$x; done | grep -E '^Demuxer |extensions:' - ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="avif,avifs,blp,bmp,dcx,dds,dib,emf,eps,fits,flc,fli,fpx,gif,heic,heics,heif,heifs,icns,ico,im,j2p,j2k,jp2,jpeg,jpg,jpx,pbm,pcx,pgm,png,pnm,ppm,psd,qoi,sgi,spi,tga,tif,tiff,webp,wmf,xbm,xpm", help="image formats to decode using pillow") + ap2.add_argument("--th-r-pil", metavar="T,T", type=u, default="avif,avifs,blp,bmp,cbz,dcx,dds,dib,emf,eps,fits,flc,fli,fpx,gif,heic,heics,heif,heifs,icns,ico,im,j2p,j2k,jp2,jpeg,jpg,jpx,pbm,pcx,pgm,png,pnm,ppm,psd,qoi,sgi,spi,tga,tif,tiff,webp,wmf,xbm,xpm", help="image formats to decode using pillow") ap2.add_argument("--th-r-vips", metavar="T,T", type=u, default="avif,exr,fit,fits,fts,gif,hdr,heic,jp2,jpeg,jpg,jpx,jxl,nii,pfm,pgm,png,ppm,svg,tif,tiff,webp", help="image formats to decode using pyvips") - ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg") + ap2.add_argument("--th-r-ffi", metavar="T,T", type=u, default="apng,avif,avifs,bmp,cbz,dds,dib,fit,fits,fts,gif,hdr,heic,heics,heif,heifs,icns,ico,jp2,jpeg,jpg,jpx,jxl,pbm,pcx,pfm,pgm,png,pnm,ppm,psd,qoi,sgi,tga,tif,tiff,webp,xbm,xpm", help="image formats to decode using ffmpeg") ap2.add_argument("--th-r-ffv", metavar="T,T", type=u, default="3gp,asf,av1,avc,avi,flv,h264,h265,hevc,m4v,mjpeg,mjpg,mkv,mov,mp4,mpeg,mpeg2,mpegts,mpg,mpg2,mts,nut,ogm,ogv,rm,ts,vob,webm,wmv", help="video formats to decode using ffmpeg") ap2.add_argument("--th-r-ffa", metavar="T,T", type=u, default="aac,ac3,aif,aiff,alac,alaw,amr,apac,ape,au,bonk,dfpwm,dts,flac,gsm,ilbc,it,itgz,itxz,itz,m4a,mdgz,mdxz,mdz,mo3,mod,mp2,mp3,mpc,mptm,mt2,mulaw,ogg,okt,opus,ra,s3m,s3gz,s3xz,s3z,tak,tta,ulaw,wav,wma,wv,xm,xmgz,xmxz,xmz,xpk", help="audio formats to decode using ffmpeg") - ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz", help="audio formats to decompress before passing to ffmpeg") + ap2.add_argument("--au-unpk", metavar="E=F.C", type=u, default="mdz=mod.zip, mdgz=mod.gz, mdxz=mod.xz, s3z=s3m.zip, s3gz=s3m.gz, s3xz=s3m.xz, xmz=xm.zip, xmgz=xm.gz, xmxz=xm.xz, itz=it.zip, itgz=it.gz, itxz=it.xz, cbz=jpg.cbz", help="audio/image formats to decompress before passing to ffmpeg") def add_transcoding(ap): diff --git a/copyparty/mtag.py b/copyparty/mtag.py index 99868e40..8bbd969c 100644 --- a/copyparty/mtag.py +++ b/copyparty/mtag.py @@ -4,6 +4,7 @@ from __future__ import print_function, unicode_literals import argparse import json import os +import re import shutil import subprocess as sp import sys @@ -62,6 +63,9 @@ def have_ff(scmd: str) -> bool: HAVE_FFMPEG = not os.environ.get("PRTY_NO_FFMPEG") and have_ff("ffmpeg") HAVE_FFPROBE = not os.environ.get("PRTY_NO_FFPROBE") and have_ff("ffprobe") +CBZ_PICS = set("png jpg jpeg gif bmp tga tif tiff webp avif".split()) +CBZ_01 = re.compile(r"(^|[^0-9v])0+[01]\b") + class MParser(object): def __init__(self, cmdline: str) -> None: @@ -126,6 +130,7 @@ def au_unpk( log: "NamedLogger", fmt_map: dict[str, str], abspath: str, vn: Optional[VFS] = None ) -> str: ret = "" + maxsz = 1024 * 1024 * 64 try: ext = abspath.split(".")[-1].lower() au, pk = fmt_map[ext].split(".") @@ -148,17 +153,41 @@ def au_unpk( zf = zipfile.ZipFile(abspath, "r") zil = zf.infolist() zil = [x for x in zil if x.filename.lower().split(".")[-1] == au] + if not zil: + raise Exception("no audio inside zip") fi = zf.open(zil[0]) + elif pk == "cbz": + import zipfile + + zf = zipfile.ZipFile(abspath, "r") + znil = [(x.filename.lower(), x) for x in zf.infolist()] + nf = len(znil) + znil = [x for x in znil if x[0].split(".")[-1] in CBZ_PICS] + znil = [x for x in znil if "cover" in x[0]] or znil + znil = [x for x in znil if CBZ_01.search(x[0])] or znil + t = "cbz: %d files, %d hits" % (nf, len(znil)) + if znil: + t += ", using " + znil[0][1].filename + log(t) + if not znil: + raise Exception("no images inside cbz") + fi = zf.open(znil[0][1]) + else: raise Exception("unknown compression %s" % (pk,)) + fsz = 0 with os.fdopen(fd, "wb") as fo: while True: buf = fi.read(32768) if not buf: break + fsz += len(buf) + if fsz > maxsz: + raise Exception("zipbomb defused") + fo.write(buf) return ret