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 +}  | 
