diff options
Diffstat (limited to 'internal/db/bundb')
4 files changed, 319 insertions, 3 deletions
diff --git a/internal/db/bundb/migrations/20240318115336_account_settings.go b/internal/db/bundb/migrations/20240318115336_account_settings.go index 25c64e826..3bf58e21e 100644 --- a/internal/db/bundb/migrations/20240318115336_account_settings.go +++ b/internal/db/bundb/migrations/20240318115336_account_settings.go @@ -78,12 +78,12 @@ func init() { CreatedAt: account.CreatedAt, Reason: account.Reason, Privacy: newgtsmodel.Visibility(account.Privacy), - Sensitive: util.Ptr(util.PtrValueOr(account.Sensitive, false)), + Sensitive: util.Ptr(util.PtrOrValue(account.Sensitive, false)), Language: account.Language, StatusContentType: account.StatusContentType, CustomCSS: account.CustomCSS, - EnableRSS: util.Ptr(util.PtrValueOr(account.EnableRSS, false)), - HideCollections: util.Ptr(util.PtrValueOr(account.HideCollections, false)), + EnableRSS: util.Ptr(util.PtrOrValue(account.EnableRSS, false)), + HideCollections: util.Ptr(util.PtrOrValue(account.HideCollections, false)), } // Insert the settings model. diff --git a/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements.go b/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements.go new file mode 100644 index 000000000..5f01f53ef --- /dev/null +++ b/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements.go @@ -0,0 +1,124 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package migrations + +import ( + "context" + + old_gtsmodel "github.com/superseriousbusiness/gotosocial/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements" + new_gtsmodel "github.com/superseriousbusiness/gotosocial/internal/gtsmodel" + + "github.com/uptrace/bun" +) + +func init() { + up := func(ctx context.Context, db *bun.DB) error { + if err := db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + if _, err := tx.NewAddColumn(). + Table("media_attachments"). + ColumnExpr("? INTEGER NOT NULL DEFAULT ?", bun.Ident("type_new"), 0). + Exec(ctx); err != nil { + return err + } + + for old, new := range map[old_gtsmodel.FileType]new_gtsmodel.FileType{ + old_gtsmodel.FileTypeAudio: new_gtsmodel.FileTypeAudio, + old_gtsmodel.FileTypeImage: new_gtsmodel.FileTypeImage, + old_gtsmodel.FileTypeGifv: new_gtsmodel.FileTypeImage, + old_gtsmodel.FileTypeVideo: new_gtsmodel.FileTypeVideo, + old_gtsmodel.FileTypeUnknown: new_gtsmodel.FileTypeUnknown, + } { + if _, err := tx.NewUpdate(). + Table("media_attachments"). + Where("? = ?", bun.Ident("type"), old). + Set("? = ?", bun.Ident("type_new"), new). + Exec(ctx); err != nil { + return err + } + } + + if _, err := tx.NewDropColumn(). + Table("media_attachments"). + ColumnExpr("?", bun.Ident("type")). + Exec(ctx); err != nil { + return err + } + + if _, err := tx.NewRaw( + "ALTER TABLE ? RENAME COLUMN ? TO ?", + bun.Ident("media_attachments"), + bun.Ident("type_new"), + bun.Ident("type"), + ).Exec(ctx); err != nil { + return err + } + + return nil + }); err != nil { + return err + } + + // Zero-out attachment data + // for "unknown" non-locally + // stored media attachments. + if _, err := db.NewUpdate(). + Table("media_attachments"). + Where("? = ?", bun.Ident("type"), new_gtsmodel.FileTypeUnknown). + Set("? = ?", bun.Ident("url"), ""). + Set("? = ?", bun.Ident("file_path"), ""). + Set("? = ?", bun.Ident("file_content_type"), ""). + Set("? = ?", bun.Ident("file_file_size"), 0). + Set("? = ?", bun.Ident("thumbnail_path"), ""). + Set("? = ?", bun.Ident("thumbnail_content_type"), ""). + Set("? = ?", bun.Ident("thumbnail_file_size"), 0). + Set("? = ?", bun.Ident("thumbnail_url"), ""). + Exec(ctx); err != nil { + return err + } + + // Zero-out emoji data for + // non-locally stored emoji. + if _, err := db.NewUpdate(). + Table("emojis"). + WhereOr("? = ?", bun.Ident("image_url"), ""). + WhereOr("? = ?", bun.Ident("image_path"), ""). + Set("? = ?", bun.Ident("image_path"), ""). + Set("? = ?", bun.Ident("image_url"), ""). + Set("? = ?", bun.Ident("image_file_size"), 0). + Set("? = ?", bun.Ident("image_content_type"), ""). + Set("? = ?", bun.Ident("image_static_path"), ""). + Set("? = ?", bun.Ident("image_static_url"), ""). + Set("? = ?", bun.Ident("image_static_file_size"), 0). + Set("? = ?", bun.Ident("image_static_content_type"), ""). + Exec(ctx); err != nil { + return err + } + + return nil + } + + down := func(ctx context.Context, db *bun.DB) error { + return db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + return nil + }) + } + + if err := Migrations.Register(up, down); err != nil { + panic(err) + } +} diff --git a/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements/emoji.go b/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements/emoji.go new file mode 100644 index 000000000..f4567ab25 --- /dev/null +++ b/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements/emoji.go @@ -0,0 +1,65 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package gtsmodel + +import "time" + +// Emoji represents a custom emoji that's been uploaded through the admin UI or downloaded from a remote instance. +type Emoji struct { + ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated + Shortcode string `bun:",nullzero,notnull,unique:domainshortcode"` // String shortcode for this emoji -- the part that's between colons. This should be a-zA-Z_ eg., 'blob_hug' 'purple_heart' 'Gay_Otter' Must be unique with domain. + Domain string `bun:",nullzero,unique:domainshortcode"` // Origin domain of this emoji, eg 'example.org', 'queer.party'. empty string for local emojis. + ImageRemoteURL string `bun:",nullzero"` // Where can this emoji be retrieved remotely? Null for local emojis. + ImageStaticRemoteURL string `bun:",nullzero"` // Where can a static / non-animated version of this emoji be retrieved remotely? Null for local emojis. + ImageURL string `bun:",nullzero"` // Where can this emoji be retrieved from the local server? Null for remote emojis. + ImageStaticURL string `bun:",nullzero"` // Where can a static version of this emoji be retrieved from the local server? Null for remote emojis. + ImagePath string `bun:",notnull"` // Path of the emoji image in the server storage system. + ImageStaticPath string `bun:",notnull"` // Path of a static version of the emoji image in the server storage system + ImageContentType string `bun:",notnull"` // MIME content type of the emoji image + ImageStaticContentType string `bun:",notnull"` // MIME content type of the static version of the emoji image. + ImageFileSize int `bun:",notnull"` // Size of the emoji image file in bytes, for serving purposes. + ImageStaticFileSize int `bun:",notnull"` // Size of the static version of the emoji image file in bytes, for serving purposes. + Disabled *bool `bun:",nullzero,notnull,default:false"` // Has a moderation action disabled this emoji from being shown? + URI string `bun:",nullzero,notnull,unique"` // ActivityPub uri of this emoji. Something like 'https://example.org/emojis/1234' + VisibleInPicker *bool `bun:",nullzero,notnull,default:true"` // Is this emoji visible in the admin emoji picker? + Category *EmojiCategory `bun:"rel:belongs-to"` // In which emoji category is this emoji visible? + CategoryID string `bun:"type:CHAR(26),nullzero"` // ID of the category this emoji belongs to. + Cached *bool `bun:",nullzero,notnull,default:false"` // whether emoji is cached in locally in gotosocial storage. +} + +// IsLocal returns true if the emoji is +// local to this instance., ie., it did +// not originate from a remote instance. +func (e *Emoji) IsLocal() bool { + return e.Domain == "" +} + +// ShortcodeDomain returns the [shortcode]@[domain] for the given emoji. +func (e *Emoji) ShortcodeDomain() string { + return e.Shortcode + "@" + e.Domain +} + +// EmojiCategory represents a grouping of custom emojis. +type EmojiCategory struct { + ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated + Name string `bun:",nullzero,notnull,unique"` // name of this category +} diff --git a/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements/media.go b/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements/media.go new file mode 100644 index 000000000..471a5abd1 --- /dev/null +++ b/internal/db/bundb/migrations/20240715204203_media_pipeline_improvements/media.go @@ -0,0 +1,127 @@ +// GoToSocial +// Copyright (C) GoToSocial Authors admin@gotosocial.org +// SPDX-License-Identifier: AGPL-3.0-or-later +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. + +package gtsmodel + +import ( + "time" +) + +// MediaAttachment represents a user-uploaded media attachment: an image/video/audio/gif that is +// somewhere in storage and that can be retrieved and served by the router. +type MediaAttachment struct { + ID string `bun:"type:CHAR(26),pk,nullzero,notnull,unique"` // id of this item in the database + CreatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item created + UpdatedAt time.Time `bun:"type:timestamptz,nullzero,notnull,default:current_timestamp"` // when was item last updated + StatusID string `bun:"type:CHAR(26),nullzero"` // ID of the status to which this is attached + URL string `bun:",nullzero"` // Where can the attachment be retrieved on *this* server + RemoteURL string `bun:",nullzero"` // Where can the attachment be retrieved on a remote server (empty for local media) + Type FileType `bun:",notnull"` // Type of file (image/gifv/audio/video/unknown) + FileMeta FileMeta `bun:",embed:,notnull"` // Metadata about the file + AccountID string `bun:"type:CHAR(26),nullzero,notnull"` // To which account does this attachment belong + Description string `bun:""` // Description of the attachment (for screenreaders) + ScheduledStatusID string `bun:"type:CHAR(26),nullzero"` // To which scheduled status does this attachment belong + Blurhash string `bun:",nullzero"` // What is the generated blurhash of this attachment + Processing ProcessingStatus `bun:",notnull,default:2"` // What is the processing status of this attachment + File File `bun:",embed:file_,notnull,nullzero"` // metadata for the whole file + Thumbnail Thumbnail `bun:",embed:thumbnail_,notnull,nullzero"` // small image thumbnail derived from a larger image, video, or audio file. + Avatar *bool `bun:",nullzero,notnull,default:false"` // Is this attachment being used as an avatar? + Header *bool `bun:",nullzero,notnull,default:false"` // Is this attachment being used as a header? + Cached *bool `bun:",nullzero,notnull,default:false"` // Is this attachment currently cached by our instance? +} + +// IsLocal returns whether media attachment is local. +func (m *MediaAttachment) IsLocal() bool { + return m.RemoteURL == "" +} + +// IsRemote returns whether media attachment is remote. +func (m *MediaAttachment) IsRemote() bool { + return m.RemoteURL != "" +} + +// File refers to the metadata for the whole file +type File struct { + Path string `bun:",notnull"` // Path of the file in storage. + ContentType string `bun:",notnull"` // MIME content type of the file. + FileSize int `bun:",notnull"` // File size in bytes +} + +// Thumbnail refers to a small image thumbnail derived from a larger image, video, or audio file. +type Thumbnail struct { + Path string `bun:",notnull"` // Path of the file in storage. + ContentType string `bun:",notnull"` // MIME content type of the file. + FileSize int `bun:",notnull"` // File size in bytes + URL string `bun:",nullzero"` // What is the URL of the thumbnail on the local server + RemoteURL string `bun:",nullzero"` // What is the remote URL of the thumbnail (empty for local media) +} + +// ProcessingStatus refers to how far along in the processing stage the attachment is. +type ProcessingStatus int + +// MediaAttachment processing states. +const ( + ProcessingStatusReceived ProcessingStatus = 0 // ProcessingStatusReceived indicates the attachment has been received and is awaiting processing. No thumbnail available yet. + ProcessingStatusProcessing ProcessingStatus = 1 // ProcessingStatusProcessing indicates the attachment is currently being processed. Thumbnail is available but full media is not. + ProcessingStatusProcessed ProcessingStatus = 2 // ProcessingStatusProcessed indicates the attachment has been fully processed and is ready to be served. + ProcessingStatusError ProcessingStatus = 666 // ProcessingStatusError indicates something went wrong processing the attachment and it won't be tried again--these can be deleted. +) + +// FileType refers to the file type of the media attaachment. +type FileType string + +// MediaAttachment file types. +const ( + FileTypeImage FileType = "Image" // FileTypeImage is for jpegs, pngs, and standard gifs + FileTypeGifv FileType = "Gifv" // FileTypeGif is for soundless looping videos that behave like gifs + FileTypeAudio FileType = "Audio" // FileTypeAudio is for audio-only files (no video) + FileTypeVideo FileType = "Video" // FileTypeVideo is for files with audio + visual + FileTypeUnknown FileType = "Unknown" // FileTypeUnknown is for unknown file types (surprise surprise!) +) + +// FileMeta describes metadata about the actual contents of the file. +type FileMeta struct { + Original Original `bun:"embed:original_"` + Small Small `bun:"embed:small_"` + Focus Focus `bun:"embed:focus_"` +} + +// Small can be used for a thumbnail of any media type +type Small struct { + Width int // width in pixels + Height int // height in pixels + Size int // size in pixels (width * height) + Aspect float32 // aspect ratio (width / height) +} + +// Original can be used for original metadata for any media type +type Original struct { + Width int // width in pixels + Height int // height in pixels + Size int // size in pixels (width * height) + Aspect float32 // aspect ratio (width / height) + Duration *float32 // video-specific: duration of the video in seconds + Framerate *float32 // video-specific: fps + Bitrate *uint64 // video-specific: bitrate +} + +// Focus describes the 'center' of the image for display purposes. +// X and Y should each be between -1 and 1 +type Focus struct { + X float32 + Y float32 +} |