# HG changeset patch # User Goffi # Date 1583084886 -3600 # Node ID 439e2f88c3a96a8036943f30f8737f72a3b1132c # Parent 5c3bf37f22026b3d935d2a895e45ff782d574da3 core, bridge: new `imageGeneratePreview` helped method to generate a thumbnail diff -r 5c3bf37f2202 -r 439e2f88c3a9 sat/bridge/bridge_constructor/bridge_template.ini --- a/sat/bridge/bridge_constructor/bridge_template.ini Sun Mar 01 18:47:05 2020 +0100 +++ b/sat/bridge/bridge_constructor/bridge_template.ini Sun Mar 01 18:48:06 2020 +0100 @@ -972,3 +972,14 @@ doc_param_2=height: height of the new image doc_return=path of the new image with desired size the image must be deleted once not needed anymore + +[imageGeneratePreview] +async= +type=method +category=core +sig_in=ss +sig_out=s +doc=Generate a preview of an image in cache +doc_param_0=image_path: path of the original image +doc_param_1=%(doc_profile_key)s +doc_return=path to the preview in cache diff -r 5c3bf37f2202 -r 439e2f88c3a9 sat/bridge/dbus_bridge.py --- a/sat/bridge/dbus_bridge.py Sun Mar 01 18:47:05 2020 +0100 +++ b/sat/bridge/dbus_bridge.py Sun Mar 01 18:48:06 2020 +0100 @@ -397,6 +397,12 @@ return self._callback("imageCheck", str(arg_0)) @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, + in_signature='ss', out_signature='s', + async_callbacks=('callback', 'errback')) + def imageGeneratePreview(self, image_path, profile_key, callback=None, errback=None): + return self._callback("imageGeneratePreview", str(image_path), str(profile_key), callback=callback, errback=errback) + + @dbus.service.method(const_INT_PREFIX+const_CORE_SUFFIX, in_signature='sii', out_signature='s', async_callbacks=('callback', 'errback')) def imageResize(self, image_path, width, height, callback=None, errback=None): diff -r 5c3bf37f2202 -r 439e2f88c3a9 sat/core/constants.py --- a/sat/core/constants.py Sun Mar 01 18:47:05 2020 +0100 +++ b/sat/core/constants.py Sun Mar 01 18:48:06 2020 +0100 @@ -135,6 +135,7 @@ MESS_KEY_ATTACHMENTS = "attachments" MESS_KEY_ATTACHMENTS_MEDIA_TYPE = "media_type" + MESS_KEY_ATTACHMENTS_PREVIEW = "preview" # File encryption algorithms ENC_AES_GCM = "AES-GCM" diff -r 5c3bf37f2202 -r 439e2f88c3a9 sat/core/sat_main.py --- a/sat/core/sat_main.py Sun Mar 01 18:47:05 2020 +0100 +++ b/sat/core/sat_main.py Sun Mar 01 18:48:06 2020 +0100 @@ -20,6 +20,8 @@ import sys import os.path import uuid +import hashlib +from pathlib import Path import sat from sat.core.i18n import _, D_, languageSwitch from sat.core import patches @@ -173,6 +175,7 @@ self.bridge.register_method("namespacesGet", self.getNamespaces) self.bridge.register_method("imageCheck", self._imageCheck) self.bridge.register_method("imageResize", self._imageResize) + self.bridge.register_method("imageGeneratePreview", self._imageGeneratePreview) self.memory.initialized.addCallback(lambda __: defer.ensureDeferred(self._postMemoryInit())) @@ -684,6 +687,45 @@ d.addCallback(lambda new_image_path: str(new_image_path)) return d + def _imageGeneratePreview(self, path, profile_key): + client = self.getClient(profile_key) + d = defer.ensureDeferred(self.imageGeneratePreview(client, Path(path))) + d.addCallback(lambda preview_path: str(preview_path)) + return d + + async def imageGeneratePreview(self, client, path): + """Helper method to generate in cache a preview of an image + + @param path(Path): path to the image + @return (Path): path to the generated preview + """ + report = images.checkImage(self, path, max_size=(300, 300)) + + if not report['too_large']: + # in the unlikely case that image is already smaller than a preview + preview_path = path + else: + # we use hash as id, to re-use potentially existing preview + path_hash = hashlib.sha256(str(path).encode()).hexdigest() + uid = f"{path.stem}_{path_hash}_preview" + filename = f"{uid}{path.suffix.lower()}" + metadata = client.cache.getMetadata(uid=uid) + if metadata is not None: + preview_path = metadata['path'] + else: + with client.cache.cacheData( + source='HOST_PREVIEW', + uid=uid, + filename=filename) as cache_f: + + preview_path = await images.resizeImage( + path, + new_size=report['recommended_size'], + dest=cache_f + ) + + return preview_path + # local dirs def getLocalPath(self, client, dir_name, *extra_path, **kwargs): diff -r 5c3bf37f2202 -r 439e2f88c3a9 sat_frontends/bridge/dbus_bridge.py --- a/sat_frontends/bridge/dbus_bridge.py Sun Mar 01 18:47:05 2020 +0100 +++ b/sat_frontends/bridge/dbus_bridge.py Sun Mar 01 18:48:06 2020 +0100 @@ -489,6 +489,15 @@ kwargs['error_handler'] = error_handler return str(self.db_core_iface.imageCheck(arg_0, **kwargs)) + def imageGeneratePreview(self, image_path, profile_key, callback=None, errback=None): + if callback is None: + error_handler = None + else: + if errback is None: + errback = log.error + error_handler = lambda err:errback(dbus_to_bridge_exception(err)) + return str(self.db_core_iface.imageGeneratePreview(image_path, profile_key, timeout=const_TIMEOUT, reply_handler=callback, error_handler=error_handler)) + def imageResize(self, image_path, width, height, callback=None, errback=None): if callback is None: error_handler = None @@ -1149,6 +1158,14 @@ self.db_core_iface.imageCheck(arg_0, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) return fut + def imageGeneratePreview(self, image_path, profile_key): + loop = asyncio.get_running_loop() + fut = loop.create_future() + reply_handler = lambda ret=None: loop.call_soon_threadsafe(fut.set_result, ret) + error_handler = lambda err: loop.call_soon_threadsafe(fut.set_exception, dbus_to_bridge_exception(err)) + self.db_core_iface.imageGeneratePreview(image_path, profile_key, timeout=const_TIMEOUT, reply_handler=reply_handler, error_handler=error_handler) + return fut + def imageResize(self, image_path, width, height): loop = asyncio.get_running_loop() fut = loop.create_future() diff -r 5c3bf37f2202 -r 439e2f88c3a9 sat_frontends/bridge/pb.py --- a/sat_frontends/bridge/pb.py Sun Mar 01 18:47:05 2020 +0100 +++ b/sat_frontends/bridge/pb.py Sun Mar 01 18:48:06 2020 +0100 @@ -383,6 +383,14 @@ errback = self._generic_errback d.addErrback(errback) + def imageGeneratePreview(self, image_path, profile_key, callback=None, errback=None): + d = self.root.callRemote("imageGeneratePreview", image_path, profile_key) + if callback is not None: + d.addCallback(callback) + if errback is None: + errback = self._generic_errback + d.addErrback(errback) + def imageResize(self, image_path, width, height, callback=None, errback=None): d = self.root.callRemote("imageResize", image_path, width, height) if callback is not None: @@ -818,6 +826,11 @@ d.addErrback(self._errback) return d.asFuture(asyncio.get_event_loop()) + def imageGeneratePreview(self, image_path, profile_key): + d = self.root.callRemote("imageGeneratePreview", image_path, profile_key) + d.addErrback(self._errback) + return d.asFuture(asyncio.get_event_loop()) + def imageResize(self, image_path, width, height): d = self.root.callRemote("imageResize", image_path, width, height) d.addErrback(self._errback)