| 
									
										
										
										
											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-02-13 18:40:48 +00:00
										 |  |  | 	"errors" | 
					
						
							| 
									
										
										
										
											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-02-13 18:40:48 +00:00
										 |  |  | 	"codeberg.org/gruf/go-store/v2/storage" | 
					
						
							| 
									
										
										
										
											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" | 
					
						
							|  |  |  | 	"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{ | 
					
						
							|  |  |  | 	mimeImageJpeg, | 
					
						
							|  |  |  | 	mimeImageGif, | 
					
						
							|  |  |  | 	mimeImagePng, | 
					
						
							|  |  |  | 	mimeImageWebp, | 
					
						
							|  |  |  | 	mimeVideoMp4, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2022-05-15 16:45:04 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-11 12:48:38 +01:00
										 |  |  | var SupportedEmojiMIMETypes = []string{ | 
					
						
							|  |  |  | 	mimeImageGif, | 
					
						
							|  |  |  | 	mimeImagePng, | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											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
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // PreProcessMedia begins the process of decoding | 
					
						
							|  |  |  | // and storing the given data as an attachment. | 
					
						
							|  |  |  | // It will return a pointer to a ProcessingMedia | 
					
						
							|  |  |  | // struct upon which further actions can be performed, | 
					
						
							|  |  |  | // such as getting the finished media, thumbnail, | 
					
						
							|  |  |  | // attachment, etc. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | //   - data: a function that the media manager can call | 
					
						
							|  |  |  | //     to return a reader containing the media data. | 
					
						
							|  |  |  | //   - accountID: the account that the media belongs to. | 
					
						
							|  |  |  | //   - ai: optional and can be nil. Any additional information | 
					
						
							|  |  |  | //     about the attachment provided will be put in the database. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // Note: unlike ProcessMedia, this will NOT | 
					
						
							|  |  |  | // queue the media to be asynchronously processed. | 
					
						
							|  |  |  | func (m *Manager) PreProcessMedia( | 
					
						
							|  |  |  | 	data DataFunc, | 
					
						
							|  |  |  | 	accountID string, | 
					
						
							|  |  |  | 	ai *AdditionalMediaInfo, | 
					
						
							|  |  |  | ) *ProcessingMedia { | 
					
						
							|  |  |  | 	// Populate initial fields on the new media, | 
					
						
							|  |  |  | 	// leaving out fields with values we don't know | 
					
						
							|  |  |  | 	// yet. These will be overwritten as we go. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	now := time.Now() | 
					
						
							|  |  |  | 	attachment := >smodel.MediaAttachment{ | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		ID:         id.NewULID(), | 
					
						
							|  |  |  | 		CreatedAt:  now, | 
					
						
							|  |  |  | 		UpdatedAt:  now, | 
					
						
							|  |  |  | 		Type:       gtsmodel.FileTypeUnknown, | 
					
						
							|  |  |  | 		FileMeta:   gtsmodel.FileMeta{}, | 
					
						
							|  |  |  | 		AccountID:  accountID, | 
					
						
							|  |  |  | 		Processing: gtsmodel.ProcessingStatusReceived, | 
					
						
							|  |  |  | 		File: gtsmodel.File{ | 
					
						
							|  |  |  | 			UpdatedAt:   now, | 
					
						
							|  |  |  | 			ContentType: "application/octet-stream", | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		Thumbnail: gtsmodel.Thumbnail{UpdatedAt: now}, | 
					
						
							|  |  |  | 		Avatar:    util.Ptr(false), | 
					
						
							|  |  |  | 		Header:    util.Ptr(false), | 
					
						
							|  |  |  | 		Cached:    util.Ptr(false), | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	attachment.URL = uris.URIForAttachment( | 
					
						
							|  |  |  | 		accountID, | 
					
						
							|  |  |  | 		string(TypeAttachment), | 
					
						
							|  |  |  | 		string(SizeOriginal), | 
					
						
							|  |  |  | 		attachment.ID, | 
					
						
							|  |  |  | 		"unknown", | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	attachment.File.Path = uris.StoragePathForAttachment( | 
					
						
							|  |  |  | 		accountID, | 
					
						
							|  |  |  | 		string(TypeAttachment), | 
					
						
							|  |  |  | 		string(SizeOriginal), | 
					
						
							|  |  |  | 		attachment.ID, | 
					
						
							|  |  |  | 		"unknown", | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Check if we were provided additional info | 
					
						
							|  |  |  | 	// to add to the attachment, and overwrite | 
					
						
							|  |  |  | 	// some of the attachment fields if so. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	if ai != nil { | 
					
						
							|  |  |  | 		if ai.CreatedAt != nil { | 
					
						
							|  |  |  | 			attachment.CreatedAt = *ai.CreatedAt | 
					
						
							| 
									
										
										
										
											2022-05-07 16:36:01 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		if ai.StatusID != nil { | 
					
						
							|  |  |  | 			attachment.StatusID = *ai.StatusID | 
					
						
							| 
									
										
										
										
											2022-05-07 16:36:01 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		if ai.RemoteURL != nil { | 
					
						
							|  |  |  | 			attachment.RemoteURL = *ai.RemoteURL | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.Description != nil { | 
					
						
							|  |  |  | 			attachment.Description = *ai.Description | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.ScheduledStatusID != nil { | 
					
						
							|  |  |  | 			attachment.ScheduledStatusID = *ai.ScheduledStatusID | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.Blurhash != nil { | 
					
						
							|  |  |  | 			attachment.Blurhash = *ai.Blurhash | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.Avatar != nil { | 
					
						
							|  |  |  | 			attachment.Avatar = ai.Avatar | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.Header != nil { | 
					
						
							|  |  |  | 			attachment.Header = ai.Header | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.FocusX != nil { | 
					
						
							|  |  |  | 			attachment.FileMeta.Focus.X = *ai.FocusX | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.FocusY != nil { | 
					
						
							|  |  |  | 			attachment.FileMeta.Focus.Y = *ai.FocusY | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2022-05-07 16:36:01 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	processingMedia := &ProcessingMedia{ | 
					
						
							|  |  |  | 		media:  attachment, | 
					
						
							|  |  |  | 		dataFn: data, | 
					
						
							|  |  |  | 		mgr:    m, | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-03 17:37:38 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	return processingMedia | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // PreProcessMediaRecache refetches, reprocesses, | 
					
						
							|  |  |  | // and recaches an existing attachment that has | 
					
						
							|  |  |  | // been uncached via cleaner pruning. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // Note: unlike ProcessMedia, this will NOT queue | 
					
						
							|  |  |  | // the media to be asychronously processed. | 
					
						
							|  |  |  | func (m *Manager) PreProcessMediaRecache( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	data DataFunc, | 
					
						
							|  |  |  | 	attachmentID string, | 
					
						
							|  |  |  | ) (*ProcessingMedia, error) { | 
					
						
							|  |  |  | 	// Get the existing attachment from database. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	attachment, err := m.state.DB.GetAttachmentByID(ctx, attachmentID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2022-05-15 16:45:04 +02:00
										 |  |  | 		return nil, err | 
					
						
							| 
									
										
										
										
											2022-03-07 11:08:26 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	processingMedia := &ProcessingMedia{ | 
					
						
							|  |  |  | 		media:   attachment, | 
					
						
							|  |  |  | 		dataFn:  data, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		recache: true, // Indicate it's a recache. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		mgr:     m, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return processingMedia, nil | 
					
						
							| 
									
										
										
										
											2021-04-01 20:46:45 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // PreProcessEmoji begins the process of decoding and storing | 
					
						
							|  |  |  | // the given data as an emoji. It will return a pointer to a | 
					
						
							|  |  |  | // ProcessingEmoji struct upon which further actions can be | 
					
						
							|  |  |  | // performed, such as getting the finished media, thumbnail, | 
					
						
							|  |  |  | // attachment, etc. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | //   - data: function that the media manager can call | 
					
						
							|  |  |  | //     to return a reader containing the emoji data. | 
					
						
							|  |  |  | //   - shortcode: the emoji shortcode without the ':'s around it. | 
					
						
							|  |  |  | //   - emojiID: database ID that should be used to store the emoji. | 
					
						
							|  |  |  | //   - uri: ActivityPub URI/ID of the emoji. | 
					
						
							|  |  |  | //   - ai: optional and can be nil. Any additional information | 
					
						
							|  |  |  | //     about the emoji provided will be put in the database. | 
					
						
							|  |  |  | //   - refresh: refetch/refresh the emoji. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // Note: unlike ProcessEmoji, this will NOT queue | 
					
						
							|  |  |  | // the emoji to be asynchronously processed. | 
					
						
							|  |  |  | func (m *Manager) PreProcessEmoji( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	data DataFunc, | 
					
						
							|  |  |  | 	shortcode string, | 
					
						
							|  |  |  | 	emojiID string, | 
					
						
							|  |  |  | 	uri string, | 
					
						
							|  |  |  | 	ai *AdditionalEmojiInfo, | 
					
						
							|  |  |  | 	refresh bool, | 
					
						
							|  |  |  | ) (*ProcessingEmoji, error) { | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	var ( | 
					
						
							|  |  |  | 		newPathID string | 
					
						
							|  |  |  | 		emoji     *gtsmodel.Emoji | 
					
						
							|  |  |  | 		now       = time.Now() | 
					
						
							|  |  |  | 	) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01: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) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	if refresh { | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		// Existing emoji! | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		emoji, err = m.state.DB.GetEmojiByID(ctx, emojiID) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 			err = gtserror.Newf("error fetching emoji to refresh from the db: %w", err) | 
					
						
							|  |  |  | 			return nil, err | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		// Since this is a refresh, we will end up with | 
					
						
							|  |  |  | 		// new images stored for this emoji, so we should | 
					
						
							|  |  |  | 		// use an io.Closer callback to perform clean up | 
					
						
							|  |  |  | 		// of the original images from storage. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 		originalData := data | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		originalImagePath := emoji.ImagePath | 
					
						
							|  |  |  | 		originalImageStaticPath := emoji.ImageStaticPath | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 		data = func(ctx context.Context) (io.ReadCloser, int64, error) { | 
					
						
							|  |  |  | 			// Call original data func. | 
					
						
							|  |  |  | 			rc, sz, err := originalData(ctx) | 
					
						
							|  |  |  | 			if err != nil { | 
					
						
							|  |  |  | 				return nil, 0, err | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 			// Wrap closer to cleanup old data. | 
					
						
							|  |  |  | 			c := iotools.CloserCallback(rc, func() { | 
					
						
							|  |  |  | 				if err := m.state.Storage.Delete(ctx, originalImagePath); err != nil && !errors.Is(err, storage.ErrNotFound) { | 
					
						
							|  |  |  | 					log.Errorf(ctx, "error removing old emoji %s@%s from storage: %v", emoji.Shortcode, emoji.Domain, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if err := m.state.Storage.Delete(ctx, originalImageStaticPath); err != nil && !errors.Is(err, storage.ErrNotFound) { | 
					
						
							|  |  |  | 					log.Errorf(ctx, "error removing old static emoji %s@%s from storage: %v", emoji.Shortcode, emoji.Domain, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 			// Return newly wrapped readcloser and size. | 
					
						
							|  |  |  | 			return iotools.ReadCloser(rc, c), sz, nil | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		// Reuse existing shortcode and URI - | 
					
						
							|  |  |  | 		// these don't change when we refresh. | 
					
						
							|  |  |  | 		emoji.Shortcode = shortcode | 
					
						
							|  |  |  | 		emoji.URI = uri | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Use a new ID to create a new path | 
					
						
							|  |  |  | 		// for the new images, to get around | 
					
						
							|  |  |  | 		// needing to do cache invalidation. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		newPathID, err = id.NewRandomULID() | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2023-06-22 20:46:36 +01:00
										 |  |  | 			return nil, gtserror.Newf("error generating alternateID for emoji refresh: %s", err) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		emoji.ImageStaticURL = uris.URIForAttachment( | 
					
						
							|  |  |  | 			instanceAcc.ID, | 
					
						
							|  |  |  | 			string(TypeEmoji), | 
					
						
							|  |  |  | 			string(SizeStatic), | 
					
						
							|  |  |  | 			newPathID, | 
					
						
							|  |  |  | 			// All static emojis | 
					
						
							|  |  |  | 			// are encoded as png. | 
					
						
							|  |  |  | 			mimePng, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		emoji.ImageStaticPath = uris.StoragePathForAttachment( | 
					
						
							|  |  |  | 			instanceAcc.ID, | 
					
						
							|  |  |  | 			string(TypeEmoji), | 
					
						
							|  |  |  | 			string(SizeStatic), | 
					
						
							|  |  |  | 			newPathID, | 
					
						
							|  |  |  | 			// All static emojis | 
					
						
							|  |  |  | 			// are encoded as png. | 
					
						
							|  |  |  | 			mimePng, | 
					
						
							|  |  |  | 		) | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		// New emoji! | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		imageStaticURL := uris.URIForAttachment( | 
					
						
							|  |  |  | 			instanceAcc.ID, | 
					
						
							|  |  |  | 			string(TypeEmoji), | 
					
						
							|  |  |  | 			string(SizeStatic), | 
					
						
							|  |  |  | 			emojiID, | 
					
						
							|  |  |  | 			// All static emojis | 
					
						
							|  |  |  | 			// are encoded as png. | 
					
						
							|  |  |  | 			mimePng, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		imageStaticPath := uris.StoragePathForAttachment( | 
					
						
							|  |  |  | 			instanceAcc.ID, | 
					
						
							|  |  |  | 			string(TypeEmoji), | 
					
						
							|  |  |  | 			string(SizeStatic), | 
					
						
							|  |  |  | 			emojiID, | 
					
						
							|  |  |  | 			// All static emojis | 
					
						
							|  |  |  | 			// are encoded as png. | 
					
						
							|  |  |  | 			mimePng, | 
					
						
							|  |  |  | 		) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Populate initial fields on the new emoji, | 
					
						
							|  |  |  | 		// leaving out fields with values we don't know | 
					
						
							|  |  |  | 		// yet. These will be overwritten as we go. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		emoji = >smodel.Emoji{ | 
					
						
							|  |  |  | 			ID:                     emojiID, | 
					
						
							|  |  |  | 			CreatedAt:              now, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 			UpdatedAt:              now, | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 			Shortcode:              shortcode, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 			ImageStaticURL:         imageStaticURL, | 
					
						
							|  |  |  | 			ImageStaticPath:        imageStaticPath, | 
					
						
							|  |  |  | 			ImageStaticContentType: mimeImagePng, | 
					
						
							|  |  |  | 			ImageUpdatedAt:         now, | 
					
						
							|  |  |  | 			Disabled:               util.Ptr(false), | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 			URI:                    uri, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 			VisibleInPicker:        util.Ptr(true), | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 	// Check if we have additional info to add to the emoji, | 
					
						
							|  |  |  | 	// and overwrite some of the emoji fields if so. | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	if ai != nil { | 
					
						
							|  |  |  | 		if ai.CreatedAt != nil { | 
					
						
							|  |  |  | 			emoji.CreatedAt = *ai.CreatedAt | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.Domain != nil { | 
					
						
							|  |  |  | 			emoji.Domain = *ai.Domain | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.ImageRemoteURL != nil { | 
					
						
							|  |  |  | 			emoji.ImageRemoteURL = *ai.ImageRemoteURL | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.ImageStaticRemoteURL != nil { | 
					
						
							|  |  |  | 			emoji.ImageStaticRemoteURL = *ai.ImageStaticRemoteURL | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.Disabled != nil { | 
					
						
							|  |  |  | 			emoji.Disabled = ai.Disabled | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.VisibleInPicker != nil { | 
					
						
							|  |  |  | 			emoji.VisibleInPicker = ai.VisibleInPicker | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if ai.CategoryID != nil { | 
					
						
							|  |  |  | 			emoji.CategoryID = *ai.CategoryID | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-05-21 15:48:26 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	processingEmoji := &ProcessingEmoji{ | 
					
						
							|  |  |  | 		emoji:     emoji, | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 		existing:  refresh, | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 		newPathID: newPathID, | 
					
						
							|  |  |  | 		dataFn:    data, | 
					
						
							|  |  |  | 		mgr:       m, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-11 17:49:14 +01:00
										 |  |  | 	return processingEmoji, nil | 
					
						
							| 
									
										
										
										
											2022-01-08 17:17:01 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // PreProcessEmojiRecache refetches, reprocesses, and recaches | 
					
						
							|  |  |  | // an existing emoji that has been uncached via cleaner pruning. | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | // | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // Note: unlike ProcessEmoji, this will NOT queue the emoji to | 
					
						
							|  |  |  | // be asychronously processed. | 
					
						
							|  |  |  | func (m *Manager) PreProcessEmojiRecache( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	data DataFunc, | 
					
						
							|  |  |  | 	emojiID string, | 
					
						
							|  |  |  | ) (*ProcessingEmoji, error) { | 
					
						
							|  |  |  | 	// Get the existing emoji from the database. | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 	emoji, err := m.state.DB.GetEmojiByID(ctx, emojiID) | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	processingEmoji := &ProcessingEmoji{ | 
					
						
							|  |  |  | 		emoji:    emoji, | 
					
						
							|  |  |  | 		dataFn:   data, | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | 		existing: true, // Indicate recache. | 
					
						
							| 
									
										
										
										
											2023-07-24 13:14:13 +01:00
										 |  |  | 		mgr:      m, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return processingEmoji, nil | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 19:29:26 +01:00
										 |  |  | // ProcessEmoji will call PreProcessEmoji, followed | 
					
						
							|  |  |  | // by queuing the emoji in the emoji worker queue. | 
					
						
							|  |  |  | func (m *Manager) ProcessEmoji( | 
					
						
							|  |  |  | 	ctx context.Context, | 
					
						
							|  |  |  | 	data DataFunc, | 
					
						
							|  |  |  | 	shortcode string, | 
					
						
							|  |  |  | 	id string, | 
					
						
							|  |  |  | 	uri string, | 
					
						
							|  |  |  | 	ai *AdditionalEmojiInfo, | 
					
						
							|  |  |  | 	refresh bool, | 
					
						
							|  |  |  | ) (*ProcessingEmoji, error) { | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 	// Create a new processing emoji object for this emoji request. | 
					
						
							| 
									
										
										
										
											2023-05-28 13:08:35 +01:00
										 |  |  | 	emoji, err := m.PreProcessEmoji(ctx, data, shortcode, id, uri, ai, refresh) | 
					
						
							| 
									
										
										
										
											2022-03-07 11:08:26 +01:00
										 |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return nil, err | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-02-13 18:40:48 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Attempt to add this emoji processing item to the worker queue. | 
					
						
							|  |  |  | 	_ = m.state.Workers.Media.MustEnqueueCtx(ctx, emoji.Process) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return emoji, nil | 
					
						
							| 
									
										
										
										
											2022-03-07 11:08:26 +01:00
										 |  |  | } |