summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLibravatar kim <89579420+NyaaaWhatsUpDoc@users.noreply.github.com>2024-11-04 14:00:10 +0000
committerLibravatar GitHub <noreply@github.com>2024-11-04 15:00:10 +0100
commitf3b2eca8b86c797170d198d2aeb16a4cadd71e41 (patch)
treee387216c9d91e1fefb50a02cee84c9e166558336
parent[bugfix] determine mime-type to use during ffprobe evaluation stage, don't bo... (diff)
downloadgotosocial-f3b2eca8b86c797170d198d2aeb16a4cadd71e41.tar.xz
[feature] add support for hinting via api/v_/instance preferred image / video max sizes (#3505)
* add support for hinting via api/v_/instance endpoints a preferred image / video size limit * fix tests expecting old default values
-rw-r--r--docs/configuration/media.md18
-rw-r--r--example/config.yaml18
-rw-r--r--internal/api/client/instance/instancepatch_test.go36
-rw-r--r--internal/config/config.go2
-rw-r--r--internal/config/helpers.gen.go50
-rw-r--r--internal/typeutils/internaltofrontend.go65
-rw-r--r--internal/typeutils/internaltofrontend_test.go12
-rwxr-xr-xtest/envparsing.sh4
8 files changed, 161 insertions, 44 deletions
diff --git a/docs/configuration/media.md b/docs/configuration/media.md
index 4e222c6c7..e49b59dd3 100644
--- a/docs/configuration/media.md
+++ b/docs/configuration/media.md
@@ -18,6 +18,24 @@
# Default: 40MiB (41943040 bytes)
media-local-max-size: 40MiB
+# Size. Size in bytes of max image size referred to on /api/v_/instance endpoints,
+# used by applications like Tusky to automatically scale locally uploaded media.
+#
+# Leaving this unset will default to media-local-max-size.
+#
+# Examples: [64, 500, 5MiB, 5MB, 50M]
+# Default: unset
+media-image-size-hint: 5MiB
+
+# Size. Size in bytes of max video size referred to on /api/v_/instance endpoints,
+# used by applications like Tusky to automatically scale locally uploaded media.
+#
+# Leaving this unset will default to media-local-max-size.
+#
+# Examples: [64, 4096, 4MiB, 4MB, 40M]
+# Default: unset
+media-video-size-hint: 40MiB
+
# Size. Max size in bytes of media to download from other instances.
#
# Lowering this limit may cause your instance not to fetch post media.
diff --git a/example/config.yaml b/example/config.yaml
index d3de40791..644b51575 100644
--- a/example/config.yaml
+++ b/example/config.yaml
@@ -471,6 +471,24 @@ accounts-custom-css-length: 10000
# Default: 40MiB (41943040 bytes)
media-local-max-size: 40MiB
+# Size. Size in bytes of max image size referred to on /api/v_/instance endpoints,
+# used by applications like Tusky to automatically scale locally uploaded media.
+#
+# Leaving this unset will default to media-local-max-size.
+#
+# Examples: [64, 500, 5MiB, 5MB, 50M]
+# Default: unset
+media-image-size-hint: 5MiB
+
+# Size. Size in bytes of max video size referred to on /api/v_/instance endpoints,
+# used by applications like Tusky to automatically scale locally uploaded media.
+#
+# Leaving this unset will default to media-local-max-size.
+#
+# Examples: [64, 4096, 4MiB, 4MB, 40M]
+# Default: unset
+media-video-size-hint: 40MiB
+
# Size. Max size in bytes of media to download from other instances.
#
# Lowering this limit may cause your instance not to fetch post media.
diff --git a/internal/api/client/instance/instancepatch_test.go b/internal/api/client/instance/instancepatch_test.go
index 504fd7eb9..3a362f27c 100644
--- a/internal/api/client/instance/instancepatch_test.go
+++ b/internal/api/client/instance/instancepatch_test.go
@@ -130,10 +130,10 @@ func (suite *InstancePatchTestSuite) TestInstancePatch1() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
@@ -271,10 +271,10 @@ func (suite *InstancePatchTestSuite) TestInstancePatch2() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
@@ -412,10 +412,10 @@ func (suite *InstancePatchTestSuite) TestInstancePatch3() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
@@ -604,10 +604,10 @@ func (suite *InstancePatchTestSuite) TestInstancePatch6() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
@@ -767,10 +767,10 @@ func (suite *InstancePatchTestSuite) TestInstancePatch8() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
@@ -949,10 +949,10 @@ func (suite *InstancePatchTestSuite) TestInstancePatch9() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
diff --git a/internal/config/config.go b/internal/config/config.go
index 4a40e9c13..9001b61d0 100644
--- a/internal/config/config.go
+++ b/internal/config/config.go
@@ -98,6 +98,8 @@ type Configuration struct {
MediaRemoteCacheDays int `name:"media-remote-cache-days" usage:"Number of days to locally cache media from remote instances. If set to 0, remote media will be kept indefinitely."`
MediaEmojiLocalMaxSize bytesize.Size `name:"media-emoji-local-max-size" usage:"Max size in bytes of emojis uploaded to this instance via the admin API."`
MediaEmojiRemoteMaxSize bytesize.Size `name:"media-emoji-remote-max-size" usage:"Max size in bytes of emojis to download from other instances."`
+ MediaImageSizeHint bytesize.Size `name:"media-image-size-hint" usage:"Size in bytes of max image size referred to on /api/v_/instance endpoints (else, local max size)"`
+ MediaVideoSizeHint bytesize.Size `name:"media-video-size-hint" usage:"Size in bytes of max video size referred to on /api/v_/instance endpoints (else, local max size)"`
MediaLocalMaxSize bytesize.Size `name:"media-local-max-size" usage:"Max size in bytes of media uploaded to this instance via API"`
MediaRemoteMaxSize bytesize.Size `name:"media-remote-max-size" usage:"Max size in bytes of media to download from other instances"`
MediaCleanupFrom string `name:"media-cleanup-from" usage:"Time of day from which to start running media cleanup/prune jobs. Should be in the format 'hh:mm:ss', eg., '15:04:05'."`
diff --git a/internal/config/helpers.gen.go b/internal/config/helpers.gen.go
index d25d6cca8..2a7e5b6ad 100644
--- a/internal/config/helpers.gen.go
+++ b/internal/config/helpers.gen.go
@@ -1225,6 +1225,56 @@ func GetMediaEmojiRemoteMaxSize() bytesize.Size { return global.GetMediaEmojiRem
// SetMediaEmojiRemoteMaxSize safely sets the value for global configuration 'MediaEmojiRemoteMaxSize' field
func SetMediaEmojiRemoteMaxSize(v bytesize.Size) { global.SetMediaEmojiRemoteMaxSize(v) }
+// GetMediaImageSizeHint safely fetches the Configuration value for state's 'MediaImageSizeHint' field
+func (st *ConfigState) GetMediaImageSizeHint() (v bytesize.Size) {
+ st.mutex.RLock()
+ v = st.config.MediaImageSizeHint
+ st.mutex.RUnlock()
+ return
+}
+
+// SetMediaImageSizeHint safely sets the Configuration value for state's 'MediaImageSizeHint' field
+func (st *ConfigState) SetMediaImageSizeHint(v bytesize.Size) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaImageSizeHint = v
+ st.reloadToViper()
+}
+
+// MediaImageSizeHintFlag returns the flag name for the 'MediaImageSizeHint' field
+func MediaImageSizeHintFlag() string { return "media-image-size-hint" }
+
+// GetMediaImageSizeHint safely fetches the value for global configuration 'MediaImageSizeHint' field
+func GetMediaImageSizeHint() bytesize.Size { return global.GetMediaImageSizeHint() }
+
+// SetMediaImageSizeHint safely sets the value for global configuration 'MediaImageSizeHint' field
+func SetMediaImageSizeHint(v bytesize.Size) { global.SetMediaImageSizeHint(v) }
+
+// GetMediaVideoSizeHint safely fetches the Configuration value for state's 'MediaVideoSizeHint' field
+func (st *ConfigState) GetMediaVideoSizeHint() (v bytesize.Size) {
+ st.mutex.RLock()
+ v = st.config.MediaVideoSizeHint
+ st.mutex.RUnlock()
+ return
+}
+
+// SetMediaVideoSizeHint safely sets the Configuration value for state's 'MediaVideoSizeHint' field
+func (st *ConfigState) SetMediaVideoSizeHint(v bytesize.Size) {
+ st.mutex.Lock()
+ defer st.mutex.Unlock()
+ st.config.MediaVideoSizeHint = v
+ st.reloadToViper()
+}
+
+// MediaVideoSizeHintFlag returns the flag name for the 'MediaVideoSizeHint' field
+func MediaVideoSizeHintFlag() string { return "media-video-size-hint" }
+
+// GetMediaVideoSizeHint safely fetches the value for global configuration 'MediaVideoSizeHint' field
+func GetMediaVideoSizeHint() bytesize.Size { return global.GetMediaVideoSizeHint() }
+
+// SetMediaVideoSizeHint safely sets the value for global configuration 'MediaVideoSizeHint' field
+func SetMediaVideoSizeHint(v bytesize.Size) { global.SetMediaVideoSizeHint(v) }
+
// GetMediaLocalMaxSize safely fetches the Configuration value for state's 'MediaLocalMaxSize' field
func (st *ConfigState) GetMediaLocalMaxSize() (v bytesize.Size) {
st.mutex.RLock()
diff --git a/internal/typeutils/internaltofrontend.go b/internal/typeutils/internaltofrontend.go
index 03b24fc9c..2a6d495d7 100644
--- a/internal/typeutils/internaltofrontend.go
+++ b/internal/typeutils/internaltofrontend.go
@@ -18,9 +18,11 @@
package typeutils
import (
+ "cmp"
"context"
"errors"
"fmt"
+ "math"
"slices"
"strconv"
"strings"
@@ -42,16 +44,13 @@ import (
)
const (
- instanceStatusesCharactersReservedPerURL = 25
- instanceMediaAttachmentsImageMatrixLimit = 16777216 // width * height
- instanceMediaAttachmentsVideoMatrixLimit = 16777216 // width * height
- instanceMediaAttachmentsVideoFrameRateLimit = 60
- instancePollsMinExpiration = 300 // seconds
- instancePollsMaxExpiration = 2629746 // seconds
- instanceAccountsMaxFeaturedTags = 10
- instanceAccountsMaxProfileFields = 6 // FIXME: https://github.com/superseriousbusiness/gotosocial/issues/1876
- instanceSourceURL = "https://github.com/superseriousbusiness/gotosocial"
- instanceMastodonVersion = "3.5.3"
+ instanceStatusesCharactersReservedPerURL = 25
+ instancePollsMinExpiration = 300 // seconds
+ instancePollsMaxExpiration = 2629746 // seconds
+ instanceAccountsMaxFeaturedTags = 10
+ instanceAccountsMaxProfileFields = 6 // FIXME: https://github.com/superseriousbusiness/gotosocial/issues/1876
+ instanceSourceURL = "https://github.com/superseriousbusiness/gotosocial"
+ instanceMastodonVersion = "3.5.3"
)
var instanceStatusesSupportedMimeTypes = []string{
@@ -1563,11 +1562,24 @@ func (c *Converter) InstanceToAPIV1Instance(ctx context.Context, i *gtsmodel.Ins
instance.Configuration.Statuses.CharactersReservedPerURL = instanceStatusesCharactersReservedPerURL
instance.Configuration.Statuses.SupportedMimeTypes = instanceStatusesSupportedMimeTypes
instance.Configuration.MediaAttachments.SupportedMimeTypes = media.SupportedMIMETypes
- instance.Configuration.MediaAttachments.ImageSizeLimit = int(config.GetMediaRemoteMaxSize()) // #nosec G115 -- Already validated.
- instance.Configuration.MediaAttachments.ImageMatrixLimit = instanceMediaAttachmentsImageMatrixLimit
- instance.Configuration.MediaAttachments.VideoSizeLimit = int(config.GetMediaRemoteMaxSize()) // #nosec G115 -- Already validated.
- instance.Configuration.MediaAttachments.VideoFrameRateLimit = instanceMediaAttachmentsVideoFrameRateLimit
- instance.Configuration.MediaAttachments.VideoMatrixLimit = instanceMediaAttachmentsVideoMatrixLimit
+
+ // NOTE: we use the local max sizes here
+ // as it hints to apps like Tusky for image
+ // compression of locally uploaded media.
+ //
+ // TODO: return local / remote depending
+ // on authorized endpoint user (if any)?
+ localMax := config.GetMediaLocalMaxSize()
+ imageSz := cmp.Or(config.GetMediaImageSizeHint(), localMax)
+ videoSz := cmp.Or(config.GetMediaVideoSizeHint(), localMax)
+ instance.Configuration.MediaAttachments.ImageSizeLimit = int(imageSz) // #nosec G115 -- Already validated.
+ instance.Configuration.MediaAttachments.VideoSizeLimit = int(videoSz) // #nosec G115 -- Already validated.
+
+ // we don't actually set any limits on these. set to max possible.
+ instance.Configuration.MediaAttachments.ImageMatrixLimit = math.MaxInt
+ instance.Configuration.MediaAttachments.VideoFrameRateLimit = math.MaxInt
+ instance.Configuration.MediaAttachments.VideoMatrixLimit = math.MaxInt
+
instance.Configuration.Polls.MaxOptions = config.GetStatusesPollMaxOptions()
instance.Configuration.Polls.MaxCharactersPerOption = config.GetStatusesPollOptionMaxChars()
instance.Configuration.Polls.MinExpiration = instancePollsMinExpiration
@@ -1713,11 +1725,24 @@ func (c *Converter) InstanceToAPIV2Instance(ctx context.Context, i *gtsmodel.Ins
instance.Configuration.Statuses.CharactersReservedPerURL = instanceStatusesCharactersReservedPerURL
instance.Configuration.Statuses.SupportedMimeTypes = instanceStatusesSupportedMimeTypes
instance.Configuration.MediaAttachments.SupportedMimeTypes = media.SupportedMIMETypes
- instance.Configuration.MediaAttachments.ImageSizeLimit = int(config.GetMediaRemoteMaxSize()) // #nosec G115 -- Already validated.
- instance.Configuration.MediaAttachments.ImageMatrixLimit = instanceMediaAttachmentsImageMatrixLimit
- instance.Configuration.MediaAttachments.VideoSizeLimit = int(config.GetMediaRemoteMaxSize()) // #nosec G115 -- Already validated.
- instance.Configuration.MediaAttachments.VideoFrameRateLimit = instanceMediaAttachmentsVideoFrameRateLimit
- instance.Configuration.MediaAttachments.VideoMatrixLimit = instanceMediaAttachmentsVideoMatrixLimit
+
+ // NOTE: we use the local max sizes here
+ // as it hints to apps like Tusky for image
+ // compression of locally uploaded media.
+ //
+ // TODO: return local / remote depending
+ // on authorized endpoint user (if any)?
+ localMax := config.GetMediaLocalMaxSize()
+ imageSz := cmp.Or(config.GetMediaImageSizeHint(), localMax)
+ videoSz := cmp.Or(config.GetMediaVideoSizeHint(), localMax)
+ instance.Configuration.MediaAttachments.ImageSizeLimit = int(imageSz) // #nosec G115 -- Already validated.
+ instance.Configuration.MediaAttachments.VideoSizeLimit = int(videoSz) // #nosec G115 -- Already validated.
+
+ // we don't actually set any limits on these. set to max possible.
+ instance.Configuration.MediaAttachments.ImageMatrixLimit = math.MaxInt
+ instance.Configuration.MediaAttachments.VideoFrameRateLimit = math.MaxInt
+ instance.Configuration.MediaAttachments.VideoMatrixLimit = math.MaxInt
+
instance.Configuration.Polls.MaxOptions = config.GetStatusesPollMaxOptions()
instance.Configuration.Polls.MaxCharactersPerOption = config.GetStatusesPollOptionMaxChars()
instance.Configuration.Polls.MinExpiration = instancePollsMinExpiration
diff --git a/internal/typeutils/internaltofrontend_test.go b/internal/typeutils/internaltofrontend_test.go
index cf11655ca..6c318e851 100644
--- a/internal/typeutils/internaltofrontend_test.go
+++ b/internal/typeutils/internaltofrontend_test.go
@@ -1968,10 +1968,10 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV1ToFrontend() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
@@ -2113,10 +2113,10 @@ func (suite *InternalToFrontendTestSuite) TestInstanceV2ToFrontend() {
"video/x-matroska"
],
"image_size_limit": 41943040,
- "image_matrix_limit": 16777216,
+ "image_matrix_limit": 9223372036854775807,
"video_size_limit": 41943040,
- "video_frame_rate_limit": 60,
- "video_matrix_limit": 16777216
+ "video_frame_rate_limit": 9223372036854775807,
+ "video_matrix_limit": 9223372036854775807
},
"polls": {
"max_options": 6,
diff --git a/test/envparsing.sh b/test/envparsing.sh
index ac6c2edc0..503bdd817 100755
--- a/test/envparsing.sh
+++ b/test/envparsing.sh
@@ -129,9 +129,11 @@ EXPECT=$(cat << "EOF"
"media-emoji-local-max-size": 420,
"media-emoji-remote-max-size": 420,
"media-ffmpeg-pool-size": 8,
+ "media-image-size-hint": 5242880,
"media-local-max-size": 420,
"media-remote-cache-days": 30,
"media-remote-max-size": 420,
+ "media-video-size-hint": 41943040,
"metrics-auth-enabled": false,
"metrics-auth-password": "",
"metrics-auth-username": "",
@@ -244,12 +246,14 @@ GTS_ACCOUNTS_REGISTRATION_OPEN=true \
GTS_ACCOUNTS_REASON_REQUIRED=false \
GTS_MEDIA_DESCRIPTION_MIN_CHARS=69 \
GTS_MEDIA_DESCRIPTION_MAX_CHARS=5000 \
+GTS_MEDIA_IMAGE_SIZE_HINT='5MiB' \
GTS_MEDIA_LOCAL_MAX_SIZE=420 \
GTS_MEDIA_REMOTE_MAX_SIZE=420 \
GTS_MEDIA_REMOTE_CACHE_DAYS=30 \
GTS_MEDIA_EMOJI_LOCAL_MAX_SIZE=420 \
GTS_MEDIA_EMOJI_REMOTE_MAX_SIZE=420 \
GTS_MEDIA_FFMPEG_POOL_SIZE=8 \
+GTS_MEDIA_VIDEO_SIZE_HINT='40MiB' \
GTS_METRICS_AUTH_ENABLED=false \
GTS_METRICS_ENABLED=false \
GTS_STORAGE_BACKEND='local' \