mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-15 00:27:29 -06:00
[chore] media and emoji refactoring (#3000)
* start updating media manager interface ready for storing attachments / emoji right away
* store emoji and media as uncached immediately, then (re-)cache on Processing{}.Load()
* remove now unused media workers
* fix tests and issues
* fix another test!
* fix emoji activitypub uri setting behaviour, fix remainder of test compilation issues
* fix more tests
* fix (most of) remaining tests, add debouncing to repeatedly failing media / emojis
* whoops, rebase issue
* remove kim's whacky experiments
* do some reshuffling, ensure emoji uri gets set
* ensure marked as not cached on cleanup
* tweaks to media / emoji processing to handle context canceled better
* ensure newly fetched emojis actually get set in returned slice
* use different varnames to be a bit more obvious
* move emoji refresh rate limiting to dereferencer
* add exported dereferencer functions for remote media, use these for recaching in processor
* add check for nil attachment in updateAttachment()
* remove unused emoji and media fields + columns
* see previous commit
* fix old migrations expecting image_updated_at to exists (from copies of old models)
* remove freshness checking code (seems to be broken...)
* fix error arg causing nil ptr exception
* finish documentating functions with comments, slight tweaks to media / emoji deref error logic
* remove some extra unneeded boolean checking
* finish writing documentation (code comments) for exported media manager methods
* undo changes to migration snapshot gtsmodels, updated failing migration to have its own snapshot
* move doesColumnExist() to util.go in migrations package
This commit is contained in:
parent
fa710057c8
commit
21bb324156
48 changed files with 2578 additions and 1926 deletions
|
|
@ -33,7 +33,6 @@ import (
|
|||
"github.com/superseriousbusiness/gotosocial/internal/id"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/log"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/media"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/transport"
|
||||
"github.com/superseriousbusiness/gotosocial/internal/util"
|
||||
)
|
||||
|
||||
|
|
@ -730,18 +729,18 @@ func (d *Dereferencer) enrichAccount(
|
|||
latestAcc.ID = account.ID
|
||||
latestAcc.FetchedAt = time.Now()
|
||||
|
||||
// Ensure the account's avatar media is populated, passing in existing to check for changes.
|
||||
if err := d.fetchRemoteAccountAvatar(ctx, tsport, account, latestAcc); err != nil {
|
||||
// Ensure the account's avatar media is populated, passing in existing to check for chages.
|
||||
if err := d.fetchAccountAvatar(ctx, requestUser, account, latestAcc); err != nil {
|
||||
log.Errorf(ctx, "error fetching remote avatar for account %s: %v", uri, err)
|
||||
}
|
||||
|
||||
// Ensure the account's avatar media is populated, passing in existing to check for changes.
|
||||
if err := d.fetchRemoteAccountHeader(ctx, tsport, account, latestAcc); err != nil {
|
||||
// Ensure the account's avatar media is populated, passing in existing to check for chages.
|
||||
if err := d.fetchAccountHeader(ctx, requestUser, account, latestAcc); err != nil {
|
||||
log.Errorf(ctx, "error fetching remote header for account %s: %v", uri, err)
|
||||
}
|
||||
|
||||
// Fetch the latest remote account emoji IDs used in account display name/bio.
|
||||
if _, err = d.fetchRemoteAccountEmojis(ctx, latestAcc, requestUser); err != nil {
|
||||
if err = d.fetchAccountEmojis(ctx, account, latestAcc); err != nil {
|
||||
log.Errorf(ctx, "error fetching remote emojis for account %s: %v", uri, err)
|
||||
}
|
||||
|
||||
|
|
@ -779,9 +778,9 @@ func (d *Dereferencer) enrichAccount(
|
|||
return latestAcc, apubAcc, nil
|
||||
}
|
||||
|
||||
func (d *Dereferencer) fetchRemoteAccountAvatar(
|
||||
func (d *Dereferencer) fetchAccountAvatar(
|
||||
ctx context.Context,
|
||||
tsport transport.Transport,
|
||||
requestUser string,
|
||||
existingAcc *gtsmodel.Account,
|
||||
latestAcc *gtsmodel.Account,
|
||||
) error {
|
||||
|
|
@ -808,7 +807,7 @@ func (d *Dereferencer) fetchRemoteAccountAvatar(
|
|||
// Ensuring existing attachment is up-to-date
|
||||
// and any recaching is performed if required.
|
||||
existing, err := d.updateAttachment(ctx,
|
||||
tsport,
|
||||
requestUser,
|
||||
existing,
|
||||
nil,
|
||||
)
|
||||
|
|
@ -830,18 +829,23 @@ func (d *Dereferencer) fetchRemoteAccountAvatar(
|
|||
}
|
||||
}
|
||||
|
||||
// Fetch newly changed avatar from remote.
|
||||
attachment, err := d.loadAttachment(ctx,
|
||||
tsport,
|
||||
// Fetch newly changed avatar.
|
||||
attachment, err := d.GetMedia(ctx,
|
||||
requestUser,
|
||||
latestAcc.ID,
|
||||
latestAcc.AvatarRemoteURL,
|
||||
&media.AdditionalMediaInfo{
|
||||
media.AdditionalMediaInfo{
|
||||
Avatar: util.Ptr(true),
|
||||
RemoteURL: &latestAcc.AvatarRemoteURL,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error loading attachment %s: %w", latestAcc.AvatarRemoteURL, err)
|
||||
if attachment == nil {
|
||||
return gtserror.Newf("error loading attachment %s: %w", latestAcc.AvatarRemoteURL, err)
|
||||
}
|
||||
|
||||
// non-fatal error occurred during loading, still use it.
|
||||
log.Warnf(ctx, "partially loaded attachment: %v", err)
|
||||
}
|
||||
|
||||
// Set the avatar attachment on account model.
|
||||
|
|
@ -851,9 +855,9 @@ func (d *Dereferencer) fetchRemoteAccountAvatar(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *Dereferencer) fetchRemoteAccountHeader(
|
||||
func (d *Dereferencer) fetchAccountHeader(
|
||||
ctx context.Context,
|
||||
tsport transport.Transport,
|
||||
requestUser string,
|
||||
existingAcc *gtsmodel.Account,
|
||||
latestAcc *gtsmodel.Account,
|
||||
) error {
|
||||
|
|
@ -880,7 +884,7 @@ func (d *Dereferencer) fetchRemoteAccountHeader(
|
|||
// Ensuring existing attachment is up-to-date
|
||||
// and any recaching is performed if required.
|
||||
existing, err := d.updateAttachment(ctx,
|
||||
tsport,
|
||||
requestUser,
|
||||
existing,
|
||||
nil,
|
||||
)
|
||||
|
|
@ -902,18 +906,23 @@ func (d *Dereferencer) fetchRemoteAccountHeader(
|
|||
}
|
||||
}
|
||||
|
||||
// Fetch newly changed header from remote.
|
||||
attachment, err := d.loadAttachment(ctx,
|
||||
tsport,
|
||||
// Fetch newly changed header.
|
||||
attachment, err := d.GetMedia(ctx,
|
||||
requestUser,
|
||||
latestAcc.ID,
|
||||
latestAcc.HeaderRemoteURL,
|
||||
&media.AdditionalMediaInfo{
|
||||
media.AdditionalMediaInfo{
|
||||
Header: util.Ptr(true),
|
||||
RemoteURL: &latestAcc.HeaderRemoteURL,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
return gtserror.Newf("error loading attachment %s: %w", latestAcc.HeaderRemoteURL, err)
|
||||
if attachment == nil {
|
||||
return gtserror.Newf("error loading attachment %s: %w", latestAcc.HeaderRemoteURL, err)
|
||||
}
|
||||
|
||||
// non-fatal error occurred during loading, still use it.
|
||||
log.Warnf(ctx, "partially loaded attachment: %v", err)
|
||||
}
|
||||
|
||||
// Set the header attachment on account model.
|
||||
|
|
@ -923,119 +932,44 @@ func (d *Dereferencer) fetchRemoteAccountHeader(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (d *Dereferencer) fetchRemoteAccountEmojis(ctx context.Context, targetAccount *gtsmodel.Account, requestingUsername string) (bool, error) {
|
||||
maybeEmojis := targetAccount.Emojis
|
||||
maybeEmojiIDs := targetAccount.EmojiIDs
|
||||
|
||||
// It's possible that the account had emoji IDs set on it, but not Emojis
|
||||
// themselves, depending on how it was fetched before being passed to us.
|
||||
//
|
||||
// If we only have IDs, fetch the emojis from the db. We know they're in
|
||||
// there or else they wouldn't have IDs.
|
||||
if len(maybeEmojiIDs) > len(maybeEmojis) {
|
||||
maybeEmojis = make([]*gtsmodel.Emoji, 0, len(maybeEmojiIDs))
|
||||
for _, emojiID := range maybeEmojiIDs {
|
||||
maybeEmoji, err := d.state.DB.GetEmojiByID(ctx, emojiID)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
maybeEmojis = append(maybeEmojis, maybeEmoji)
|
||||
}
|
||||
}
|
||||
|
||||
// For all the maybe emojis we have, we either fetch them from the database
|
||||
// (if we haven't already), or dereference them from the remote instance.
|
||||
gotEmojis, err := d.populateEmojis(ctx, maybeEmojis, requestingUsername)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// Extract the ID of each fetched or dereferenced emoji, so we can attach
|
||||
// this to the account if necessary.
|
||||
gotEmojiIDs := make([]string, 0, len(gotEmojis))
|
||||
for _, e := range gotEmojis {
|
||||
gotEmojiIDs = append(gotEmojiIDs, e.ID)
|
||||
}
|
||||
|
||||
var (
|
||||
changed = false // have the emojis for this account changed?
|
||||
maybeLen = len(maybeEmojis)
|
||||
gotLen = len(gotEmojis)
|
||||
func (d *Dereferencer) fetchAccountEmojis(
|
||||
ctx context.Context,
|
||||
existing *gtsmodel.Account,
|
||||
account *gtsmodel.Account,
|
||||
) error {
|
||||
// Fetch the updated emojis for our account.
|
||||
emojis, changed, err := d.fetchEmojis(ctx,
|
||||
existing.Emojis,
|
||||
account.Emojis,
|
||||
)
|
||||
|
||||
// if the length of everything is zero, this is simple:
|
||||
// nothing has changed and there's nothing to do
|
||||
if maybeLen == 0 && gotLen == 0 {
|
||||
return changed, nil
|
||||
if err != nil {
|
||||
return gtserror.Newf("error fetching emojis: %w", err)
|
||||
}
|
||||
|
||||
// if the *amount* of emojis on the account has changed, then the got emojis
|
||||
// are definitely different from the previous ones (if there were any) --
|
||||
// the account has either more or fewer emojis set on it now, so take the
|
||||
// discovered emojis as the new correct ones.
|
||||
if maybeLen != gotLen {
|
||||
changed = true
|
||||
targetAccount.Emojis = gotEmojis
|
||||
targetAccount.EmojiIDs = gotEmojiIDs
|
||||
return changed, nil
|
||||
if !changed {
|
||||
// Use existing account emoji objects.
|
||||
account.EmojiIDs = existing.EmojiIDs
|
||||
account.Emojis = existing.Emojis
|
||||
return nil
|
||||
}
|
||||
|
||||
// if the lengths are the same but not all of the slices are
|
||||
// zero, something *might* have changed, so we have to check
|
||||
// Set latest emojis.
|
||||
account.Emojis = emojis
|
||||
|
||||
// 1. did we have emojis before that we don't have now?
|
||||
for _, maybeEmoji := range maybeEmojis {
|
||||
var stillPresent bool
|
||||
|
||||
for _, gotEmoji := range gotEmojis {
|
||||
if maybeEmoji.URI == gotEmoji.URI {
|
||||
// the emoji we maybe had is still present now,
|
||||
// so we can stop checking gotEmojis
|
||||
stillPresent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !stillPresent {
|
||||
// at least one maybeEmoji is no longer present in
|
||||
// the got emojis, so we can stop checking now
|
||||
changed = true
|
||||
targetAccount.Emojis = gotEmojis
|
||||
targetAccount.EmojiIDs = gotEmojiIDs
|
||||
return changed, nil
|
||||
}
|
||||
// Iterate over and set changed emoji IDs.
|
||||
account.EmojiIDs = make([]string, len(emojis))
|
||||
for i, emoji := range emojis {
|
||||
account.EmojiIDs[i] = emoji.ID
|
||||
}
|
||||
|
||||
// 2. do we have emojis now that we didn't have before?
|
||||
for _, gotEmoji := range gotEmojis {
|
||||
var wasPresent bool
|
||||
|
||||
for _, maybeEmoji := range maybeEmojis {
|
||||
// check emoji IDs here as well, because unreferenced
|
||||
// maybe emojis we didn't already have would not have
|
||||
// had IDs set on them yet
|
||||
if gotEmoji.URI == maybeEmoji.URI && gotEmoji.ID == maybeEmoji.ID {
|
||||
// this got emoji was present already in the maybeEmoji,
|
||||
// so we can stop checking through maybeEmojis
|
||||
wasPresent = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !wasPresent {
|
||||
// at least one gotEmojis was not present in
|
||||
// the maybeEmojis, so we can stop checking now
|
||||
changed = true
|
||||
targetAccount.Emojis = gotEmojis
|
||||
targetAccount.EmojiIDs = gotEmojiIDs
|
||||
return changed, nil
|
||||
}
|
||||
}
|
||||
|
||||
return changed, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *Dereferencer) dereferenceAccountStats(ctx context.Context, requestUser string, account *gtsmodel.Account) error {
|
||||
func (d *Dereferencer) dereferenceAccountStats(
|
||||
ctx context.Context,
|
||||
requestUser string,
|
||||
account *gtsmodel.Account,
|
||||
) error {
|
||||
// Ensure we have a stats model for this account.
|
||||
if account.Stats == nil {
|
||||
if err := d.state.DB.PopulateAccountStats(ctx, account); err != nil {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue