mirror of
				https://github.com/9001/copyparty.git
				synced 2025-11-04 05:43:17 +00:00 
			
		
		
		
	crop thumbs for AESTHETICS
This commit is contained in:
		@@ -252,7 +252,8 @@ def run_argparse(argv, formatter):
 | 
				
			|||||||
    ap2 = ap.add_argument_group('thumbnail options')
 | 
					    ap2 = ap.add_argument_group('thumbnail options')
 | 
				
			||||||
    ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails")
 | 
					    ap2.add_argument("--no-thumb", action="store_true", help="disable all thumbnails")
 | 
				
			||||||
    ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails")
 | 
					    ap2.add_argument("--no-vthumb", action="store_true", help="disable video thumbnails")
 | 
				
			||||||
    ap2.add_argument("--thumbsz", metavar="WxH", default="352x352", help="thumbnail res")
 | 
					    ap2.add_argument("--th-size", metavar="WxH", default="320x256", help="thumbnail res")
 | 
				
			||||||
 | 
					    ap2.add_argument("--th-nocrop", action="store_true", help="dynamic height (no crop)")
 | 
				
			||||||
    ap2.add_argument("--th-poke", metavar="SEC", type=int, default=300, help="activity labeling cooldown")
 | 
					    ap2.add_argument("--th-poke", metavar="SEC", type=int, default=300, help="activity labeling cooldown")
 | 
				
			||||||
    ap2.add_argument("--th-clean", metavar="SEC", type=int, default=1800, help="cleanup interval")
 | 
					    ap2.add_argument("--th-clean", metavar="SEC", type=int, default=1800, help="cleanup interval")
 | 
				
			||||||
    ap2.add_argument("--th-maxage", metavar="SEC", type=int, default=604800, help="max folder age")
 | 
					    ap2.add_argument("--th-maxage", metavar="SEC", type=int, default=604800, help="max folder age")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1225,7 +1225,7 @@ class HttpCli(object):
 | 
				
			|||||||
        if len(ext) > 11:
 | 
					        if len(ext) > 11:
 | 
				
			||||||
            ext = "⋯" + ext[-9:]
 | 
					            ext = "⋯" + ext[-9:]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        mime, ico = self.ico.get(ext)
 | 
					        mime, ico = self.ico.get(ext, not exact)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dt = datetime.utcfromtimestamp(E.t0)
 | 
					        dt = datetime.utcfromtimestamp(E.t0)
 | 
				
			||||||
        lm = dt.strftime("%a, %d %b %Y %H:%M:%S GMT")
 | 
					        lm = dt.strftime("%a, %d %b %Y %H:%M:%S GMT")
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,7 +39,7 @@ class HttpConn(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        enth = HAVE_PIL and not self.args.no_thumb
 | 
					        enth = HAVE_PIL and not self.args.no_thumb
 | 
				
			||||||
        self.thumbcli = ThumbCli(hsrv.broker) if enth else None
 | 
					        self.thumbcli = ThumbCli(hsrv.broker) if enth else None
 | 
				
			||||||
        self.ico = Ico()
 | 
					        self.ico = Ico(self.args)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.t0 = time.time()
 | 
					        self.t0 = time.time()
 | 
				
			||||||
        self.nbyte = 0
 | 
					        self.nbyte = 0
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -5,10 +5,10 @@ from .__init__ import PY2
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Ico(object):
 | 
					class Ico(object):
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self, args):
 | 
				
			||||||
        pass
 | 
					        self.args = args
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get(self, ext):
 | 
					    def get(self, ext, as_thumb):
 | 
				
			||||||
        """placeholder to make thumbnails not break"""
 | 
					        """placeholder to make thumbnails not break"""
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        h = hashlib.md5(ext.encode("utf-8")).digest()[:2]
 | 
					        h = hashlib.md5(ext.encode("utf-8")).digest()[:2]
 | 
				
			||||||
@@ -21,14 +21,19 @@ class Ico(object):
 | 
				
			|||||||
        c = [int(x * 255) for x in c]
 | 
					        c = [int(x * 255) for x in c]
 | 
				
			||||||
        c = "".join(["{:02x}".format(x) for x in c])
 | 
					        c = "".join(["{:02x}".format(x) for x in c])
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        h = 30
 | 
				
			||||||
 | 
					        if not self.args.th_nocrop and as_thumb:
 | 
				
			||||||
 | 
					            w, h = self.args.th_size.split("x")
 | 
				
			||||||
 | 
					            h = int(100 / (float(w) / float(h)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        svg = """\
 | 
					        svg = """\
 | 
				
			||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<svg version="1.1" viewBox="0 0 100 30" xmlns="http://www.w3.org/2000/svg"><g>
 | 
					<svg version="1.1" viewBox="0 0 100 {}" xmlns="http://www.w3.org/2000/svg"><g>
 | 
				
			||||||
<rect width="100%" height="100%" fill="#{}" />
 | 
					<rect width="100%" height="100%" fill="#{}" />
 | 
				
			||||||
<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" xml:space="preserve"
 | 
					<text x="50%" y="50%" dominant-baseline="middle" text-anchor="middle" xml:space="preserve"
 | 
				
			||||||
  fill="#{}" font-family="monospace" font-size="14px" style="letter-spacing:.5px">{}</text>
 | 
					  fill="#{}" font-family="monospace" font-size="14px" style="letter-spacing:.5px">{}</text>
 | 
				
			||||||
</g></svg>
 | 
					</g></svg>
 | 
				
			||||||
"""
 | 
					"""
 | 
				
			||||||
        svg = svg.format(c[:6], c[6:], ext).encode("utf-8")
 | 
					        svg = svg.format(h, c[:6], c[6:], ext).encode("utf-8")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return ["image/svg+xml", svg]
 | 
					        return ["image/svg+xml", svg]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,7 +18,7 @@ if not PY2:
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
try:
 | 
					try:
 | 
				
			||||||
    HAVE_PIL = True
 | 
					    HAVE_PIL = True
 | 
				
			||||||
    from PIL import Image
 | 
					    from PIL import Image, ImageOps
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        HAVE_HEIF = True
 | 
					        HAVE_HEIF = True
 | 
				
			||||||
@@ -83,7 +83,7 @@ class ThumbSrv(object):
 | 
				
			|||||||
        self.args = hub.args
 | 
					        self.args = hub.args
 | 
				
			||||||
        self.log_func = hub.log
 | 
					        self.log_func = hub.log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        res = hub.args.thumbsz.split("x")
 | 
					        res = hub.args.th_size.split("x")
 | 
				
			||||||
        self.res = tuple([int(x) for x in res])
 | 
					        self.res = tuple([int(x) for x in res])
 | 
				
			||||||
        self.poke_cd = Cooldown(self.args.th_poke)
 | 
					        self.poke_cd = Cooldown(self.args.th_poke)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -207,18 +207,35 @@ class ThumbSrv(object):
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    def conv_pil(self, abspath, tpath):
 | 
					    def conv_pil(self, abspath, tpath):
 | 
				
			||||||
        with Image.open(abspath) as im:
 | 
					        with Image.open(abspath) as im:
 | 
				
			||||||
 | 
					            crop = not self.args.th_nocrop
 | 
				
			||||||
 | 
					            res2 = self.res
 | 
				
			||||||
 | 
					            if crop:
 | 
				
			||||||
 | 
					                res2 = (res2[0] * 2, res2[1] * 2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            try:
 | 
				
			||||||
 | 
					                im.thumbnail(res2, resample=Image.LANCZOS)
 | 
				
			||||||
 | 
					                if crop:
 | 
				
			||||||
 | 
					                    im = ImageOps.fit(im, self.res, method=Image.LANCZOS)
 | 
				
			||||||
 | 
					            except:
 | 
				
			||||||
 | 
					                im.thumbnail(self.res)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if im.mode not in ("RGB", "L"):
 | 
					            if im.mode not in ("RGB", "L"):
 | 
				
			||||||
                im = im.convert("RGB")
 | 
					                im = im.convert("RGB")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            im.thumbnail(self.res)
 | 
					            im.save(tpath, quality=50)
 | 
				
			||||||
            im.save(tpath)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def conv_ffmpeg(self, abspath, tpath):
 | 
					    def conv_ffmpeg(self, abspath, tpath):
 | 
				
			||||||
        ret, _ = run_ffprobe(abspath)
 | 
					        ret, _ = ffprobe(abspath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        dur = ret[".dur"][1]
 | 
					        dur = ret[".dur"][1]
 | 
				
			||||||
        seek = "{:.0f}".format(dur / 3)
 | 
					        seek = "{:.0f}".format(dur / 3)
 | 
				
			||||||
        scale = "scale=w={}:h={}:force_original_aspect_ratio=decrease"
 | 
					
 | 
				
			||||||
 | 
					        scale = "scale={0}:{1}:force_original_aspect_ratio="
 | 
				
			||||||
 | 
					        if self.args.th_nocrop:
 | 
				
			||||||
 | 
					            scale += "decrease,setsar=1:1"
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            scale += "increase,crop={0}:{1},setsar=1:1"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        scale = scale.format(*list(self.res)).encode("utf-8")
 | 
					        scale = scale.format(*list(self.res)).encode("utf-8")
 | 
				
			||||||
        cmd = [
 | 
					        cmd = [
 | 
				
			||||||
            b"ffmpeg",
 | 
					            b"ffmpeg",
 | 
				
			||||||
@@ -233,11 +250,11 @@ class ThumbSrv(object):
 | 
				
			|||||||
            b"-vframes",
 | 
					            b"-vframes",
 | 
				
			||||||
            b"1",
 | 
					            b"1",
 | 
				
			||||||
            b"-q:v",
 | 
					            b"-q:v",
 | 
				
			||||||
            b"5",
 | 
					            b"6",
 | 
				
			||||||
            fsenc(tpath),
 | 
					            fsenc(tpath),
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
 | 
					        p = sp.Popen(cmd, stdout=sp.PIPE, stderr=sp.PIPE)
 | 
				
			||||||
        r = p.communicate()
 | 
					        p.communicate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def poke(self, tdir):
 | 
					    def poke(self, tdir):
 | 
				
			||||||
        if not self.poke_cd.poke(tdir):
 | 
					        if not self.poke_cd.poke(tdir):
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user