[feature] Support incoming avatar/header descriptions (#4275)

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>

# Description

Follow-up to #4270

Closes https://codeberg.org/superseriousbusiness/gotosocial/issues/3450

## Checklist

- [x] I/we have read the [GoToSocial contribution guidelines](https://codeberg.org/superseriousbusiness/gotosocial/src/branch/main/CONTRIBUTING.md).
- [ ] I/we have discussed the proposed changes already, either in an issue on the repository, or in the Matrix chat.
- [x] I/we have not leveraged AI to create the proposed changes.
- [x] I/we have performed a self-review of added code.
- [x] I/we have written code that is legible and maintainable by others.
- [x] I/we have commented the added code, particularly in hard-to-understand areas.
- [ ] I/we have made any necessary changes to documentation.
- [x] I/we have added tests that cover new code.
- [x] I/we have run tests and they pass locally with the changes.
- [x] I/we have run `go fmt ./...` and `golangci-lint run`.

Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4275
Co-authored-by: nicole mikołajczyk <git@mkljczk.pl>
Co-committed-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk 2025-06-19 15:10:41 +02:00 committed by tobi
commit bfc8c31e5f
5 changed files with 238 additions and 6 deletions

View file

@ -370,6 +370,54 @@ func ExtractIconURI(i WithIcon) (*url.URL, error) {
return nil, gtserror.New("could not extract valid image URI from icon")
}
// ExtractIconDescription extracts the name property from
// the given WithIcon which links to a supported image file,
// or returns an empty string.
// Input will look something like this:
//
// "icon": {
// "mediaType": "image/jpeg",
// "name": "some description",
// "type": "Image",
// "url": "http://example.org/path/to/some/file.jpeg"
// },
func ExtractIconDescription(i WithIcon) string {
iconProp := i.GetActivityStreamsIcon()
if iconProp == nil {
return ""
}
// Icon can potentially contain multiple entries,
// so we iterate through all of them here in order
// to find the first one that meets these criteria:
//
// 1. Is an image.
// 2. Has a URL that we can use to derefereince it.
for iter := iconProp.Begin(); iter != iconProp.End(); iter = iter.Next() {
if !iter.IsActivityStreamsImage() {
continue
}
image := iter.GetActivityStreamsImage()
if image == nil {
continue
}
imageURL := GetURL(image)
if len(imageURL) == 0 {
// Nothing here.
continue
}
imageDescription := ExtractName(image)
// Got a hit.
return imageDescription
}
return ""
}
// ExtractImageURI extracts the first URI it can find from
// the given WithImage which links to a supported image file.
// Input will look something like this:
@ -416,6 +464,54 @@ func ExtractImageURI(i WithImage) (*url.URL, error) {
return nil, gtserror.New("could not extract valid image URI from image")
}
// ExtractImageDescription extracts the name property from
// the given WithImage which links to a supported image file,
// or returns an empty string.
// Input will look something like this:
//
// "image": {
// "mediaType": "image/jpeg",
// "name": "some description",
// "type": "Image",
// "url": "http://example.org/path/to/some/file.jpeg"
// },
func ExtractImageDescription(i WithImage) string {
imageProp := i.GetActivityStreamsImage()
if imageProp == nil {
return ""
}
// Image can potentially contain multiple entries,
// so we iterate through all of them here in order
// to find the first one that meets these criteria:
//
// 1. Is an image.
// 2. Has a URL that we can use to derefereince it.
for iter := imageProp.Begin(); iter != imageProp.End(); iter = iter.Next() {
if !iter.IsActivityStreamsImage() {
continue
}
image := iter.GetActivityStreamsImage()
if image == nil {
continue
}
imageURL := GetURL(image)
if len(imageURL) == 0 {
// Nothing here.
continue
}
imageDescription := ExtractName(image)
// Got a hit.
return imageDescription
}
return ""
}
// ExtractSummary extracts the summary/content warning of
// the given WithSummary interface. Will return an empty
// string if no summary/content warning was present.