diff --git a/src/python/matrix_client.py b/src/python/matrix_client.py index aa2dcd1c..7f64fa41 100644 --- a/src/python/matrix_client.py +++ b/src/python/matrix_client.py @@ -443,7 +443,6 @@ class MatrixClient(nio.AsyncClient): else: crypt_dict, upload_mime = {}, mime - return ( await self.upload(data, upload_mime, Path(path).name), { @@ -813,7 +812,7 @@ class MatrixClient(nio.AsyncClient): ev, content = "", inline_content = ev.body, - media_url = nio.Api.mxc_to_http(ev.url), + media_url = ev.url, media_title = ev.body, media_width = info.get("w") or 0, media_height = info.get("h") or 0, @@ -821,9 +820,7 @@ class MatrixClient(nio.AsyncClient): media_size = info.get("size") or 0, media_mime = info.get("mimetype") or 0, - thumbnail_url = - nio.Api.mxc_to_http(info.get("thumbnail_url") or ""), - + thumbnail_url = info.get("thumbnail_url") or "", thumbnail_width = thumb_info.get("w") or 0, thumbnail_height = thumb_info.get("h") or 0, ) diff --git a/src/python/media_cache.py b/src/python/media_cache.py index 97bd2238..ad0e4cc7 100644 --- a/src/python/media_cache.py +++ b/src/python/media_cache.py @@ -26,8 +26,9 @@ class DownloadFailed(Exception): @dataclass class Media: - cache: "MediaCache" = field() - mxc: str = field() + cache: "MediaCache" = field() + mxc: str = field() + data: Optional[bytes] = field(repr=False) def __post_init__(self) -> None: @@ -54,7 +55,7 @@ class Media: try: return await self._get_local_existing_file() except FileNotFoundError: - return await self._download() + return await self.create() async def _get_local_existing_file(self) -> Path: @@ -64,14 +65,15 @@ class Media: return self.local_path - async def _download(self) -> Path: - async with CONCURRENT_DOWNLOADS_LIMIT: - body = await self._get_remote_data() + async def create(self) -> Path: + if self.data is None: + async with CONCURRENT_DOWNLOADS_LIMIT: + self.data = await self._get_remote_data() self.local_path.parent.mkdir(parents=True, exist_ok=True) async with aiofiles.open(self.local_path, "wb") as file: - await file.write(body) + await file.write(self.data) return self.local_path @@ -82,9 +84,10 @@ class Media: @dataclass class Thumbnail(Media): - cache: "MediaCache" = field() - mxc: str = field() - wanted_size: Size = field() + cache: "MediaCache" = field() + mxc: str = field() + data: Optional[bytes] = field(repr=False) + wanted_size: Size = field() server_size: Optional[Size] = field(init=False, repr=False, default=None) @@ -143,7 +146,6 @@ class Thumbnail(Media): raise FileNotFoundError() - async def _get_remote_data(self) -> bytes: parsed = urlparse(self.mxc) @@ -154,13 +156,13 @@ class Thumbnail(Media): height = self.wanted_size[1], ) + if isinstance(resp, nio.ThumbnailError): + raise DownloadFailed(resp.message, resp.status_code) + with io.BytesIO(resp.body) as img: # The server may return a thumbnail bigger than what we asked for self.server_size = PILImage.open(img).size - if isinstance(resp, nio.ErrorResponse): - raise DownloadFailed(resp.message, resp.status_code) - return resp.body @@ -178,5 +180,5 @@ class MediaCache: self.downloads_dir.mkdir(parents=True, exist_ok=True) - async def thumbnail(self, mxc: str, width: int, height: int) -> str: - return str(await Thumbnail(self, mxc, (width, height)).get()) + async def get_thumbnail(self, mxc: str, width: int, height: int) -> str: + return str(await Thumbnail(self, mxc, None, (width, height)).get()) diff --git a/src/qml/Base/HMxcImage.qml b/src/qml/Base/HMxcImage.qml index c19a7ec1..8c20e8a5 100644 --- a/src/qml/Base/HMxcImage.qml +++ b/src/qml/Base/HMxcImage.qml @@ -31,10 +31,18 @@ HImage { if (! image) return // if it was destroyed - py.callClientCoro(clientUserId, "media_cache.thumbnail", arg, path => { - if (! image) return - image.cachedPath = path - show = image.visible - }) + if (! image.mxc.startsWith("mxc://")) { + source = mxc + show = image.visible + return + } + + py.callClientCoro( + clientUserId, "media_cache.get_thumbnail", [mxc, w, h], path => { + if (! image) return + image.cachedPath = path + show = image.visible + } + ) } } diff --git a/src/qml/Chat/Timeline/EventImage.qml b/src/qml/Chat/Timeline/EventImage.qml index 364ec049..79ee445a 100644 --- a/src/qml/Chat/Timeline/EventImage.qml +++ b/src/qml/Chat/Timeline/EventImage.qml @@ -2,17 +2,19 @@ import QtQuick 2.12 import "../../Base" import "../../utils.js" as Utils -HImage { +HMxcImage { id: image horizontalAlignment: Image.AlignLeft - sourceSize.width: theme.chat.message.thumbnailWidth // FIXME - source: animated ? openUrl : loader.previewUrl + sourceSize.width: 640 // FIXME + sourceSize.height: 480 // FIXME animated: loader.singleMediaInfo.media_mime === "image/gif" || Utils.urlExtension(loader.mediaUrl) === "gif" + clientUserId: chatPage.userId + mxc: animated ? openUrl : (loader.thumbnailMxc || loader.mediaUrl) property EventMediaLoader loader - readonly property url openUrl: loader.mediaUrl || loader.previewUrl + readonly property url openUrl: loader.mediaUrl || loader.thumbnailMxc TapHandler { diff --git a/src/qml/Chat/Timeline/EventMediaLoader.qml b/src/qml/Chat/Timeline/EventMediaLoader.qml index a37e999f..c9e1e2bf 100644 --- a/src/qml/Chat/Timeline/EventMediaLoader.qml +++ b/src/qml/Chat/Timeline/EventMediaLoader.qml @@ -8,7 +8,7 @@ HLoader { property QtObject singleMediaInfo - property url mediaUrl + property string mediaUrl property string showSender: "" property string showDate: "" @@ -47,21 +47,17 @@ HLoader { return EventDelegate.Media.Page } - readonly property url previewUrl: ( - type === EventDelegate.Media.File || - type === EventDelegate.Media.Image ? - singleMediaInfo.thumbnail_url : "" - ) || mediaUrl + readonly property string thumbnailMxc: singleMediaInfo.thumbnail_url - onPreviewUrlChanged: { + onTypeChanged: { if (type === EventDelegate.Media.Image) { - var file = "EventImage.qml" + var file = "EventImage.qml" // } else if (type === EventDelegate.Media.File) { // var file = "EventFile.qml" // var props = { - // thumbnailUrl: previewUrl, + // thumbnailMxc: thumbnailMxc, // fileUrl: mediaUrl, // fileTitle: info.media_title, // fileSize: info.media_size,