From f4ca435657ae3882ce28fb3f427f9e0874733282 Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 7 May 2021 23:02:59 -0700 Subject: [PATCH 1/5] If one post fails to upload, don't prevent the rest from uploading --- .../js/controllers/post_upload_controller.js | 57 +++++++++++-------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/client/js/controllers/post_upload_controller.js b/client/js/controllers/post_upload_controller.js index d317be59..cfebb0a1 100644 --- a/client/js/controllers/post_upload_controller.js +++ b/client/js/controllers/post_upload_controller.js @@ -12,7 +12,7 @@ const PostUploadView = require("../views/post_upload_view.js"); const EmptyView = require("../views/empty_view.js"); const genericErrorMessage = - "One of the posts needs your attention; " + + "One or more posts needs your attention; " + 'click "resume upload" when you\'re ready.'; class PostUploadController { @@ -55,6 +55,7 @@ class PostUploadController { _evtSubmit(e) { this._view.disableForm(); this._view.clearMessages(); + let anyFailures = false; e.detail.uploadables .reduce( @@ -64,37 +65,43 @@ class PostUploadController { uploadable, e.detail.skipDuplicates ) + .catch((error) => { + anyFailures = true; + if (error.uploadable) { + if (error.similarPosts) { + error.uploadable.lookalikes = error.similarPosts; + this._view.updateUploadable(error.uploadable); + this._view.showInfo( + error.message, + error.uploadable + ); + } else { + this._view.showError( + error.message, + error.uploadable + ); + } + } else { + this._view.showError( + error.message, + error.uploadable + ); + } + }) ), Promise.resolve() ) .then( () => { - this._view.clearMessages(); - misc.disableExitConfirmation(); - const ctx = router.show(uri.formatClientLink("posts")); - ctx.controller.showSuccess("Posts uploaded."); - }, - (error) => { - if (error.uploadable) { - if (error.similarPosts) { - error.uploadable.lookalikes = error.similarPosts; - this._view.updateUploadable(error.uploadable); - this._view.showInfo(genericErrorMessage); - this._view.showInfo( - error.message, - error.uploadable - ); - } else { - this._view.showError(genericErrorMessage); - this._view.showError( - error.message, - error.uploadable - ); - } + if (anyFailures) { + this._view.showError(genericErrorMessage); + this._view.enableForm(); } else { - this._view.showError(error.message); + this._view.clearMessages(); + misc.disableExitConfirmation(); + const ctx = router.show(uri.formatClientLink("posts")); + ctx.controller.showSuccess("Posts uploaded."); } - this._view.enableForm(); } ); } From 516b3a51a754ee7f0e4ec30ac1a08db99eb8731b Mon Sep 17 00:00:00 2001 From: Ruin0x11 Date: Fri, 7 May 2021 23:11:29 -0700 Subject: [PATCH 2/5] Option to always upload similar posts instead of confirming every time --- client/css/post-upload.styl | 5 +++++ client/html/post_upload.tpl | 8 ++++++++ client/js/controllers/post_upload_controller.js | 9 +++++---- client/js/views/post_upload_view.js | 5 +++++ 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/client/css/post-upload.styl b/client/css/post-upload.styl index aa36e0a0..38362937 100644 --- a/client/css/post-upload.styl +++ b/client/css/post-upload.styl @@ -13,8 +13,10 @@ $cancel-button-color = tomato &.inactive input[type=submit], &.inactive .skip-duplicates + &.inactive .always-upload-similar &.uploading input[type=submit], &.uploading .skip-duplicates, + &.uploading .always-upload-similar &:not(.uploading) .cancel display: none @@ -39,6 +41,9 @@ $cancel-button-color = tomato .skip-duplicates margin-left: 1em + .always-upload-similar + margin-left: 1em + form>.messages margin-top: 1em diff --git a/client/html/post_upload.tpl b/client/html/post_upload.tpl index f1ed88fc..6374fe8c 100644 --- a/client/html/post_upload.tpl +++ b/client/html/post_upload.tpl @@ -13,6 +13,14 @@ }) %> + + <%= ctx.makeCheckbox({ + text: 'Always upload similar', + name: 'always-upload-similar', + checked: false, + }) %> + + diff --git a/client/js/controllers/post_upload_controller.js b/client/js/controllers/post_upload_controller.js index cfebb0a1..83ec2716 100644 --- a/client/js/controllers/post_upload_controller.js +++ b/client/js/controllers/post_upload_controller.js @@ -63,7 +63,8 @@ class PostUploadController { promise.then(() => this._uploadSinglePost( uploadable, - e.detail.skipDuplicates + e.detail.skipDuplicates, + e.detail.alwaysUploadSimilar ) .catch((error) => { anyFailures = true; @@ -84,7 +85,7 @@ class PostUploadController { } else { this._view.showError( error.message, - error.uploadable + uploadable ); } }) @@ -106,7 +107,7 @@ class PostUploadController { ); } - _uploadSinglePost(uploadable, skipDuplicates) { + _uploadSinglePost(uploadable, skipDuplicates, alwaysUploadSimilar) { progress.start(); let reverseSearchPromise = Promise.resolve(); if (!uploadable.lookalikesConfirmed) { @@ -135,7 +136,7 @@ class PostUploadController { } // notify about similar posts - if (searchResult.similarPosts.length) { + if (searchResult.similarPosts.length && !alwaysUploadSimilar) { let error = new Error( `Found ${searchResult.similarPosts.length} similar ` + "posts.\nYou can resume or discard this upload." diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index 7daf4fb0..49aab7f2 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -350,6 +350,7 @@ class PostUploadView extends events.EventTarget { detail: { uploadables: this._uploadables, skipDuplicates: this._skipDuplicatesCheckboxNode.checked, + alwaysUploadSimilar: this._alwaysUploadSimilarCheckboxNode.checked, }, }) ); @@ -413,6 +414,10 @@ class PostUploadView extends events.EventTarget { return this._hostNode.querySelector("form [name=skip-duplicates]"); } + get _alwaysUploadSimilarCheckboxNode() { + return this._hostNode.querySelector("form [name=always-upload-similar]"); + } + get _submitButtonNode() { return this._hostNode.querySelector("form [type=submit]"); } From e4a253fd2579719add519efa83c2aa28e3cb9a92 Mon Sep 17 00:00:00 2001 From: Shyam Sunder Date: Mon, 13 Sep 2021 12:58:28 -0400 Subject: [PATCH 3/5] client+server: fixed style errors --- client/js/controllers/home_controller.js | 2 +- client/js/controls/tag_input_control.js | 6 ++---- client/js/main.js | 6 +++--- server/szurubooru/func/image_hash.py | 5 +++-- server/szurubooru/func/images.py | 3 ++- server/szurubooru/func/mime.py | 1 + 6 files changed, 12 insertions(+), 11 deletions(-) diff --git a/client/js/controllers/home_controller.js b/client/js/controllers/home_controller.js index ea2a411c..528ce622 100644 --- a/client/js/controllers/home_controller.js +++ b/client/js/controllers/home_controller.js @@ -17,7 +17,7 @@ class HomeController { buildDate: config.meta.buildDate, canListSnapshots: api.hasPrivilege("snapshots:list"), canListPosts: api.hasPrivilege("posts:list"), - isDevelopmentMode: config.environment == "development" + isDevelopmentMode: config.environment == "development", }); Info.get().then( diff --git a/client/js/controls/tag_input_control.js b/client/js/controls/tag_input_control.js index a383d449..cca58d5b 100644 --- a/client/js/controls/tag_input_control.js +++ b/client/js/controls/tag_input_control.js @@ -196,11 +196,9 @@ class TagInputControl extends events.EventTarget { const listItemNode = this._createListItemNode(tag); if (!tag.category) { listItemNode.classList.add("new"); - } - else if (source === SOURCE_IMPLICATION) { + } else if (source === SOURCE_IMPLICATION) { listItemNode.classList.add("implication"); - } - else { + } else { listItemNode.classList.add("added"); } this._tagListNode.prependChild(listItemNode); diff --git a/client/js/main.js b/client/js/main.js index 2be2cd53..c5bdc537 100644 --- a/client/js/main.js +++ b/client/js/main.js @@ -4,12 +4,12 @@ const config = require("./config.js"); if (config.environment == "development") { var ws = new WebSocket("ws://" + location.hostname + ":8080"); - ws.addEventListener('open', function (event) { + ws.addEventListener("open", function (event) { console.log("Live-reloading websocket connected."); }); - ws.addEventListener('message', (event) => { + ws.addEventListener("message", (event) => { console.log(event); - if (event.data == 'reload'){ + if (event.data == "reload") { location.reload(); } }); diff --git a/server/szurubooru/func/image_hash.py b/server/szurubooru/func/image_hash.py index a445e62d..05b27a42 100644 --- a/server/szurubooru/func/image_hash.py +++ b/server/szurubooru/func/image_hash.py @@ -5,14 +5,15 @@ from io import BytesIO from typing import Any, Callable, List, Optional, Set, Tuple import numpy as np -from PIL import Image import pillow_avif import pyheif +from PIL import Image from pyheif_pillow_opener import register_heif_opener -register_heif_opener() from szurubooru import config, errors +register_heif_opener() + logger = logging.getLogger(__name__) # Math based on paper from H. Chi Wong, Marshall Bern and David Goldberg diff --git a/server/szurubooru/func/images.py b/server/szurubooru/func/images.py index 101bba8c..de41222f 100644 --- a/server/szurubooru/func/images.py +++ b/server/szurubooru/func/images.py @@ -6,6 +6,7 @@ import shlex import subprocess from io import BytesIO from typing import List + from PIL import Image as PILImage from szurubooru import errors @@ -17,7 +18,7 @@ logger = logging.getLogger(__name__) def convert_heif_to_png(content: bytes) -> bytes: img = PILImage.open(BytesIO(content)) img_byte_arr = BytesIO() - img.save(img_byte_arr, format='PNG') + img.save(img_byte_arr, format="PNG") return img_byte_arr.getvalue() diff --git a/server/szurubooru/func/mime.py b/server/szurubooru/func/mime.py index 93c096b1..3be43f77 100644 --- a/server/szurubooru/func/mime.py +++ b/server/szurubooru/func/mime.py @@ -88,6 +88,7 @@ def is_animated_gif(content: bytes) -> bool: and len(re.findall(pattern, content)) > 1 ) + def is_heif(mime_type: str) -> bool: return mime_type.lower() in ( "image/heif", From f5338ca508bdcc0a2b30fe98dd3734f6343d407e Mon Sep 17 00:00:00 2001 From: Shyam Sunder Date: Mon, 13 Sep 2021 13:26:57 -0400 Subject: [PATCH 4/5] Fix style --- .../js/controllers/post_upload_controller.js | 37 ++++++++++--------- client/js/views/post_upload_view.js | 7 +++- 2 files changed, 25 insertions(+), 19 deletions(-) diff --git a/client/js/controllers/post_upload_controller.js b/client/js/controllers/post_upload_controller.js index 83ec2716..a54baec7 100644 --- a/client/js/controllers/post_upload_controller.js +++ b/client/js/controllers/post_upload_controller.js @@ -65,13 +65,15 @@ class PostUploadController { uploadable, e.detail.skipDuplicates, e.detail.alwaysUploadSimilar - ) - .catch((error) => { + ).catch((error) => { anyFailures = true; if (error.uploadable) { if (error.similarPosts) { - error.uploadable.lookalikes = error.similarPosts; - this._view.updateUploadable(error.uploadable); + error.uploadable.lookalikes = + error.similarPosts; + this._view.updateUploadable( + error.uploadable + ); this._view.showInfo( error.message, error.uploadable @@ -92,19 +94,17 @@ class PostUploadController { ), Promise.resolve() ) - .then( - () => { - if (anyFailures) { - this._view.showError(genericErrorMessage); - this._view.enableForm(); - } else { - this._view.clearMessages(); - misc.disableExitConfirmation(); - const ctx = router.show(uri.formatClientLink("posts")); - ctx.controller.showSuccess("Posts uploaded."); - } + .then(() => { + if (anyFailures) { + this._view.showError(genericErrorMessage); + this._view.enableForm(); + } else { + this._view.clearMessages(); + misc.disableExitConfirmation(); + const ctx = router.show(uri.formatClientLink("posts")); + ctx.controller.showSuccess("Posts uploaded."); } - ); + }); } _uploadSinglePost(uploadable, skipDuplicates, alwaysUploadSimilar) { @@ -136,7 +136,10 @@ class PostUploadController { } // notify about similar posts - if (searchResult.similarPosts.length && !alwaysUploadSimilar) { + if ( + searchResult.similarPosts.length && + !alwaysUploadSimilar + ) { let error = new Error( `Found ${searchResult.similarPosts.length} similar ` + "posts.\nYou can resume or discard this upload." diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index 49aab7f2..0e8489bb 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -350,7 +350,8 @@ class PostUploadView extends events.EventTarget { detail: { uploadables: this._uploadables, skipDuplicates: this._skipDuplicatesCheckboxNode.checked, - alwaysUploadSimilar: this._alwaysUploadSimilarCheckboxNode.checked, + alwaysUploadSimilar: this._alwaysUploadSimilarCheckboxNode + .checked, }, }) ); @@ -415,7 +416,9 @@ class PostUploadView extends events.EventTarget { } get _alwaysUploadSimilarCheckboxNode() { - return this._hostNode.querySelector("form [name=always-upload-similar]"); + return this._hostNode.querySelector( + "form [name=always-upload-similar]" + ); } get _submitButtonNode() { From f58079e12edd3c4dcc3f8b8dab572207b235aeff Mon Sep 17 00:00:00 2001 From: Shyam Sunder Date: Mon, 13 Sep 2021 14:24:07 -0400 Subject: [PATCH 5/5] client/upload: force enable 'upload anonymously' for anon users Fixes #425 --- client/html/post_upload_row.tpl | 1 + client/js/views/post_upload_view.js | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/client/html/post_upload_row.tpl b/client/html/post_upload_row.tpl index c7cc5dba..2885e3d7 100644 --- a/client/html/post_upload_row.tpl +++ b/client/html/post_upload_row.tpl @@ -61,6 +61,7 @@ text: 'Upload anonymously', name: 'anonymous', checked: ctx.uploadable.anonymous, + readonly: ctx.uploadable.forceAnonymous, }) %> <% } %> diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index b92a9aef..7fdd4a4f 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -1,6 +1,7 @@ "use strict"; const events = require("../events.js"); +const api = require("../api.js"); const views = require("../util/views.js"); const FileDropperControl = require("../controls/file_dropper_control.js"); @@ -34,7 +35,8 @@ class Uploadable extends events.EventTarget { this.flags = []; this.tags = []; this.relations = []; - this.anonymous = false; + this.anonymous = !api.isLoggedIn(); + this.forceAnonymous = !api.isLoggedIn(); } destroy() {}