mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2025-11-18 16:47:29 -06:00
parse funkwhale / bandwagon album as statusable
This commit is contained in:
parent
728c1289f3
commit
c1fd23438d
8 changed files with 171 additions and 43 deletions
|
|
@ -98,10 +98,17 @@ const (
|
||||||
// that we don't *yet* know what type of Object something is.
|
// that we don't *yet* know what type of Object something is.
|
||||||
ObjectUnknown = "Unknown"
|
ObjectUnknown = "Unknown"
|
||||||
|
|
||||||
// Extensions and unofficial additions.
|
/* Extensions and unofficial additions */
|
||||||
|
|
||||||
|
/* GtS stuff */
|
||||||
|
|
||||||
ObjectLikeApproval = "LikeApproval"
|
ObjectLikeApproval = "LikeApproval"
|
||||||
ObjectReplyApproval = "ReplyApproval"
|
ObjectReplyApproval = "ReplyApproval"
|
||||||
ObjectAnnounceApproval = "AnnounceApproval"
|
ObjectAnnounceApproval = "AnnounceApproval"
|
||||||
|
|
||||||
|
/* Funkwhale stuff */
|
||||||
|
|
||||||
|
ObjectAlbum = "Album"
|
||||||
)
|
)
|
||||||
|
|
||||||
// isActivity returns whether AS type name is of an Activity (NOT IntransitiveActivity).
|
// isActivity returns whether AS type name is of an Activity (NOT IntransitiveActivity).
|
||||||
|
|
|
||||||
|
|
@ -1078,7 +1078,14 @@ func ExtractInteractionPolicy(
|
||||||
statusable Statusable,
|
statusable Statusable,
|
||||||
owner *gtsmodel.Account,
|
owner *gtsmodel.Account,
|
||||||
) *gtsmodel.InteractionPolicy {
|
) *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 {
|
if policyProp == nil || policyProp.Len() != 1 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,8 @@ func IsStatusable(typeName string) bool {
|
||||||
ObjectEvent,
|
ObjectEvent,
|
||||||
ObjectPlace,
|
ObjectPlace,
|
||||||
ObjectProfile,
|
ObjectProfile,
|
||||||
ActivityQuestion:
|
ActivityQuestion,
|
||||||
|
ObjectAlbum:
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
|
@ -226,11 +227,13 @@ type Statusable interface {
|
||||||
WithTo
|
WithTo
|
||||||
WithCc
|
WithCc
|
||||||
WithSensitive
|
WithSensitive
|
||||||
WithConversation
|
|
||||||
WithContent
|
WithContent
|
||||||
WithAttachment
|
WithAttachment
|
||||||
WithTag
|
WithTag
|
||||||
WithReplies
|
WithReplies
|
||||||
|
}
|
||||||
|
|
||||||
|
type InteractionPolicyAware interface {
|
||||||
WithInteractionPolicy
|
WithInteractionPolicy
|
||||||
WithApprovedBy
|
WithApprovedBy
|
||||||
}
|
}
|
||||||
|
|
@ -589,10 +592,6 @@ type WithSensitive interface {
|
||||||
SetActivityStreamsSensitive(vocab.ActivityStreamsSensitiveProperty)
|
SetActivityStreamsSensitive(vocab.ActivityStreamsSensitiveProperty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithConversation ...
|
|
||||||
type WithConversation interface { // TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
// WithContent represents an activity with ActivityStreamsContentProperty
|
// WithContent represents an activity with ActivityStreamsContentProperty
|
||||||
type WithContent interface {
|
type WithContent interface {
|
||||||
GetActivityStreamsContent() vocab.ActivityStreamsContentProperty
|
GetActivityStreamsContent() vocab.ActivityStreamsContentProperty
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,56 @@ func (suite *ResolveTestSuite) TestResolveNonAPJSONAsAccountable() {
|
||||||
suite.Nil(accountable)
|
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) {
|
func TestResolveTestSuite(t *testing.T) {
|
||||||
suite.Run(t, &ResolveTestSuite{})
|
suite.Run(t, &ResolveTestSuite{})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,9 @@ func serializeStatusable(t vocab.Type, includeContext bool) (map[string]interfac
|
||||||
|
|
||||||
NormalizeOutgoingAttachmentProp(statusable, data)
|
NormalizeOutgoingAttachmentProp(statusable, data)
|
||||||
NormalizeOutgoingContentProp(statusable, data)
|
NormalizeOutgoingContentProp(statusable, data)
|
||||||
NormalizeOutgoingInteractionPolicyProp(statusable, data)
|
if ipa, ok := statusable.(InteractionPolicyAware); ok {
|
||||||
|
NormalizeOutgoingInteractionPolicyProp(ipa, data)
|
||||||
|
}
|
||||||
|
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -434,9 +434,10 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
|
||||||
return nil, gtserror.SetMalformed(err)
|
return nil, gtserror.SetMalformed(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Status was sent to us or dereffed
|
// Status was sent to us or dereffed by
|
||||||
// by us so it must be federated.
|
// us so it must be federated and not local.
|
||||||
status.Federated = util.Ptr(true)
|
status.Federated = util.Ptr(true)
|
||||||
|
status.Local = util.Ptr(false)
|
||||||
|
|
||||||
// Derive interaction policy for this status.
|
// Derive interaction policy for this status.
|
||||||
status.InteractionPolicy = ap.ExtractInteractionPolicy(
|
status.InteractionPolicy = ap.ExtractInteractionPolicy(
|
||||||
|
|
@ -446,9 +447,11 @@ func (c *Converter) ASStatusToStatus(ctx context.Context, statusable ap.Statusab
|
||||||
|
|
||||||
// Set approvedByURI if present,
|
// Set approvedByURI if present,
|
||||||
// for later dereferencing.
|
// for later dereferencing.
|
||||||
approvedByURI := ap.GetApprovedBy(statusable)
|
if ipa, ok := statusable.(ap.InteractionPolicyAware); ok {
|
||||||
if approvedByURI != nil {
|
approvedByURI := ap.GetApprovedBy(ipa)
|
||||||
status.ApprovedByURI = approvedByURI.String()
|
if approvedByURI != nil {
|
||||||
|
status.ApprovedByURI = approvedByURI.String()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assume not pending approval; this may
|
// Assume not pending approval; this may
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -224,8 +223,7 @@ func (suite *ASToInternalTestSuite) TestParseOwncastService() {
|
||||||
|
|
||||||
b, err := json.Marshal(apiAcct)
|
b, err := json.Marshal(apiAcct)
|
||||||
suite.NoError(err)
|
suite.NoError(err)
|
||||||
|
suite.NotNil(b)
|
||||||
fmt.Printf("\n\n\n%s\n\n\n", string(b))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (suite *ASToInternalTestSuite) TestParseBookwyrmStatus() {
|
func (suite *ASToInternalTestSuite) TestParseBookwyrmStatus() {
|
||||||
|
|
@ -282,6 +280,65 @@ func (suite *ASToInternalTestSuite) TestParseBookwyrmStatus() {
|
||||||
suite.Len(status.Attachments, 1)
|
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() {
|
func (suite *ASToInternalTestSuite) TestParseFlag1() {
|
||||||
reportedAccount := suite.testAccounts["local_account_1"]
|
reportedAccount := suite.testAccounts["local_account_1"]
|
||||||
reportingAccount := suite.testAccounts["remote_account_1"]
|
reportingAccount := suite.testAccounts["remote_account_1"]
|
||||||
|
|
|
||||||
|
|
@ -705,35 +705,38 @@ func (c *Converter) StatusToAS(ctx context.Context, s *gtsmodel.Status) (ap.Stat
|
||||||
status.SetActivityStreamsSensitive(sensitiveProp)
|
status.SetActivityStreamsSensitive(sensitiveProp)
|
||||||
|
|
||||||
// interactionPolicy
|
// interactionPolicy
|
||||||
var p *gtsmodel.InteractionPolicy
|
if ipa, ok := status.(ap.InteractionPolicyAware); ok {
|
||||||
if s.InteractionPolicy != nil {
|
var p *gtsmodel.InteractionPolicy
|
||||||
// Use InteractionPolicy
|
if s.InteractionPolicy != nil {
|
||||||
// set on the status.
|
// Use InteractionPolicy
|
||||||
p = s.InteractionPolicy
|
// set on the status.
|
||||||
} else {
|
p = s.InteractionPolicy
|
||||||
// Fall back to default policy
|
} else {
|
||||||
// for the status's visibility.
|
// Fall back to default policy
|
||||||
p = gtsmodel.DefaultInteractionPolicyFor(s.Visibility)
|
// for the status's visibility.
|
||||||
}
|
p = gtsmodel.DefaultInteractionPolicyFor(s.Visibility)
|
||||||
policy, err := c.InteractionPolicyToASInteractionPolicy(ctx, p, s)
|
}
|
||||||
if err != nil {
|
policy, err := c.InteractionPolicyToASInteractionPolicy(ctx, p, s)
|
||||||
return nil, fmt.Errorf("error creating interactionPolicy: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
policyProp := streams.NewGoToSocialInteractionPolicyProperty()
|
|
||||||
policyProp.AppendGoToSocialInteractionPolicy(policy)
|
|
||||||
status.SetGoToSocialInteractionPolicy(policyProp)
|
|
||||||
|
|
||||||
// Parse + set approvedBy.
|
|
||||||
if s.ApprovedByURI != "" {
|
|
||||||
approvedBy, err := url.Parse(s.ApprovedByURI)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error parsing approvedBy: %w", err)
|
return nil, fmt.Errorf("error creating interactionPolicy: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
approvedByProp := streams.NewGoToSocialApprovedByProperty()
|
// Set interaction policy.
|
||||||
approvedByProp.Set(approvedBy)
|
policyProp := streams.NewGoToSocialInteractionPolicyProperty()
|
||||||
status.SetGoToSocialApprovedBy(approvedByProp)
|
policyProp.AppendGoToSocialInteractionPolicy(policy)
|
||||||
|
ipa.SetGoToSocialInteractionPolicy(policyProp)
|
||||||
|
|
||||||
|
// Parse + set approvedBy.
|
||||||
|
if s.ApprovedByURI != "" {
|
||||||
|
approvedBy, err := url.Parse(s.ApprovedByURI)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error parsing approvedBy: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
approvedByProp := streams.NewGoToSocialApprovedByProperty()
|
||||||
|
approvedByProp.Set(approvedBy)
|
||||||
|
ipa.SetGoToSocialApprovedBy(approvedByProp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status, nil
|
return status, nil
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue