| 
									
										
										
										
											2023-03-12 16:00:57 +01:00
										 |  |  | // 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/>. | 
					
						
							| 
									
										
										
										
											2021-02-28 15:17:18 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-09 17:03:40 +01:00
										 |  |  | package media | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | import ( | 
					
						
							| 
									
										
										
										
											2021-05-17 19:06:58 +02:00
										 |  |  | 	"context" | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 	"io" | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 	"codeberg.org/gruf/go-iotools" | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtserror" | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/gtsmodel" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/id" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/log" | 
					
						
							|  |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/state" | 
					
						
							| 
									
										
										
										
											2024-05-22 09:46:24 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/storage" | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/uris" | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	"github.com/superseriousbusiness/gotosocial/internal/util" | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-11 12:48:38 +01:00
										 |  |  | var SupportedMIMETypes = []string{ | 
					
						
							| 
									
										
										
										
											2024-07-15 14:24:53 +00:00
										 |  |  | 	"image/jpeg", // .jpeg | 
					
						
							|  |  |  | 	"image/gif",  // .gif | 
					
						
							|  |  |  | 	"image/webp", // .webp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"audio/mp2", // .mp2 | 
					
						
							|  |  |  | 	"audio/mp3", // .mp3 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"video/x-msvideo", // .avi | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// png types | 
					
						
							|  |  |  | 	"image/png",  // .png | 
					
						
							|  |  |  | 	"image/apng", // .apng | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// ogg types | 
					
						
							|  |  |  | 	"audio/ogg", // .ogg | 
					
						
							|  |  |  | 	"video/ogg", // .ogv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// mpeg4 types | 
					
						
							|  |  |  | 	"audio/x-m4a",     // .m4a | 
					
						
							|  |  |  | 	"video/mp4",       // .mp4 | 
					
						
							|  |  |  | 	"video/quicktime", // .mov | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// asf types | 
					
						
							|  |  |  | 	"audio/x-ms-wma", // .wma | 
					
						
							|  |  |  | 	"video/x-ms-wmv", // .wmv | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// matroska types | 
					
						
							|  |  |  | 	"video/webm",       // .webm | 
					
						
							|  |  |  | 	"audio/x-matroska", // .mka | 
					
						
							|  |  |  | 	"video/x-matroska", // .mkv | 
					
						
							| 
									
										
										
										
											2023-02-11 12:48:38 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-05-15 16:45:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-11 12:48:38 +01:00
										 |  |  | var SupportedEmojiMIMETypes = []string{ | 
					
						
							| 
									
										
										
										
											2024-07-15 14:24:53 +00:00
										 |  |  | 	"image/jpeg", // .jpeg | 
					
						
							|  |  |  | 	"image/gif",  // .gif | 
					
						
							|  |  |  | 	"image/webp", // .webp | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// png types | 
					
						
							|  |  |  | 	"image/png",  // .png | 
					
						
							|  |  |  | 	"image/apng", // .apng | 
					
						
							| 
									
										
										
										
											2023-02-11 12:48:38 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2022-06-30 12:22:10 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | type Manager struct { | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	state *state.State | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | // NewManager returns a media manager with given state. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | func NewManager(state *state.State) *Manager { | 
					
						
							| 
									
										
										
										
											2023-11-30 10:50:28 +01:00
										 |  |  | 	return &Manager{state: state} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | // CreateMedia creates a new media attachment entry | 
					
						
							|  |  |  | // in the database for given owning account ID and | 
					
						
							|  |  |  | // extra information, and prepares a new processing | 
					
						
							|  |  |  | // media entry to dereference it using the given | 
					
						
							|  |  |  | // data function, decode the media and finish filling | 
					
						
							|  |  |  | // out remaining media fields (e.g. type, path, etc). | 
					
						
							|  |  |  | func (m *Manager) CreateMedia( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	accountID string, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	data DataFunc, | 
					
						
							|  |  |  | 	info AdditionalMediaInfo, | 
					
						
							|  |  |  | ) ( | 
					
						
							|  |  |  | 	*ProcessingMedia, | 
					
						
							|  |  |  | 	error, | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Populate initial fields on the new media, | 
					
						
							|  |  |  | 	// leaving out fields with values we don't know | 
					
						
							|  |  |  | 	// yet. These will be overwritten as we go. | 
					
						
							|  |  |  | 	attachment := >smodel.MediaAttachment{ | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 		ID:         id.NewULID(), | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 		AccountID:  accountID, | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 		Type:       gtsmodel.FileTypeUnknown, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 		Processing: gtsmodel.ProcessingStatusReceived, | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 		Avatar:     util.Ptr(false), | 
					
						
							|  |  |  | 		Header:     util.Ptr(false), | 
					
						
							|  |  |  | 		Cached:     util.Ptr(false), | 
					
						
							|  |  |  | 		CreatedAt:  now, | 
					
						
							|  |  |  | 		UpdatedAt:  now, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Check if we were provided additional info | 
					
						
							|  |  |  | 	// to add to the attachment, and overwrite | 
					
						
							|  |  |  | 	// some of the attachment fields if so. | 
					
						
							|  |  |  | 	if info.CreatedAt != nil { | 
					
						
							|  |  |  | 		attachment.CreatedAt = *info.CreatedAt | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.StatusID != nil { | 
					
						
							|  |  |  | 		attachment.StatusID = *info.StatusID | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.RemoteURL != nil { | 
					
						
							|  |  |  | 		attachment.RemoteURL = *info.RemoteURL | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.Description != nil { | 
					
						
							|  |  |  | 		attachment.Description = *info.Description | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.ScheduledStatusID != nil { | 
					
						
							|  |  |  | 		attachment.ScheduledStatusID = *info.ScheduledStatusID | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.Blurhash != nil { | 
					
						
							|  |  |  | 		attachment.Blurhash = *info.Blurhash | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.Avatar != nil { | 
					
						
							|  |  |  | 		attachment.Avatar = info.Avatar | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.Header != nil { | 
					
						
							|  |  |  | 		attachment.Header = info.Header | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.FocusX != nil { | 
					
						
							|  |  |  | 		attachment.FileMeta.Focus.X = *info.FocusX | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.FocusY != nil { | 
					
						
							|  |  |  | 		attachment.FileMeta.Focus.Y = *info.FocusY | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Store attachment in database in initial form. | 
					
						
							|  |  |  | 	err := m.state.DB.PutAttachment(ctx, attachment) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2022-05-07 16:36:01 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Pass prepared media as ready to be cached. | 
					
						
							|  |  |  | 	return m.RecacheMedia(attachment, data), nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // RecacheMedia wraps a media model (assumed already | 
					
						
							|  |  |  | // inserted in the database!) with given data function | 
					
						
							|  |  |  | // to perform a blocking dereference / decode operation | 
					
						
							|  |  |  | // from the data stream returned. | 
					
						
							|  |  |  | func (m *Manager) RecacheMedia( | 
					
						
							|  |  |  | 	media *gtsmodel.MediaAttachment, | 
					
						
							|  |  |  | 	data DataFunc, | 
					
						
							|  |  |  | ) *ProcessingMedia { | 
					
						
							|  |  |  | 	return &ProcessingMedia{ | 
					
						
							|  |  |  | 		media:  media, | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		dataFn: data, | 
					
						
							|  |  |  | 		mgr:    m, | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | // CreateEmoji creates a new emoji entry in the | 
					
						
							|  |  |  | // database for given shortcode, domain and extra | 
					
						
							|  |  |  | // information, and prepares a new processing emoji | 
					
						
							|  |  |  | // entry to dereference it using the given data | 
					
						
							|  |  |  | // function, decode the media and finish filling | 
					
						
							|  |  |  | // out remaining fields (e.g. type, path, etc). | 
					
						
							|  |  |  | func (m *Manager) CreateEmoji( | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	ctx context.Context, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	shortcode string, | 
					
						
							|  |  |  | 	domain string, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	data DataFunc, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	info AdditionalEmojiInfo, | 
					
						
							|  |  |  | ) ( | 
					
						
							|  |  |  | 	*ProcessingEmoji, | 
					
						
							|  |  |  | 	error, | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Generate new ID. | 
					
						
							|  |  |  | 	id := id.NewULID() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if domain == "" && info.URI == nil { | 
					
						
							|  |  |  | 		// Generate URI for local emoji. | 
					
						
							|  |  |  | 		uri := uris.URIForEmoji(id) | 
					
						
							|  |  |  | 		info.URI = &uri | 
					
						
							| 
									
										
										
										
											2022-03-07 11:08:26 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Populate initial fields on the new emoji, | 
					
						
							|  |  |  | 	// leaving out fields with values we don't know | 
					
						
							|  |  |  | 	// yet. These will be overwritten as we go. | 
					
						
							|  |  |  | 	emoji := >smodel.Emoji{ | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 		ID:              id, | 
					
						
							|  |  |  | 		Shortcode:       shortcode, | 
					
						
							|  |  |  | 		Domain:          domain, | 
					
						
							|  |  |  | 		Disabled:        util.Ptr(false), | 
					
						
							|  |  |  | 		VisibleInPicker: util.Ptr(true), | 
					
						
							|  |  |  | 		CreatedAt:       now, | 
					
						
							|  |  |  | 		UpdatedAt:       now, | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Finally, create new emoji. | 
					
						
							|  |  |  | 	return m.createEmoji(ctx, | 
					
						
							|  |  |  | 		m.state.DB.PutEmoji, | 
					
						
							|  |  |  | 		data, | 
					
						
							|  |  |  | 		emoji, | 
					
						
							|  |  |  | 		info, | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | // RefreshEmoji will prepare a recache operation | 
					
						
							|  |  |  | // for the given emoji, updating it with extra | 
					
						
							|  |  |  | // information, and in particular using new storage | 
					
						
							|  |  |  | // paths for the dereferenced media files to skirt | 
					
						
							|  |  |  | // around browser caching of the old files. | 
					
						
							|  |  |  | func (m *Manager) RefreshEmoji( | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	ctx context.Context, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	emoji *gtsmodel.Emoji, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	data DataFunc, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	info AdditionalEmojiInfo, | 
					
						
							|  |  |  | ) ( | 
					
						
							|  |  |  | 	*ProcessingEmoji, | 
					
						
							|  |  |  | 	error, | 
					
						
							|  |  |  | ) { | 
					
						
							|  |  |  | 	// Create references to old emoji image | 
					
						
							|  |  |  | 	// paths before they get updated with new | 
					
						
							|  |  |  | 	// path ID. These are required for later | 
					
						
							|  |  |  | 	// deleting the old image files on refresh. | 
					
						
							| 
									
										
										
										
											2024-07-03 15:53:54 -07:00
										 |  |  | 	shortcodeDomain := emoji.ShortcodeDomain() | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	oldStaticPath := emoji.ImageStaticPath | 
					
						
							|  |  |  | 	oldPath := emoji.ImagePath | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Since this is a refresh we will end up storing new images at new | 
					
						
							|  |  |  | 	// paths, so we should wrap closer to delete old paths at completion. | 
					
						
							| 
									
										
										
										
											2024-07-12 09:39:47 +00:00
										 |  |  | 	wrapped := func(ctx context.Context) (io.ReadCloser, error) { | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 09:39:47 +00:00
										 |  |  | 		// Call original func. | 
					
						
							|  |  |  | 		rc, err := data(ctx) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2024-07-12 09:39:47 +00:00
										 |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 09:39:47 +00:00
										 |  |  | 		// Cast as separated reader / closer types. | 
					
						
							|  |  |  | 		rct, ok := rc.(*iotools.ReadCloserType) | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 09:39:47 +00:00
										 |  |  | 		if !ok { | 
					
						
							|  |  |  | 			// Allocate new read closer type. | 
					
						
							|  |  |  | 			rct = new(iotools.ReadCloserType) | 
					
						
							|  |  |  | 			rct.Reader = rc | 
					
						
							|  |  |  | 			rct.Closer = rc | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Wrap underlying io.Closer type to cleanup old data. | 
					
						
							|  |  |  | 		rct.Closer = iotools.CloserCallback(rct.Closer, func() { | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 			// Remove any *old* emoji image file path now stream is closed. | 
					
						
							|  |  |  | 			if err := m.state.Storage.Delete(ctx, oldPath); err != nil && | 
					
						
							|  |  |  | 				!storage.IsNotFound(err) { | 
					
						
							|  |  |  | 				log.Errorf(ctx, "error deleting old emoji %s from storage: %v", shortcodeDomain, err) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 			// Remove any *old* emoji static image file path now stream is closed. | 
					
						
							|  |  |  | 			if err := m.state.Storage.Delete(ctx, oldStaticPath); err != nil && | 
					
						
							|  |  |  | 				!storage.IsNotFound(err) { | 
					
						
							|  |  |  | 				log.Errorf(ctx, "error deleting old static emoji %s from storage: %v", shortcodeDomain, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-12 09:39:47 +00:00
										 |  |  | 		return rct, nil | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Finally, create new emoji in database. | 
					
						
							|  |  |  | 	processingEmoji, err := m.createEmoji(ctx, | 
					
						
							|  |  |  | 		func(ctx context.Context, emoji *gtsmodel.Emoji) error { | 
					
						
							|  |  |  | 			return m.state.DB.UpdateEmoji(ctx, emoji) | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		wrapped, | 
					
						
							|  |  |  | 		emoji, | 
					
						
							|  |  |  | 		info, | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2021-05-21 15:48:26 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 	// Generate a new path ID to use instead. | 
					
						
							|  |  |  | 	processingEmoji.newPathID = id.NewULID() | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-11 17:49:14 +01:00
										 |  |  | 	return processingEmoji, nil | 
					
						
							| 
									
										
										
										
											2022-01-08 17:17:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | func (m *Manager) createEmoji( | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	ctx context.Context, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	putDB func(context.Context, *gtsmodel.Emoji) error, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	data DataFunc, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	emoji *gtsmodel.Emoji, | 
					
						
							|  |  |  | 	info AdditionalEmojiInfo, | 
					
						
							|  |  |  | ) ( | 
					
						
							|  |  |  | 	*ProcessingEmoji, | 
					
						
							|  |  |  | 	error, | 
					
						
							|  |  |  | ) { | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 	// Fetch the local instance account for emoji path generation. | 
					
						
							|  |  |  | 	instanceAcc, err := m.state.DB.GetInstanceAccount(ctx, "") | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, gtserror.Newf("error fetching instance account: %w", err) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Check if we have additional info to add to the emoji, | 
					
						
							|  |  |  | 	// and overwrite some of the emoji fields if so. | 
					
						
							|  |  |  | 	if info.URI != nil { | 
					
						
							|  |  |  | 		emoji.URI = *info.URI | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.CreatedAt != nil { | 
					
						
							|  |  |  | 		emoji.CreatedAt = *info.CreatedAt | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.Domain != nil { | 
					
						
							|  |  |  | 		emoji.Domain = *info.Domain | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.ImageRemoteURL != nil { | 
					
						
							|  |  |  | 		emoji.ImageRemoteURL = *info.ImageRemoteURL | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.ImageStaticRemoteURL != nil { | 
					
						
							|  |  |  | 		emoji.ImageStaticRemoteURL = *info.ImageStaticRemoteURL | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.Disabled != nil { | 
					
						
							|  |  |  | 		emoji.Disabled = info.Disabled | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.VisibleInPicker != nil { | 
					
						
							|  |  |  | 		emoji.VisibleInPicker = info.VisibleInPicker | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if info.CategoryID != nil { | 
					
						
							|  |  |  | 		emoji.CategoryID = *info.CategoryID | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Store emoji in database in initial form. | 
					
						
							|  |  |  | 	if err := putDB(ctx, emoji); err != nil { | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | 	// Return wrapped emoji for later processing. | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 	processingEmoji := &ProcessingEmoji{ | 
					
						
							| 
									
										
										
										
											2024-07-17 15:26:33 +00:00
										 |  |  | 		instAccID: instanceAcc.ID, | 
					
						
							|  |  |  | 		emoji:     emoji, | 
					
						
							|  |  |  | 		dataFn:    data, | 
					
						
							|  |  |  | 		mgr:       m, | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return processingEmoji, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | // RecacheEmoji wraps an emoji model (assumed already | 
					
						
							|  |  |  | // inserted in the database!) with given data function | 
					
						
							|  |  |  | // to perform a blocking dereference / decode operation | 
					
						
							|  |  |  | // from the data stream returned. | 
					
						
							|  |  |  | func (m *Manager) RecacheEmoji( | 
					
						
							|  |  |  | 	emoji *gtsmodel.Emoji, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	data DataFunc, | 
					
						
							| 
									
										
										
										
											2024-06-26 15:01:16 +00:00
										 |  |  | ) *ProcessingEmoji { | 
					
						
							|  |  |  | 	return &ProcessingEmoji{ | 
					
						
							|  |  |  | 		emoji:  emoji, | 
					
						
							|  |  |  | 		dataFn: data, | 
					
						
							|  |  |  | 		mgr:    m, | 
					
						
							| 
									
										
										
										
											2022-03-07 11:08:26 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } |