<% if (['image', 'animation'].includes(ctx.post.type)) { %> - + <% } else if (ctx.post.type === 'flash') { %> - + +
Your browser does not support Flash.
<% } else if (ctx.post.type === 'video') { %> From 2b394147155c5ced25a5ffc22bde7699e95caa43 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 26 May 2023 08:30:58 +0200 Subject: [PATCH 16/29] client/css: fix overextended broken thumbnail --- client/css/core-general.styl | 1 + 1 file changed, 1 insertion(+) diff --git a/client/css/core-general.styl b/client/css/core-general.styl index 4c5d2b1b..cca99922 100644 --- a/client/css/core-general.styl +++ b/client/css/core-general.styl @@ -287,6 +287,7 @@ nav background-size: cover background-position: center display: inline-block + overflow: hidden width: 20px height: 20px &.empty From 061c604f14f50b3d9eae3d29bc1769c500428167 Mon Sep 17 00:00:00 2001 From: Eva Date: Thu, 28 Mar 2024 03:41:35 +0100 Subject: [PATCH 17/29] server/rest: allow files with empty content --- server/szurubooru/rest/context.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/szurubooru/rest/context.py b/server/szurubooru/rest/context.py index 40ba0bcb..393a37e2 100644 --- a/server/szurubooru/rest/context.py +++ b/server/szurubooru/rest/context.py @@ -51,7 +51,7 @@ class Context: use_video_downloader: bool = False, allow_tokens: bool = True, ) -> bytes: - if name in self._files and self._files[name]: + if name in self._files: return self._files[name] if name + "Url" in self._params: From 795ba068e6612927a5e3523e16d43a6e67386c76 Mon Sep 17 00:00:00 2001 From: Eva Date: Thu, 28 Mar 2024 03:39:33 +0100 Subject: [PATCH 18/29] client/posts: make discard thumbnail link delete existing custom thumb I can see the intent, sadly this was always broken in the case where the post already has a custom thumbnail from initial load, and we don't drag any new files. It did not actually remove the existing thumbnail. Before 12c4542bb2482fac89aae9a04b15984a56bb8fb0 it would actually crash, but this now makes it behave as expected. Also properly syncs internal state with what's displayed to the user. --- client/js/api.js | 9 ++++++-- client/js/controllers/post_main_controller.js | 8 ++----- .../js/controls/post_edit_sidebar_control.js | 22 +++++++++++++------ 3 files changed, 24 insertions(+), 15 deletions(-) diff --git a/client/js/api.js b/client/js/api.js index 5bde6d81..d3f74c26 100644 --- a/client/js/api.js +++ b/client/js/api.js @@ -294,11 +294,16 @@ class Api extends events.EventTarget { // transform the request: upload each file, then make the request use // its tokens. data = Object.assign({}, data); + let fileData = {}; let abortFunction = () => {}; let promise = Promise.resolve(); if (files) { for (let key of Object.keys(files)) { const file = files[key]; + if (file === null) { + fileData[key] = null; + continue; + } const fileId = this._getFileId(file); if (fileTokens[fileId]) { data[key + "Token"] = fileTokens[fileId]; @@ -324,7 +329,7 @@ class Api extends events.EventTarget { url, requestFactory, data, - {}, + fileData, options ); abortFunction = () => requestPromise.abort(); @@ -388,7 +393,7 @@ class Api extends events.EventTarget { if (files) { for (let key of Object.keys(files)) { const value = files[key]; - if (value.constructor === String) { + if (value !== null && value.constructor === String) { data[key + "Url"] = value; } else { req.attach(key, value || new Blob()); diff --git a/client/js/controllers/post_main_controller.js b/client/js/controllers/post_main_controller.js index bd338129..3cab18cf 100644 --- a/client/js/controllers/post_main_controller.js +++ b/client/js/controllers/post_main_controller.js @@ -178,15 +178,11 @@ class PostMainController extends BasePostController { if (e.detail.relations !== undefined && e.detail.relations !== null) { post.relations = e.detail.relations; } - if (e.detail.content !== undefined && e.detail.content !== null) { - post.newContent = e.detail.content; - } - if (e.detail.thumbnail !== undefined && e.detail.thumbnail !== null) { - post.newThumbnail = e.detail.thumbnail; - } if (e.detail.source !== undefined && e.detail.source !== null) { post.source = e.detail.source; } + post.newContent = e.detail.content; + post.newThumbnail = e.detail.thumbnail; post.save().then( () => { this._view.sidebarControl.showSuccess("Post saved."); diff --git a/client/js/controls/post_edit_sidebar_control.js b/client/js/controls/post_edit_sidebar_control.js index 7602ae9c..9f2d37da 100644 --- a/client/js/controls/post_edit_sidebar_control.js +++ b/client/js/controls/post_edit_sidebar_control.js @@ -138,10 +138,7 @@ class PostEditSidebarControl extends events.EventTarget { this._thumbnailRemovalLinkNode.addEventListener("click", (e) => this._evtRemoveThumbnailClick(e) ); - this._thumbnailRemovalLinkNode.style.display = this._post - .customThumbnailUrl - ? "block" - : "none"; + this._thumbnailRemovalLinkUpdate(this._post); } if (this._addNoteLinkNode) { @@ -249,12 +246,25 @@ class PostEditSidebarControl extends events.EventTarget { this._poolsExpander.title = `Pools (${this._post.pools.length})`; } + _thumbnailRemovalLinkUpdate(post) { + if (this._thumbnailRemovalLinkNode) { + this._thumbnailRemovalLinkNode.style.display = post + .customThumbnailUrl + ? "block" + : "none"; + } + } + _evtPostContentChange(e) { this._contentFileDropper.reset(); + this._thumbnailRemovalLinkUpdate(e.detail.post); + this._newPostContent = null; } _evtPostThumbnailChange(e) { this._thumbnailFileDropper.reset(); + this._thumbnailRemovalLinkUpdate(e.detail.post); + this._newPostThumbnail = undefined; } _evtRemoveThumbnailClick(e) { @@ -427,9 +437,7 @@ class PostEditSidebarControl extends events.EventTarget { : undefined, thumbnail: - this._newPostThumbnail !== undefined && this._newPostThumbnail !== null - ? this._newPostThumbnail - : undefined, + this._newPostThumbnail, source: this._sourceInputNode ? this._sourceInputNode.value From 535d2d2a8b55d782db812c8d2b6188010c99877e Mon Sep 17 00:00:00 2001 From: ItsKaa <31796925+ItsKaa@users.noreply.github.com> Date: Sun, 17 Nov 2024 12:15:33 +0100 Subject: [PATCH 19/29] server/posts: fix source file deletion --- server/szurubooru/func/files.py | 4 ++-- server/szurubooru/func/posts.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/server/szurubooru/func/files.py b/server/szurubooru/func/files.py index 4d764f52..02be1296 100644 --- a/server/szurubooru/func/files.py +++ b/server/szurubooru/func/files.py @@ -25,8 +25,8 @@ def scan(path: str) -> List[Any]: return [] -def find(path: str, pattern: str) -> List[Any]: - return glob.glob(glob.escape(_get_full_path(path) + "/") + pattern) +def find(path: str, pattern: str, recursive: bool = False) -> List[Any]: + return glob.glob(glob.escape(_get_full_path(path) + "/") + pattern, recursive=recursive) def move(source_path: str, target_path: str) -> None: diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py index 4066907d..e9e14513 100644 --- a/server/szurubooru/func/posts.py +++ b/server/szurubooru/func/posts.py @@ -481,7 +481,7 @@ def _before_post_delete( ) -> None: if post.post_id: if config.config["delete_source_files"]: - pattern = post.post_id + "_*" + pattern = f"{post.post_id}_*" for file in files.find("posts", "**/" + pattern, recursive=True) + files.find("generated-thumbnails", "**/sample_" + pattern, recursive=True): files.delete(file) From 09721398317895435b4ae323839e2a3db1c77d5c Mon Sep 17 00:00:00 2001 From: ItsKaa <31796925+ItsKaa@users.noreply.github.com> Date: Sat, 30 Nov 2024 01:54:33 +0100 Subject: [PATCH 20/29] server/posts: fix custom thumbnails --- server/szurubooru/func/posts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py index e9e14513..0720552d 100644 --- a/server/szurubooru/func/posts.py +++ b/server/szurubooru/func/posts.py @@ -129,7 +129,7 @@ def get_post_custom_thumbnail_url(post: model.Post) -> str: return "%s/generated-thumbnails/custom-thumbnails/sample_%d_%s.jpg" % ( config.config["data_url"].rstrip("/"), post.post_id, - post.image_key, + get_post_security_hash(post.post_id), ) @@ -148,7 +148,7 @@ def get_post_custom_content_path(post: model.Post) -> str: assert post.post_id return "posts/custom-thumbnails/%d_%s.dat" % ( post.post_id, - post.image_key, + get_post_security_hash(post.post_id), ) From 5d262b00594e2167303573f8702140dec0714c84 Mon Sep 17 00:00:00 2001 From: alan Date: Sun, 18 Jun 2023 14:36:26 +0100 Subject: [PATCH 21/29] server: Add required dependencies to Dockerfile --- server/Dockerfile | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/server/Dockerfile b/server/Dockerfile index 3e4dadfb..b3dbbe0f 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -33,6 +33,21 @@ RUN pip3 install --no-cache-dir --disable-pip-version-check \ "pillow-avif-plugin~=1.1.0" RUN apk --no-cache del py3-pip +# build and install mozjpeg +RUN apk --no-cache add automake cmake nasm libpng-dev libpng curl +RUN curl -fL "https://github.com/mozilla/mozjpeg/archive/refs/tags/v4.1.1.tar.gz" -o mozjpeg.tar.gz +RUN tar xzf mozjpeg.tar.gz && cd mozjpeg-* \ +&& cmake -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INSTALL_LIBDIR=/usr/lib \ + -DBUILD_SHARED_LIBS=True \ + -DCMAKE_BUILD_TYPE=None \ + -DCMAKE_C_FLAGS="$CFLAGS" \ + -DWITH_JPEG8=1 \ + -DWITH_TURBOJPEG=1 \ + -DENABLE_STATIC=0 \ +&& make install && cd +RUN apk --no-cache del automake nasm cmake curl + COPY ./ /opt/app/ RUN rm -rf /opt/app/szurubooru/tests From 9362444871f6afcc6835b3458db1216c5c9928cd Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 25 Mar 2025 17:39:48 +0100 Subject: [PATCH 22/29] client/css: make broken thumbnails in search take up the same area To preserve the "right-click to save" behavior --- client/css/core-general.styl | 1 + 1 file changed, 1 insertion(+) diff --git a/client/css/core-general.styl b/client/css/core-general.styl index cca99922..804bff7c 100644 --- a/client/css/core-general.styl +++ b/client/css/core-general.styl @@ -304,6 +304,7 @@ nav object-fit: cover width: 100% height: 100% + display: block .flexbox-dummy height: 0 !important From 418640d96709f169656bf53dda6507bdfa373404 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 28 Mar 2025 13:51:46 +0100 Subject: [PATCH 23/29] server/szuru-admin: update thumbnail regeneration script --- server/szuru-admin | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/server/szuru-admin b/server/szuru-admin index 08ba1827..204e8f11 100755 --- a/server/szuru-admin +++ b/server/szuru-admin @@ -13,7 +13,7 @@ from getpass import getpass from sys import stderr from szurubooru import config, db, errors, model -from szurubooru.func import files, images +from szurubooru.func import files, images, mime from szurubooru.func import posts as postfuncs from szurubooru.func import users as userfuncs @@ -95,7 +95,14 @@ def regenerate_thumbnails() -> None: for post in db.session.query(model.Post).all(): print("Generating tumbnail for post %d ..." % post.post_id, end="\r") try: - postfuncs.generate_post_thumbnail(post) + content = files.get(postfuncs.get_post_content_path(post)) + postfuncs.generate_post_thumbnail(postfuncs.get_post_thumbnail_path(post), content, seek=False) + + custom_content = files.get(postfuncs.get_post_custom_content_path(post)) + if custom_content: + generate_post_thumbnail(get_post_custom_thumbnail_path(post), custom_content, seek=True) + elif mime.is_video(post.mime_type): + generate_post_thumbnail(get_post_custom_thumbnail_path(post), content, seek=True) except Exception: pass From 1fd36b1f3277567b3a6da0d383872cbd811ab842 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 28 Mar 2025 14:17:29 +0100 Subject: [PATCH 24/29] server/posts: prepend thumbnail filenames with 'sample_' --- server/szurubooru/func/posts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/server/szurubooru/func/posts.py b/server/szurubooru/func/posts.py index 0720552d..3244da98 100644 --- a/server/szurubooru/func/posts.py +++ b/server/szurubooru/func/posts.py @@ -117,7 +117,7 @@ def get_post_content_url(post: model.Post) -> str: def get_post_thumbnail_url(post: model.Post) -> str: assert post - return "%s/generated-thumbnails/%d_%s.jpg" % ( + return "%s/generated-thumbnails/sample_%d_%s.jpg" % ( config.config["data_url"].rstrip("/"), post.post_id, get_post_security_hash(post.post_id), @@ -154,7 +154,7 @@ def get_post_custom_content_path(post: model.Post) -> str: def get_post_thumbnail_path(post: model.Post) -> str: assert post - return "generated-thumbnails/%d_%s.jpg" % ( + return "generated-thumbnails/sample_%d_%s.jpg" % ( post.post_id, get_post_security_hash(post.post_id), ) From 1c08492a9407e1e23a43084cdec5d242a41acadc Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 28 Mar 2025 15:22:36 +0100 Subject: [PATCH 25/29] server/posts: update tests for thumbnail rework --- server/szurubooru/tests/func/test_posts.py | 39 ++++++++++++++-------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/server/szurubooru/tests/func/test_posts.py b/server/szurubooru/tests/func/test_posts.py index 5e0095fd..55e77bc5 100644 --- a/server/szurubooru/tests/func/test_posts.py +++ b/server/szurubooru/tests/func/test_posts.py @@ -41,7 +41,7 @@ def test_get_post_thumbnail_url(input_mime_type, config_injector): post.mime_type = input_mime_type assert ( posts.get_post_thumbnail_url(post) - == "http://example.com/generated-thumbnails/1_244c8840887984c4.jpg" + == "http://example.com/generated-thumbnails/sample_1_244c8840887984c4.jpg" ) @@ -67,7 +67,7 @@ def test_get_post_thumbnail_path(input_mime_type): post.mime_type = input_mime_type assert ( posts.get_post_thumbnail_path(post) - == "generated-thumbnails/1_244c8840887984c4.jpg" + == "generated-thumbnails/sample_1_244c8840887984c4.jpg" ) @@ -78,7 +78,7 @@ def test_get_post_custom_thumbnail_path(input_mime_type): post.mime_type = input_mime_type assert ( posts.get_post_custom_thumbnail_path(post) - == "posts/custom-thumbnails/1_244c8840887984c4.dat" + == "generated-thumbnails/custom-thumbnails/sample_1_244c8840887984c4.jpg" ) @@ -226,7 +226,9 @@ def test_serialize_post( "canvasHeight": 300, "contentUrl": "http://example.com/posts/1_244c8840887984c4.jpg", "thumbnailUrl": "http://example.com/" - "generated-thumbnails/1_244c8840887984c4.jpg", + "generated-thumbnails/sample_1_244c8840887984c4.jpg", + "customThumbnailUrl": "http://example.com/" + "generated-thumbnails/custom-thumbnails/sample_1_244c8840887984c4.jpg", "flags": ["loop"], "tags": [ { @@ -270,17 +272,27 @@ def test_serialize_post( "relationCount": 0, "lastFeatureTime": datetime(1999, 1, 1), "favoritedBy": ["fav1"], - "hasCustomThumbnail": True, "mimeType": "image/jpeg", "comments": ["commenter1", "commenter2"], } -def test_serialize_micro_post(post_factory, user_factory): +def test_serialize_micro_post(tmpdir, config_injector, post_factory, user_factory): with patch("szurubooru.func.posts.get_post_thumbnail_url"): posts.get_post_thumbnail_url.return_value = ( "https://example.com/thumb.png" ) + config_injector( + { + "data_dir": str(tmpdir.mkdir("data")), + "thumbnails": { + "post_width": 300, + "post_height": 300, + }, + "secret": "test", + "allow_broken_uploads": False, + } + ) auth_user = user_factory() post = post_factory() db.session.add(post) @@ -288,6 +300,7 @@ def test_serialize_micro_post(post_factory, user_factory): assert posts.serialize_micro_post(post, auth_user) == { "id": post.post_id, "thumbnailUrl": "https://example.com/thumb.png", + "customThumbnailUrl": None, } @@ -605,7 +618,7 @@ def test_update_post_thumbnail_to_new_one( assert post.post_id generated_path = ( "{}/data/generated-thumbnails/".format(tmpdir) - + "1_244c8840887984c4.jpg" + + "sample_1_244c8840887984c4.jpg" ) source_path = ( "{}/data/posts/custom-thumbnails/".format(tmpdir) @@ -646,7 +659,7 @@ def test_update_post_thumbnail_to_default( assert post.post_id generated_path = ( "{}/data/generated-thumbnails/".format(tmpdir) - + "1_244c8840887984c4.jpg" + + "sample_1_244c8840887984c4.jpg" ) source_path = ( "{}/data/posts/custom-thumbnails/".format(tmpdir) @@ -686,7 +699,7 @@ def test_update_post_thumbnail_with_broken_thumbnail( assert post.post_id generated_path = ( "{}/data/generated-thumbnails/".format(tmpdir) - + "1_244c8840887984c4.jpg" + + "sample_1_244c8840887984c4.jpg" ) source_path = ( "{}/data/posts/custom-thumbnails/".format(tmpdir) @@ -705,8 +718,8 @@ def test_update_post_thumbnail_with_broken_thumbnail( assert handle.read() == read_asset("png-broken.png") with open(generated_path, "rb") as handle: image = images.Image(handle.read()) - assert image.width == 1 - assert image.height == 1 + assert image.width == 300 + assert image.height == 300 def test_update_post_content_leaving_custom_thumbnail( @@ -731,7 +744,7 @@ def test_update_post_content_leaving_custom_thumbnail( db.session.flush() generated_path = ( "{}/data/generated-thumbnails/".format(tmpdir) - + "1_244c8840887984c4.jpg" + + "sample_1_244c8840887984c4.jpg" ) source_path = ( "{}/data/posts/custom-thumbnails/".format(tmpdir) @@ -763,7 +776,7 @@ def test_update_post_content_convert_heif_to_png_when_processing( db.session.flush() generated_path = ( "{}/data/generated-thumbnails/".format(tmpdir) - + "1_244c8840887984c4.jpg" + + "sample_1_244c8840887984c4.jpg" ) source_path = ( "{}/data/posts/custom-thumbnails/".format(tmpdir) From 952e683b720770432af375858762aa8bb7ff1b64 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 28 Mar 2025 14:39:48 +0100 Subject: [PATCH 26/29] server/images: restore ffmepg swf handling --- server/szurubooru/func/images.py | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/server/szurubooru/func/images.py b/server/szurubooru/func/images.py index f3bc5fdc..93891017 100644 --- a/server/szurubooru/func/images.py +++ b/server/szurubooru/func/images.py @@ -33,9 +33,6 @@ class Image: def __init__(self, content: bytes) -> None: self.content = content self._reload_info() - if self.info["format"]["format_name"] == "swf": - self.content = self.swf_to_png() - self._reload_info() @property def width(self) -> int: @@ -72,7 +69,11 @@ class Image: "png", "-", ] - if seek and "duration" in self.info["format"]: + if ( + seek + and "duration" in self.info["format"] + and self.info["format"]["format_name"] != "swf" + ): duration = float(self.info["format"]["duration"]) if duration > 3: cli = [ @@ -85,19 +86,6 @@ class Image: self.content = content self._reload_info() - def swf_to_png(self) -> bytes: - return self._execute( - [ - "--silent", - "-g", - "gl", - "--", - "{path}", - "-", - ], - program="exporter", - ) - def to_png(self) -> bytes: return self._execute( [ @@ -329,7 +317,7 @@ class Image: ) assert "format" in self.info assert "streams" in self.info - if len(self.info["streams"]) < 1 and self.info["format"]["format_name"] != "swf": + if len(self.info["streams"]) < 1: logger.warning("The video contains no video streams.") raise errors.ProcessingError( "The video contains no video streams." From bfe3767b6895d8169c905c0b96a8e82361381e95 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 28 Mar 2025 14:51:07 +0100 Subject: [PATCH 27/29] server/users: disable transparency and seeking on user avatars --- server/szurubooru/func/users.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/server/szurubooru/func/users.py b/server/szurubooru/func/users.py index 5cbe3cc0..a2e21da6 100644 --- a/server/szurubooru/func/users.py +++ b/server/szurubooru/func/users.py @@ -311,6 +311,8 @@ def update_user_avatar( image.resize_fill( int(config.config["thumbnails"]["avatar_width"]), int(config.config["thumbnails"]["avatar_height"]), + keep_transparency=False, + seek=False, ) files.save(avatar_path, image.to_png()) else: From 289f8a87be5922e2a49882dca1de3e2c07604fc4 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 28 Mar 2025 17:10:20 +0100 Subject: [PATCH 28/29] client/css: outline around post relations --- client/css/post-main-view.styl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/css/post-main-view.styl b/client/css/post-main-view.styl index 1183cce2..aa1a6b0c 100644 --- a/client/css/post-main-view.styl +++ b/client/css/post-main-view.styl @@ -124,6 +124,8 @@ li margin: 0 0.3em 0.3em 0 display: inline-block + a + box-shadow: 0 0 0 1px rgba(0,0,0,0.2) .tags margin-top: 2em From 14a438656188c2023ad5cf3fe21dd993819c0dc2 Mon Sep 17 00:00:00 2001 From: Eva Date: Tue, 1 Apr 2025 02:36:20 +0200 Subject: [PATCH 29/29] client/posts: skip thumbnail placeholder if fullsize image is in cache --- client/js/controls/post_content_control.js | 9 ++++++--- client/js/util/misc.js | 10 ++++++++++ client/js/views/home_view.js | 1 + client/js/views/post_main_view.js | 1 + 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/client/js/controls/post_content_control.js b/client/js/controls/post_content_control.js index b37d79c8..68951dca 100644 --- a/client/js/controls/post_content_control.js +++ b/client/js/controls/post_content_control.js @@ -5,11 +5,12 @@ const views = require("../util/views.js"); const optimizedResize = require("../util/optimized_resize.js"); class PostContentControl { - constructor(hostNode, post, viewportSizeCalculator, fitFunctionOverride) { + constructor(hostNode, post, isMediaCached, viewportSizeCalculator, fitFunctionOverride) { this._post = post; this._viewportSizeCalculator = viewportSizeCalculator; this._hostNode = hostNode; this._template = views.getTemplate("post-content"); + this._isMediaCached = isMediaCached; let fitMode = settings.get().fitMode; if (typeof fitFunctionOverride !== "undefined") { @@ -150,9 +151,11 @@ class PostContentControl { newNode.firstElementChild.style.backgroundImage = ""; } if (["image", "flash"].includes(this._post.type)) { - newNode.firstElementChild.style.backgroundImage = "url("+this._post.originalThumbnailUrl+")"; + if (this._post.type !== "image" || !this._isMediaCached) { + newNode.firstElementChild.style.backgroundImage = "url("+this._post.originalThumbnailUrl+")"; + } } - if (this._post.type == "image") { + if (this._post.type == "image" && !this._isMediaCached) { newNode.firstElementChild.addEventListener("load", load); } else if (settings.get().transparencyGrid) { newNode.classList.add("transparency-grid"); diff --git a/client/js/util/misc.js b/client/js/util/misc.js index 756ad84b..2a71fe10 100644 --- a/client/js/util/misc.js +++ b/client/js/util/misc.js @@ -211,6 +211,15 @@ function getPrettyName(tag) { return tag; } +function isMediaCached(post) { + if (post.type !== "image") { + return false; + } + const img = new Image() + img.src = post.contentUrl; + return img.complete; +} + module.exports = { range: range, formatRelativeTime: formatRelativeTime, @@ -229,4 +238,5 @@ module.exports = { escapeSearchTerm: escapeSearchTerm, dataURItoBlob: dataURItoBlob, getPrettyName: getPrettyName, + isMediaCached: isMediaCached, }; diff --git a/client/js/views/home_view.js b/client/js/views/home_view.js index c91363b2..795d6a5a 100644 --- a/client/js/views/home_view.js +++ b/client/js/views/home_view.js @@ -62,6 +62,7 @@ class HomeView { this._postContentControl = new PostContentControl( this._postContainerNode, postInfo.featuredPost, + misc.isMediaCached(postInfo.featuredPost), () => { return [window.innerWidth * 0.8, window.innerHeight * 0.7]; }, diff --git a/client/js/views/post_main_view.js b/client/js/views/post_main_view.js index 5ef7f61e..d5d15c51 100644 --- a/client/js/views/post_main_view.js +++ b/client/js/views/post_main_view.js @@ -31,6 +31,7 @@ class PostMainView { this._postContentControl = new PostContentControl( postContainerNode, ctx.post, + misc.isMediaCached(ctx.post), () => { const margin = sidebarNode.getBoundingClientRect().left;