From f90c190bafcc38d6799d818d09802e108c5582b8 Mon Sep 17 00:00:00 2001 From: neobooru <50623835+neobooru@users.noreply.github.com> Date: Wed, 21 Feb 2024 01:46:28 +0100 Subject: [PATCH 1/9] Pin pillow-avif-plugin to compatible version range --- server/Dockerfile | 8 ++++---- server/requirements.txt | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/server/Dockerfile b/server/Dockerfile index c2640f16..3e4dadfb 100644 --- a/server/Dockerfile +++ b/server/Dockerfile @@ -23,15 +23,15 @@ RUN apk --no-cache add \ py3-pillow \ py3-pynacl \ py3-tz \ - py3-pyrfc3339 \ - && pip3 install --no-cache-dir --disable-pip-version-check \ + py3-pyrfc3339 +RUN pip3 install --no-cache-dir --disable-pip-version-check \ "alembic>=0.8.5" \ "coloredlogs==5.0" \ "pyheif==0.6.1" \ "heif-image-plugin>=0.3.2" \ yt-dlp \ - "pillow-avif-plugin>=1.1.0" \ - && apk --no-cache del py3-pip + "pillow-avif-plugin~=1.1.0" +RUN apk --no-cache del py3-pip COPY ./ /opt/app/ RUN rm -rf /opt/app/szurubooru/tests diff --git a/server/requirements.txt b/server/requirements.txt index ceff0b8d..ffe18f0c 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -3,7 +3,7 @@ certifi>=2017.11.5 coloredlogs==5.0 heif-image-plugin==0.3.2 numpy>=1.8.2 -pillow-avif-plugin>=1.1.0 +pillow-avif-plugin~=1.1.0 pillow>=4.3.0 psycopg2-binary>=2.6.1 pyheif==0.6.1 From 881cfe026cd3a369d0f26b190c33c3019c5c8d43 Mon Sep 17 00:00:00 2001 From: Fabricio Winter Date: Fri, 30 Dec 2022 13:07:34 -0300 Subject: [PATCH 2/9] Default upload tags --- client/css/post-upload.styl | 4 ++++ client/html/post_upload.tpl | 2 ++ client/js/views/post_upload_view.js | 23 +++++++++++++++++++++++ 3 files changed, 29 insertions(+) diff --git a/client/css/post-upload.styl b/client/css/post-upload.styl index cb6b0067..9d15e218 100644 --- a/client/css/post-upload.styl +++ b/client/css/post-upload.styl @@ -15,6 +15,7 @@ $cancel-button-color = tomato &.inactive .skip-duplicates &.inactive .always-upload-similar &.inactive .pause-remain-on-error + &.inactive #common-tags, &.uploading input[type=submit], &.uploading .skip-duplicates, &.uploading .always-upload-similar @@ -30,6 +31,9 @@ $cancel-button-color = tomato small font-size: 60% + label[for=common-tags] + display: none !important + input[type=submit] margin-top: 1em diff --git a/client/html/post_upload.tpl b/client/html/post_upload.tpl index 3c1b2388..54a9871d 100644 --- a/client/html/post_upload.tpl +++ b/client/html/post_upload.tpl @@ -29,6 +29,8 @@ }) %> + <%= ctx.makeTextInput({placeholder: 'Common tags', id: 'common-tags', name: 'common-tags', style: 'margin-top:1em;'}) %> + diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index 4ef4c1ad..ccabacf6 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -8,6 +8,10 @@ const FileDropperControl = require("../controls/file_dropper_control.js"); const template = views.getTemplate("post-upload"); const rowTemplate = views.getTemplate("post-upload-row"); +const misc = require('../util/misc.js'); +const TagAutoCompleteControl = + require('../controls/tag_auto_complete_control.js'); + function _mimeTypeToPostType(mimeType) { return ( { @@ -185,6 +189,16 @@ class PostUploadView extends events.EventTarget { this._evtFormSubmit(e) ); this._formNode.classList.add("inactive"); + + if (this._commonTagsInputNode) { + this._autoCompleteControl = new TagAutoCompleteControl( + this._commonTagsInputNode, + { + confirm: tag => + this._autoCompleteControl.replaceSelectedText( + misc.escapeSearchTerm(tag.names[0]), true), + }); + } } enableForm() { @@ -307,6 +321,11 @@ class PostUploadView extends events.EventTarget { } uploadable.tags = []; + if (this._commonTagsInputNode) { + var tags = this._commonTagsInputNode.value.split(' '); + tags = tags.filter(t => t != ""); + uploadable.tags = uploadable.tags.concat(tags); + } uploadable.relations = []; for (let [i, lookalike] of uploadable.lookalikes.entries()) { let lookalikeNode = rowNode.querySelector( @@ -452,6 +471,10 @@ class PostUploadView extends events.EventTarget { get _contentInputNode() { return this._formNode.querySelector(".dropper-container"); } + + get _commonTagsInputNode() { + return this._formNode.querySelector('form [name=common-tags'); + } } module.exports = PostUploadView; From 9533de5c8c03fa23cce08c0c97aa39c898981608 Mon Sep 17 00:00:00 2001 From: Fabricio Winter Date: Fri, 30 Dec 2022 13:15:25 -0300 Subject: [PATCH 3/9] Allow default anonymous uploads --- client/css/post-upload.styl | 3 +++ client/html/post_upload.tpl | 8 ++++++++ client/js/views/post_upload_view.js | 13 ++++++++----- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/client/css/post-upload.styl b/client/css/post-upload.styl index 9d15e218..e362be2a 100644 --- a/client/css/post-upload.styl +++ b/client/css/post-upload.styl @@ -53,6 +53,9 @@ $cancel-button-color = tomato .pause-remain-on-error margin-left: 1em + .upload-all-anonymous + margin-left: 1em + form>.messages margin-top: 1em diff --git a/client/html/post_upload.tpl b/client/html/post_upload.tpl index 54a9871d..de5d32ee 100644 --- a/client/html/post_upload.tpl +++ b/client/html/post_upload.tpl @@ -29,6 +29,14 @@ }) %> + + <%= ctx.makeCheckbox({ + text: 'Upload anonymously', + name: 'upload-all-anonymous', + checked: false, + }) %> + + <%= ctx.makeTextInput({placeholder: 'Common tags', id: 'common-tags', name: 'common-tags', style: 'margin-top:1em;'}) %> diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index ccabacf6..33c40de1 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -313,12 +313,11 @@ class PostUploadView extends events.EventTarget { uploadable.safety = safetyNode.value; } - const anonymousNode = rowNode.querySelector( - ".anonymous input:checked" - ); - if (anonymousNode) { - uploadable.anonymous = true; + let anonymous = this._uploadAllAnonymous?.checked; + if (!anonymous) { + anonymous = rowNode.querySelector(".anonymous input:checked"); } + uploadable.anonymous = anonymous; uploadable.tags = []; if (this._commonTagsInputNode) { @@ -460,6 +459,10 @@ class PostUploadView extends events.EventTarget { ); } + get _uploadAllAnonymous() { + return this._hostNode.querySelector("form [name=upload-all-anonymous]"); + } + get _submitButtonNode() { return this._hostNode.querySelector("form [type=submit]"); } From ec39500bbd5b4e348d98f10b1f59f1333b5cef6c Mon Sep 17 00:00:00 2001 From: Fabricio Winter Date: Fri, 30 Dec 2022 13:29:33 -0300 Subject: [PATCH 4/9] Remove nullcheck operator --- client/js/views/post_upload_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index 33c40de1..fdeb28f7 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -313,7 +313,7 @@ class PostUploadView extends events.EventTarget { uploadable.safety = safetyNode.value; } - let anonymous = this._uploadAllAnonymous?.checked; + let anonymous = this._uploadAllAnonymous.checked; if (!anonymous) { anonymous = rowNode.querySelector(".anonymous input:checked"); } From a06b3bb37f9811f8f2501e572cd219b3b108b76b Mon Sep 17 00:00:00 2001 From: Fabricio Winter Date: Fri, 30 Dec 2022 13:47:08 -0300 Subject: [PATCH 5/9] Better layout for upload options --- client/css/post-upload.styl | 11 ++++++ client/html/post_upload.tpl | 60 +++++++++++++++-------------- client/js/views/post_upload_view.js | 2 +- 3 files changed, 43 insertions(+), 30 deletions(-) diff --git a/client/css/post-upload.styl b/client/css/post-upload.styl index e362be2a..8b2ee83e 100644 --- a/client/css/post-upload.styl +++ b/client/css/post-upload.styl @@ -15,11 +15,13 @@ $cancel-button-color = tomato &.inactive .skip-duplicates &.inactive .always-upload-similar &.inactive .pause-remain-on-error + &.inactive .upload-all-anonymous &.inactive #common-tags, &.uploading input[type=submit], &.uploading .skip-duplicates, &.uploading .always-upload-similar &.uploading .pause-remain-on-error + &.uploading .upload-all-anonymous &:not(.uploading) .cancel display: none @@ -59,6 +61,15 @@ $cancel-button-color = tomato form>.messages margin-top: 1em + .control-strip + display: flex + flex-direction: column + gap: 0.5em + + .control-options + display: flex + flex-direction: column + .uploadables-container list-style-type: none margin: 0 diff --git a/client/html/post_upload.tpl b/client/html/post_upload.tpl index de5d32ee..83968eb9 100644 --- a/client/html/post_upload.tpl +++ b/client/html/post_upload.tpl @@ -5,39 +5,41 @@
- - <%= ctx.makeCheckbox({ - text: 'Skip duplicate', - name: 'skip-duplicates', - checked: false, - }) %> - +
+ + <%= ctx.makeCheckbox({ + text: 'Skip duplicate', + name: 'skip-duplicates', + checked: false, + }) %> + - - <%= ctx.makeCheckbox({ - text: 'Force upload similar', - name: 'always-upload-similar', - checked: false, - }) %> - + + <%= ctx.makeCheckbox({ + text: 'Force upload similar', + name: 'always-upload-similar', + checked: false, + }) %> + - - <%= ctx.makeCheckbox({ - text: 'Pause on error', - name: 'pause-remain-on-error', - checked: true, - }) %> - + + <%= ctx.makeCheckbox({ + text: 'Pause on error', + name: 'pause-remain-on-error', + checked: true, + }) %> + - - <%= ctx.makeCheckbox({ - text: 'Upload anonymously', - name: 'upload-all-anonymous', - checked: false, - }) %> - + + <%= ctx.makeCheckbox({ + text: 'Upload anonymously', + name: 'upload-all-anonymous', + checked: false, + }) %> + +
- <%= ctx.makeTextInput({placeholder: 'Common tags', id: 'common-tags', name: 'common-tags', style: 'margin-top:1em;'}) %> + <%= ctx.makeTextInput({placeholder: 'Common tags', id: 'common-tags', name: 'common-tags'}) %>
diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index fdeb28f7..9f416a86 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -476,7 +476,7 @@ class PostUploadView extends events.EventTarget { } get _commonTagsInputNode() { - return this._formNode.querySelector('form [name=common-tags'); + return this._formNode.querySelector('form [name=common-tags]'); } } From d17d37ceb0c0d11e1f40b2665dc0b0faca752be4 Mon Sep 17 00:00:00 2001 From: Fabricio Winter Date: Fri, 30 Dec 2022 13:49:59 -0300 Subject: [PATCH 6/9] Fix tag name escaping on upload --- client/js/views/post_upload_view.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index 9f416a86..ab4f1731 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -322,7 +322,7 @@ class PostUploadView extends events.EventTarget { uploadable.tags = []; if (this._commonTagsInputNode) { var tags = this._commonTagsInputNode.value.split(' '); - tags = tags.filter(t => t != ""); + tags = tags.filter(t => t != "").map(t => t.replace('\\', '')); uploadable.tags = uploadable.tags.concat(tags); } uploadable.relations = []; From 66143dce20c035bdffae175f30e660b8ee683cb0 Mon Sep 17 00:00:00 2001 From: neobooru <50623835+neobooru@users.noreply.github.com> Date: Mon, 26 Jun 2023 20:51:25 +0200 Subject: [PATCH 7/9] client: Use expanders and full tag input control on the upload page --- client/css/expander-control.styl | 2 +- client/css/post-upload.styl | 39 ++++++++++++++--------------- client/html/post_upload.tpl | 7 +++--- client/js/views/post_upload_view.js | 36 +++++++++++++++----------- 4 files changed, 46 insertions(+), 38 deletions(-) diff --git a/client/css/expander-control.styl b/client/css/expander-control.styl index 8f689570..37b51d39 100644 --- a/client/css/expander-control.styl +++ b/client/css/expander-control.styl @@ -19,7 +19,7 @@ font-size: 1em color: $inactive-link-color float: right - line-height: 2em + line-height: 2rem .expander-content padding: 0.5em 0.5em 2em 0.5em diff --git a/client/css/post-upload.styl b/client/css/post-upload.styl index 8b2ee83e..ec4555d1 100644 --- a/client/css/post-upload.styl +++ b/client/css/post-upload.styl @@ -16,15 +16,21 @@ $cancel-button-color = tomato &.inactive .always-upload-similar &.inactive .pause-remain-on-error &.inactive .upload-all-anonymous + &.inactive .expander &.inactive #common-tags, &.uploading input[type=submit], &.uploading .skip-duplicates, &.uploading .always-upload-similar &.uploading .pause-remain-on-error &.uploading .upload-all-anonymous + &.uploading .expander &:not(.uploading) .cancel display: none + &.inactive .control-strip + &.uploading .control-strip + gap: 0 + .dropper-container margin: 0 auto .file-dropper @@ -33,42 +39,35 @@ $cancel-button-color = tomato small font-size: 60% - label[for=common-tags] - display: none !important - - input[type=submit] - margin-top: 1em + .expander + &.collapsed + margin-bottom: 0 + .expander-content + padding: 0.5em .cancel - margin-top: 1em background: $cancel-button-color border-color: $cancel-button-color &:focus border: 2px solid $text-color - .skip-duplicates - margin-left: 1em - - .always-upload-similar - margin-left: 1em - - .pause-remain-on-error - margin-left: 1em - - .upload-all-anonymous - margin-left: 1em - form>.messages margin-top: 1em .control-strip display: flex flex-direction: column - gap: 0.5em + gap: 1em + margin-top: 1em .control-options display: flex - flex-direction: column + flex-wrap: wrap + gap: 0 1em + + span + flex: 1 1 30% + white-space: nowrap .uploadables-container list-style-type: none diff --git a/client/html/post_upload.tpl b/client/html/post_upload.tpl index 83968eb9..5240e306 100644 --- a/client/html/post_upload.tpl +++ b/client/html/post_upload.tpl @@ -3,8 +3,6 @@
- -
<%= ctx.makeCheckbox({ @@ -39,8 +37,11 @@
- <%= ctx.makeTextInput({placeholder: 'Common tags', id: 'common-tags', name: 'common-tags'}) %> +
+ <%= ctx.makeTextInput({name: 'common-tags'}) %> +
+
diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index ab4f1731..f1dbe2d5 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -4,13 +4,13 @@ const events = require("../events.js"); const api = require("../api.js"); const views = require("../util/views.js"); const FileDropperControl = require("../controls/file_dropper_control.js"); +const ExpanderControl = require("../controls/expander_control.js"); +const TagInputControl = require("../controls/tag_input_control.js"); const template = views.getTemplate("post-upload"); const rowTemplate = views.getTemplate("post-upload-row"); -const misc = require('../util/misc.js'); -const TagAutoCompleteControl = - require('../controls/tag_auto_complete_control.js'); +const TagList = require("../models/tag_list.js"); function _mimeTypeToPostType(mimeType) { return ( @@ -164,6 +164,7 @@ class PostUploadView extends events.EventTarget { this._uploadables.find = (u) => { return this._uploadables.findIndex((u2) => u.key === u2.key); }; + this._commonTags = new TagList(); this._contentFileDropper = new FileDropperControl( this._contentInputNode, @@ -190,14 +191,21 @@ class PostUploadView extends events.EventTarget { ); this._formNode.classList.add("inactive"); + this._commonTagsExpander = new ExpanderControl( + "common-tags", + "Common Tags (0)", + this._hostNode.querySelectorAll(".common-tags") + ); + if (this._commonTagsInputNode) { - this._autoCompleteControl = new TagAutoCompleteControl( + this._commonTagsControl = new TagInputControl( this._commonTagsInputNode, - { - confirm: tag => - this._autoCompleteControl.replaceSelectedText( - misc.escapeSearchTerm(tag.names[0]), true), - }); + this._commonTags + ); + + this._commonTagsControl.addEventListener("change", (_) => { + this._commonTagsExpander.title = `Common Tags (${this._commonTags.length})`; + }); } } @@ -321,9 +329,7 @@ class PostUploadView extends events.EventTarget { uploadable.tags = []; if (this._commonTagsInputNode) { - var tags = this._commonTagsInputNode.value.split(' '); - tags = tags.filter(t => t != "").map(t => t.replace('\\', '')); - uploadable.tags = uploadable.tags.concat(tags); + uploadable.tags = this._commonTags.map((tag) => tag.names[0]); } uploadable.relations = []; for (let [i, lookalike] of uploadable.lookalikes.entries()) { @@ -460,7 +466,9 @@ class PostUploadView extends events.EventTarget { } get _uploadAllAnonymous() { - return this._hostNode.querySelector("form [name=upload-all-anonymous]"); + return this._hostNode.querySelector( + "form [name=upload-all-anonymous]" + ); } get _submitButtonNode() { @@ -476,7 +484,7 @@ class PostUploadView extends events.EventTarget { } get _commonTagsInputNode() { - return this._formNode.querySelector('form [name=common-tags]'); + return this._formNode.querySelector(".common-tags input"); } } From 94d145e8d00a973744c0748adb4236c8831001a7 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 19 May 2023 17:52:34 +0200 Subject: [PATCH 8/9] client/views: fix incorrectly 'checked' checkboxes When similar posts were found, the anonymous upload checkbox for that image would become checked, because we treat anything !== undefined as 'checked', and in post_upload_views.js we set 'anonymous' to a querySelector, which returns null on failure and not undefined. Treat null as 'unchecked' to fix this issue, and prevent future mistakes slipping past. --- client/js/util/views.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/js/util/views.js b/client/js/util/views.js index 38c98a13..1cbd371f 100644 --- a/client/js/util/views.js +++ b/client/js/util/views.js @@ -81,7 +81,7 @@ function makeCheckbox(options) { name: options.name, value: options.value, type: "checkbox", - checked: options.checked !== undefined ? options.checked : false, + checked: options.checked !== undefined && options.checked !== null ? options.checked : false, disabled: options.readonly, required: options.required, }), From d120f00fb5eaa7c49619dee4b280345676157400 Mon Sep 17 00:00:00 2001 From: Eva Date: Fri, 19 May 2023 18:25:20 +0200 Subject: [PATCH 9/9] client/upload: send state of image's anonymous checkbox as boolean Anonymous checkbox on images would not actually do anything, when the global checkbox was unchecked. The value of anonymous becomes a node, and it fails the anonymous === true check in save(). I don't understand why anonymous is treated differently from other post parameters and supplied as an argument to save(). Keeping it the way it is, I guess... --- client/js/views/post_upload_view.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/js/views/post_upload_view.js b/client/js/views/post_upload_view.js index f1dbe2d5..77eee672 100644 --- a/client/js/views/post_upload_view.js +++ b/client/js/views/post_upload_view.js @@ -322,8 +322,8 @@ class PostUploadView extends events.EventTarget { } let anonymous = this._uploadAllAnonymous.checked; - if (!anonymous) { - anonymous = rowNode.querySelector(".anonymous input:checked"); + if (!anonymous && rowNode.querySelector(".anonymous input:checked")) { + anonymous = true; } uploadable.anonymous = anonymous;