parse funkwhale / bandwagon album as statusable

This commit is contained in:
tobi 2025-03-23 16:27:10 +01:00
commit c1fd23438d
8 changed files with 171 additions and 43 deletions

View file

@ -98,10 +98,17 @@ const (
// that we don't *yet* know what type of Object something is.
ObjectUnknown = "Unknown"
// Extensions and unofficial additions.
/* Extensions and unofficial additions */
/* GtS stuff */
ObjectLikeApproval = "LikeApproval"
ObjectReplyApproval = "ReplyApproval"
ObjectAnnounceApproval = "AnnounceApproval"
/* Funkwhale stuff */
ObjectAlbum = "Album"
)
// isActivity returns whether AS type name is of an Activity (NOT IntransitiveActivity).

View file

@ -1078,7 +1078,14 @@ func ExtractInteractionPolicy(
statusable Statusable,
owner *gtsmodel.Account,
) *gtsmodel.InteractionPolicy {
policyProp := statusable.GetGoToSocialInteractionPolicy()
ipa, ok := statusable.(InteractionPolicyAware)
if !ok {
// Not a type with interaction
// policy properties settable.
return nil
}
policyProp := ipa.GetGoToSocialInteractionPolicy()
if policyProp == nil || policyProp.Len() != 1 {
return nil
}

View file

@ -76,7 +76,8 @@ func IsStatusable(typeName string) bool {
ObjectEvent,
ObjectPlace,
ObjectProfile,
ActivityQuestion:
ActivityQuestion,
ObjectAlbum:
return true
default:
return false
@ -226,11 +227,13 @@ type Statusable interface {
WithTo
WithCc
WithSensitive
WithConversation
WithContent
WithAttachment
WithTag
WithReplies
}
type InteractionPolicyAware interface {
WithInteractionPolicy
WithApprovedBy
}
@ -589,10 +592,6 @@ type WithSensitive interface {
SetActivityStreamsSensitive(vocab.ActivityStreamsSensitiveProperty)
}
// WithConversation ...
type WithConversation interface { // TODO
}
// WithContent represents an activity with ActivityStreamsContentProperty
type WithContent interface {
GetActivityStreamsContent() vocab.ActivityStreamsContentProperty

View file

@ -80,6 +80,56 @@ func (suite *ResolveTestSuite) TestResolveNonAPJSONAsAccountable() {
suite.Nil(accountable)
}
func (suite *ResolveTestSuite) TestResolveBandwagonAlbumAsStatusable() {
b := []byte(`{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"discoverable": "toot:discoverable",
"indexable": "toot:indexable",
"toot": "https://joinmastodon.org/ns#"
},
"https://funkwhale.audio/ns"
],
"artists": [
{
"id": "https://bandwagon.fm/@67a0a0808121f77ed3466870",
"name": "Luka Prinčič",
"type": "Artist"
}
],
"attachment": [
{
"mediaType": "image/webp",
"name": "image",
"type": "Document",
"url": "https://bandwagon.fm/67a0a219f050061c8b4ce427/attachments/67a0a21bf050061c8b4ce429"
}
],
"attributedTo": "https://bandwagon.fm/@67a0a0808121f77ed3466870",
"content": "... a transgenre mutation, a fluid entity, jagged pop, electro-funk, techno-cabaret, a schlager, and soft alternative, queer to the core, satire and tragedy, sharp and fun indulgence for the dance of bodies and brains, activism and hedonism, which would all like to steal your attention.\r\n\r\nDRAGX̶FUNK is pronounced /dɹæɡɑːfʌŋk/.\r\n\r\n---\r\n\r\n## Buy digital\r\n💳 [Stripe](https://buy.stripe.com/6oE8x52iG1Kq5pKeV3)\r\n\r\n---\r\n\r\n## Buy dl/merch\r\n🎵 [Bandcamp](https://lukaprincic.bandcamp.com/album/dragx-funk) \r\n\r\n---\r\n\r\n## More:\r\n🌐 [prin.lu](https://prin.lu/music/241205_dragx-funk/) \r\n👉 [kamizdat.si](https://kamizdat.si/releases/dragx-funk-2/)\r\n",
"context": "https://bandwagon.fm/67a0a219f050061c8b4ce427",
"id": "https://bandwagon.fm/67a0a219f050061c8b4ce427",
"library": "https://bandwagon.fm/67a0a219f050061c8b4ce427/pub/children",
"license": "CC-BY-NC-SA",
"name": "DRAGX̶FUNK",
"published": "2025-03-17T11:40:53Z",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"tracks": "https://bandwagon.fm/67a0a219f050061c8b4ce427/pub/children",
"type": "Album",
"url": "https://bandwagon.fm/67a0a219f050061c8b4ce427"
}`)
statusable, err := ap.ResolveStatusable(
context.Background(), io.NopCloser(bytes.NewReader(b)),
)
suite.NoError(err)
suite.NotNil(statusable)
}
func TestResolveTestSuite(t *testing.T) {
suite.Run(t, &ResolveTestSuite{})
}

View file

@ -153,7 +153,9 @@ func serializeStatusable(t vocab.Type, includeContext bool) (map[string]interfac
NormalizeOutgoingAttachmentProp(statusable, data)
NormalizeOutgoingContentProp(statusable, data)
NormalizeOutgoingInteractionPolicyProp(statusable, data)
if ipa, ok := statusable.(InteractionPolicyAware); ok {
NormalizeOutgoingInteractionPolicyProp(ipa, data)
}
return data, nil
}

View file

@ -434,9 +434,10 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
return nil, gtserror.SetMalformed(err)
}
// Status was sent to us or dereffed
// by us so it must be federated.
// Status was sent to us or dereffed by
// us so it must be federated and not local.
status.Federated = util.Ptr(true)
status.Local = util.Ptr(false)
// Derive interaction policy for this status.
status.InteractionPolicy = ap.ExtractInteractionPolicy(
@ -446,10 +447,12 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
// Set approvedByURI if present,
// for later dereferencing.
approvedByURI := ap.GetApprovedBy(statusable)
if ipa, ok := statusable.(ap.InteractionPolicyAware); ok {
approvedByURI := ap.GetApprovedBy(ipa)
if approvedByURI != nil {
status.ApprovedByURI = approvedByURI.String()
}
}
// Assume not pending approval; this may
// change when permissivity is checked.

View file

@ -21,7 +21,6 @@ import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"testing"
@ -224,8 +223,7 @@ func (suite *ASToInternalTestSuite) TestParseOwncastService() {
b, err := json.Marshal(apiAcct)
suite.NoError(err)
fmt.Printf("\n\n\n%s\n\n\n", string(b))
suite.NotNil(b)
}
func (suite *ASToInternalTestSuite) TestParseBookwyrmStatus() {
@ -282,6 +280,65 @@ func (suite *ASToInternalTestSuite) TestParseBookwyrmStatus() {
suite.Len(status.Attachments, 1)
}
func (suite *ASToInternalTestSuite) TestParseBandwagonAlbum() {
authorAccount := suite.testAccounts["remote_account_1"]
raw := `{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"discoverable": "toot:discoverable",
"indexable": "toot:indexable",
"toot": "https://joinmastodon.org/ns#"
},
"https://funkwhale.audio/ns"
],
"artists": [
{
"id": "https://bandwagon.fm/@67a0a0808121f77ed3466870",
"name": "Luka Prinčič",
"type": "Artist"
}
],
"attachment": [
{
"mediaType": "image/webp",
"name": "image",
"type": "Document",
"url": "https://bandwagon.fm/67a0a219f050061c8b4ce427/attachments/67a0a21bf050061c8b4ce429"
}
],
"attributedTo": "` + authorAccount.URI + `",
"content": "... a transgenre mutation, a fluid entity, jagged pop, electro-funk, techno-cabaret, a schlager, and soft alternative, queer to the core, satire and tragedy, sharp and fun indulgence for the dance of bodies and brains, activism and hedonism, which would all like to steal your attention.\r\n\r\nDRAGX̶FUNK is pronounced /dɹæɡɑːfʌŋk/.\r\n\r\n---\r\n\r\n## Buy digital\r\n💳 [Stripe](https://buy.stripe.com/6oE8x52iG1Kq5pKeV3)\r\n\r\n---\r\n\r\n## Buy dl/merch\r\n🎵 [Bandcamp](https://lukaprincic.bandcamp.com/album/dragx-funk) \r\n\r\n---\r\n\r\n## More:\r\n🌐 [prin.lu](https://prin.lu/music/241205_dragx-funk/) \r\n👉 [kamizdat.si](https://kamizdat.si/releases/dragx-funk-2/)\r\n",
"context": "https://bandwagon.fm/67a0a219f050061c8b4ce427",
"id": "https://bandwagon.fm/67a0a219f050061c8b4ce427",
"library": "https://bandwagon.fm/67a0a219f050061c8b4ce427/pub/children",
"license": "CC-BY-NC-SA",
"name": "DRAGX̶FUNK",
"published": "2025-03-17T11:40:53Z",
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"tracks": "https://bandwagon.fm/67a0a219f050061c8b4ce427/pub/children",
"type": "Album",
"url": "https://bandwagon.fm/67a0a219f050061c8b4ce427"
}`
t := suite.jsonToType(raw)
asArticle, ok := t.(ap.Statusable)
if !ok {
suite.FailNow("type not coercible")
}
s, err := suite.typeconverter.ASStatusToStatus(context.Background(), asArticle)
if err != nil {
suite.FailNow(err.Error())
}
suite.NotNil(s)
suite.NoError(err)
}
func (suite *ASToInternalTestSuite) TestParseFlag1() {
reportedAccount := suite.testAccounts["local_account_1"]
reportingAccount := suite.testAccounts["remote_account_1"]

View file

@ -705,6 +705,7 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat
status.SetActivityStreamsSensitive(sensitiveProp)
// interactionPolicy
if ipa, ok := status.(ap.InteractionPolicyAware); ok {
var p *gtsmodel.InteractionPolicy
if s.InteractionPolicy != nil {
// Use InteractionPolicy
@ -720,9 +721,10 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat
return nil, fmt.Errorf("error creating interactionPolicy: %w", err)
}
// Set interaction policy.
policyProp := streams.NewGoToSocialInteractionPolicyProperty()
policyProp.AppendGoToSocialInteractionPolicy(policy)
status.SetGoToSocialInteractionPolicy(policyProp)
ipa.SetGoToSocialInteractionPolicy(policyProp)
// Parse + set approvedBy.
if s.ApprovedByURI != "" {
@ -733,7 +735,8 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat
approvedByProp := streams.NewGoToSocialApprovedByProperty()
approvedByProp.Set(approvedBy)
status.SetGoToSocialApprovedBy(approvedByProp)
ipa.SetGoToSocialApprovedBy(approvedByProp)
}
}
return status, nil