[bugfix] update media if more than just url changes (#2970)

* refactor status media handling into separate functions, handle case of changed metadata

* update fetchRemoteAccount{Avatar,Header} to use new refactored {load,update}Attachment() functions

* whoops, nearly marked avatars as headers :')

* reformatting to improve legibility
This commit is contained in:
kim
2024-06-06 14:35:50 +00:00
committed by GitHub
parent bcda048eab
commit b371c2db47
3 changed files with 241 additions and 114 deletions

View File

@@ -18,11 +18,122 @@
package dereferencing
import (
"context"
"io"
"net/url"
"slices"
"github.com/superseriousbusiness/gotosocial/internal/gtserror"
"github.com/superseriousbusiness/gotosocial/internal/gtsmodel"
"github.com/superseriousbusiness/gotosocial/internal/media"
"github.com/superseriousbusiness/gotosocial/internal/transport"
"github.com/superseriousbusiness/gotosocial/internal/util"
)
// loadAttachment handles the case of a new media attachment
// that requires loading. it stores and caches from given data.
func (d *Dereferencer) loadAttachment(
ctx context.Context,
tsport transport.Transport,
accountID string, // media account owner
remoteURL string,
info *media.AdditionalMediaInfo,
) (
*gtsmodel.MediaAttachment,
error,
) {
// Parse str as valid URL object.
url, err := url.Parse(remoteURL)
if err != nil {
return nil, gtserror.Newf("invalid remote media url %q: %v", remoteURL, err)
}
// Start pre-processing remote media at remote URL.
processing := d.mediaManager.PreProcessMedia(
func(ctx context.Context) (io.ReadCloser, int64, error) {
return tsport.DereferenceMedia(ctx, url)
},
accountID,
info,
)
// Force attachment loading *right now*.
return processing.LoadAttachment(ctx)
}
// updateAttachment handles the case of an existing media attachment
// that *may* have changes or need recaching. it checks for changed
// fields, updating in the database if so, and recaches uncached media.
func (d *Dereferencer) updateAttachment(
ctx context.Context,
tsport transport.Transport,
existing *gtsmodel.MediaAttachment, // existing attachment
media *gtsmodel.MediaAttachment, // (optional) changed media
) (
*gtsmodel.MediaAttachment, // always set
error,
) {
if media != nil {
// Possible changed media columns.
changed := make([]string, 0, 3)
// Check if attachment description has changed.
if existing.Description != media.Description {
changed = append(changed, "description")
existing.Description = media.Description
}
// Check if attachment blurhash has changed (i.e. content change).
if existing.Blurhash != media.Blurhash && media.Blurhash != "" {
changed = append(changed, "blurhash", "cached")
existing.Blurhash = media.Blurhash
existing.Cached = util.Ptr(false)
}
if len(changed) > 0 {
// Update the existing attachment model in the database.
err := d.state.DB.UpdateAttachment(ctx, existing, changed...)
if err != nil {
return media, gtserror.Newf("error updating media: %w", err)
}
}
}
// Check if cached.
if *existing.Cached {
return existing, nil
}
// Parse str as valid URL object.
url, err := url.Parse(existing.RemoteURL)
if err != nil {
return nil, gtserror.Newf("invalid remote media url %q: %v", media.RemoteURL, err)
}
// Start pre-processing remote media recaching from remote.
processing, err := d.mediaManager.PreProcessMediaRecache(
ctx,
func(ctx context.Context) (io.ReadCloser, int64, error) {
return tsport.DereferenceMedia(ctx, url)
},
existing.ID,
)
if err != nil {
return nil, gtserror.Newf("error processing recache: %w", err)
}
// Force load attachment recache *right now*.
recached, err := processing.LoadAttachment(ctx)
// Always return the error we
// receive, but ensure we return
// most up-to-date media file.
if recached != nil {
return recached, err
}
return existing, err
}
// pollChanged returns whether a poll has changed in way that
// indicates that this should be an entirely new poll. i.e. if
// the available options have changed, or the expiry has increased.