20 KiB
Activities and Objects
:local:
:depth: 2
Supported activities
Follow
A follow enables actors to access and retrieve content from other actors as soon as it updates.
::::{dropdown} Supported on
::::
Internal logic
When Funkwhale receives a follow on a library object, it performs one of the following actions depending on the library's visibility:
- Automatically accept: If the library is public, Funkwhale automatically accepts the follow activity. Funkwhale sends a notification to the owner of the library and an
Accept
activity to the actor who sent the follow - Accept request: If the library isn't public, Funkwhale sends a notification to the library owner. If the owner approves the request, Funkwhale sends an
Accept
activity to the actor who sent the follow
Funkwhale uses the library follow status to grant access to the actor who sent the follow request. If the library isn't public and the owner doesn't send an approval, the requesting actor can't access the library's content.
For User's actors the logic is the same but we use the privacy_level of the user instead of the public to automaically accept the Follow.
Checks
Funkwhale ensures the activity is being sent to the library's owner before handling it.
Example
In this example, Alice sends a follow activity for a library object owned by Bob.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"type": "Follow",
"id": "https://music.rocks/federation/actors/Alice#follows/99fc40d7-9bc8-4c4a-add1-f637339e1ded",
"actor": "https://music.rocks/federation/actors/Alice",
"to": ["https://awesome.music/federation/actors/Bob"],
"object": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6"
}
Supported Activities
Activities sent to followings users (or to the world if the account is set to public) are :
Accept
The Accept
activity sends a positive response, such as confirming a Follow
activity.
::::{dropdown} Supported on
Activity
objects
::::
Internal logic
When Funkwhale receives an Accept
activity related to a Follow
activity, it marks the Follow
as accepted in the database. If the Follow
activity relates to a Library
object, the requester receives future activities associated with the library. This includes Create
, Audio
, and Delete
activities. They can also browse and download the library's audio files. See the section on Audio fetching on restricted libraries for more details.
Checks
Funkwhale ensures the activity is sent by the library's owner before handling it.
Example
In this example, Bob accepts a follow request from Alice.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"type": "Accept",
"id": "https://music.rocks/federation/actors/Alice#follows/99fc40d7-9bc8-4c4a-add1-f637339e1ded/accept",
"to": ["https://music.rocks/federation/actors/Alice"],
"actor": "https://awesome.music/federation/actors/Bob",
"object": {
"id": "https://music.rocks/federation/actors/Alice#follows/99fc40d7-9bc8-4c4a-add1-f637339e1ded",
"type": "Follow",
"actor": "https://music.rocks/federation/actors/Alice",
"object": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6",
},
}
Undo
::::{dropdown} Supported on
::::
Internal logic
When Funkwhale receives an Undo
activity, it deletes the corresponding Follow
from the database.
Checks
Funkwhale ensures the request actor is the same actor who sent the Follow
activity before handling it.
Example
In this example, Alice notifies Bob that she's undoing her follow.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"type": "Undo",
"id": "https://music.rocks/federation/actors/Alice#follows/99fc40d7-9bc8-4c4a-add1-f637339e1ded/accept",
"to": ["https://awesome.music/federation/actors/Bob"],
"actor": "https://music.rocks/federation/actors/Alice",
"object": {
"id": "https://music.rocks/federation/actors/Alice#follows/99fc40d7-9bc8-4c4a-add1-f637339e1ded",
"type": "Follow",
"actor": "https://music.rocks/federation/actors/Alice",
"object": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6",
},
}
Create
::::{dropdown} Supported on
::::
Internal logic
See [the `Audio` object reference](#audio) for details on the object's structure.
When Funkwhale receives a Create
activity with an Audio
object, it persists a local upload in the database. It then associates the upload to related library and track information. If no track matches the audio metadata, Funkwhale creates on using the metadata
attribute in the object.
Checks
Funkwhale ensures the activity actor and library owner are the same before handling the activity. If the associated library has no local followers, Funkwhale discards the activity.
Example
In this example, Bob creates new content in his library and sends a message to its followers.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"to": [
"https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6/followers"
],
"type": "Create",
"actor": "https://awesome.music/federation/actors/Bob",
"object": {}
}
Update
::::{dropdown} Supported on
::::
Internal logic
See [the `Track` object reference](#track) and [`Library` object reference](#library) for details on the object's structure.
When Funkwhale receives an update associated with a Library
or Track
object, it attempts to update the corresponding object in its database.
Checks
Funkwhale performs different checks depending on the target of the update:
- For
Library
objects, Funkwhale ensures the actor sending the message is the library owner - For
Track
objects, Funkwhale ensures the actor sending the message either:- Matches the
attributedTo
property on the local copy of the object - Is the service actor
- Matches the
Example
In this example, Bob updates his library and sends a message to its followers.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"to": [
"https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6/followers"
],
"type": "Update",
"actor": "https://awesome.music/federation/actors/Bob",
"object": {}
}
Delete
::::{dropdown} Supported on
::::
Internal logic
When Funkwhale receives a Delete
activity, it deletes the associated object from the database.
Checks
Funkwhale ensures the actor initiating the activity is the owner of the associated object before handling it.
Example
::::{tab-set}
:::{tab-item} Library
In this example, Bob deletes a library and notifies its followers.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"type": "Delete",
"to": [
"https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6/followers"
],
"actor": "https://awesome.music/federation/actors/Bob",
"object": {
"type": "Library",
"id": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6"
}
}
:::
:::{tab-item} Audio
In this example, Bob deletes three audio objects in a library and notifies the library's followers.
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"type": "Delete",
"to": [
"https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6/followers"
],
"actor": "https://awesome.music/federation/actors/Bob",
"object": {
"type": "Audio",
"id": [
"https://awesome.music/federation/music/uploads/19420073-3572-48a9-8c6c-b385ee1b7905",
"https://awesome.music/federation/music/uploads/11d99680-23c6-4f72-997a-073b980ab204",
"https://awesome.music/federation/music/uploads/1efadc1c-a704-4b8a-a71a-b288b1d1f423"
]
}
}
:::
::::
Like
We send the Like object with its type : this allow proper routing and avoid useless database and network queries.
::::{dropdown} Supported on
::::
Example
{
"type": "Like",
"id": "https://burn.patriachy//7b54d361-c513-4756-a085-13f97573237b",
""object": {
"Type": "Track",
"id": "https://Le_Rn.areRacists//aebd2be4-49a1-4ef5-aadf-27bff1001d4d",
},
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
"https://funkwhale.audio/ns",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"Hashtag": "as:Hashtag",
},
],
}
Dislike
We send the Dislike object with its type : this allow proper routing and avoid useless database and network queries.
::::{dropdown} Supported on
::::
Example
{
"type": "Dislike",
"id": "https://burn.patriachy//7b54d361-c513-4756-a085-13f97573237b",
""object": {
"Type": "Track",
"id": "https://Le_Rn.areRacists//aebd2be4-49a1-4ef5-aadf-27bff1001d4d",
},
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
"https://funkwhale.audio/ns",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"Hashtag": "as:Hashtag",
},
],
}
Listen
We send the Listen object with its type : this allow proper routing and avoid useless database and network queries.
::::{dropdown} Supported on
::::
Example
{
"type": "Listen",
"id": "https://makerichpeoplepay.forclimatechange//5355f8b7-bbcc-4285-9c13-d21748084cc1",
"object": {
"Type": "Track",
"id": "https://Le_Rn.areRacists//aebd2be4-49a1-4ef5-aadf-27bff1001d4d",
},
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
"https://funkwhale.audio/ns",
{
"manuallyApprovesFollowers": "as:manuallyApprovesFollowers",
"Hashtag": "as:Hashtag",
},
],
}
Supported objects
Artist
An Artist
is a custom object used to store musical artist and podcast creator information.
Properties
:header-rows: 1
* - Property
- Data type
- Description
* - `type`*
- String
- The object type (`Artist`)
* - `id`*
- String (URI)
- A URI that identifies the artist over federation
* - `name`*
- String
- The artist's name
* - `published`*
- Datetime
- The date on which the artist was published over the federation
* - `musicbrainzId`
- String (UUID)
- The Musicbrainz artist ID
Example
{
"type": "Artist",
"id": "https://awesome.music/federation/music/artists/73c32807-a199-4682-8068-e967f734a320",
"name": "Krav Boca",
"published": "2018-04-08T12:19:05.920415+00:00",
"musicbrainzId": "65f4f0c5-ef9e-490c-aee3-909e7ae6b2ab"
}
ArtistCredit
An ArtistCredit
is a custom object used to store information about how artists are credited in music objects. We followed Musicbrainz data structure.
Properties
:header-rows: 1
* - Property
- Data type
- Description
* - `type`*
- String
- The object type (`ArtistCredit`)
* - `id`*
- String (URI)
- A URI that identifies the artist over federation
* - `artist`*
- [`Artist` object](#artist)
- The credited Artist
* - `credit`*
- String
- How the artist is credited in the object. Can differ from artist.name
* - `joinphrase`
- String
- Concatenated after artist credit. Join the present ArtistCredit with the next one.
* - `published`*
- Datetime
- The date on which the artist was published over the federation
Example
{
"type": "ArtistCredit",
"id": "https://test.federation/federation/music/artistcredit/6dc0071c-0186-4f27-a234-fa5858774400",
"artist": {
"type": "Artist",
"id": "https://white.info//6dc0071c-0186-4f27-a234-fa5858774400",
"name": "John Ross",
"published": "2024-12-22T21:54:46.391743+00:00",
"musicbrainzId": "6dc0071c-0186-4f27-a234-fa5858774400",
"attributedTo": None,
"tag": [],
"image": None,
},
"joinphrase": "feat. ",
"credit": "John Ross",
"index": None,
"published": "2024-12-22T21:54:46.392309+00:00",
}
Album
An Album
is a custom object used to store album and podcast series information.
Properties
:header-rows: 1
* - Property
- Data type
- Description
* - `type`*
- String
- The object type (`Album`)
* - `id`*
- String (URI)
- A URI that identifies the album over federation
* - `name`*
- String
- The album's title
* - `artist_credit`
- Array of strings
- A list of [`ArtistCredit` objects](#artistcredit) associated with the albums
* - `published`*
- Datetime
- The date on which the artist was published over the federation
* - `released`
- Datetime
- The date on which the album was released
* - `musicbrainzId`
- String (UUID)
- The Musicbrainz release ID
* - `cover`
- [`Link` object](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-link)
- A `Link` object representing the album cover
Example
{
"type": "Album",
"id": "https://awesome.music/federation/music/albums/69d488b5-fdf6-4803-b47c-9bb7098ea57e",
"name": "Ride the Lightning",
"released": "1984-01-01",
"published": "2018-10-02T19:49:17.412546+00:00",
"musicbrainzId": "589ff96d-0be8-3f82-bdd2-299592e51b40",
"cover": {
"href": "https://awesome.music/media/albums/covers/2018/10/02/b69d398b5-fdf6-4803-b47c-9bb7098ea57e.jpg",
"type": "Link",
"mediaType": "image/jpeg"
},
"artist_credit": [
{}
]
}
Track
A Track
is a custom object used to store track information.
Properties
:header-rows: 1
* - Property
- Data type
- Description
* - `type`*
- String
- The object type (`Track`)
* - `id`*
- String (URI)
- A URI that identifies the track over federation
* - `name`*
- String
- The track title
* - `position`*
- Integer
- The position of the track in the album
* - `published`*
- Datetime
- The date on which the track was published over the federation
* - `musicbrainzId`
- String (UUID)
- The Musicbrainz recording ID
* - `album`
- [`Album` object](#album)
- The album that contains the track
* - `artist_credit`
- Array of strings
- A list of [`ArtistCredit` objects](#artistcredit) associated with the track. This can differ from the album artists
Example
{
"type": "Track",
"id": "https://awesome.music/federation/music/tracks/82ece296-6397-4e26-be90-bac5f9990240",
"name": "Shock! Extinction de masse",
"position": 3,
"published": "2018-10-02T19:49:35.822537+00:00",
"musicbrainzId": "771ab043-8821-44f9-b8e0-2733c3126c6d",
"artist_credit": [
{}
],
"album": {}
}
Library
Crawling library pages requires authentication and an approved follow unless the library is public.
A Library
is a custom object used to store music collection information. It inherits its behavior and properties from ActivityPub's Actor
and Collection
objects.
Properties
:header-rows: 1
* - Property
- Data type
- Description
* - `type`*
- String
- The object type (`Library`)
* - `id`*
- String (URI)
- A URI that identifies the library over federation
* - `name`*
- String
- The library's name
* - `followers`*
- String (URI)
- The ID of the library's followers collection
* - `totalItems`*
- Integer
- The number of [`Audio` objects](#audio) in the library
* - `first`*
- String (URI)
- The URL of the library's first page
* - `last`*
- String (URI)
- The URL of the library's last page
* - `summary`
- String
- The library's description
Example
{
"type": "Library",
"id": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6",
"attributedTo": "https://awesome.music/federation/actors/Alice",
"name": "My awesome library",
"followers": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6/followers",
"summary": "This library is for restricted use only",
"totalItems": 4234,
"first": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6?page=1",
"last": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6?page=56",
}
Audio
Accessing audio files requires authentication and an approved follow for the containing library unless the library is public.
An Audio
object is a custom object used to store upload information. It extends the ActivityStreams Audio object with custom attributes.
Properties
:header-rows: 1
* - Property
- Data type
- Description
* - `type`*
- String
- The object type (`Audio`)
* - `id`*
- String (URI)
- A URI that identifies the audio over federation
* - `name`*
- String
- A readable title for the order. Funkwhale concatenates the track name, album title, and artist name
* - `size`*
- Integer
- The size of the audio in bytes
* - `bitrate`*
- Integer
- The bitrate of the audio in bytes/s
* - `duration`*
- Integer
- The duration of the audio in seconds
* - `library`*
- String (URI)
- The ID of the audio's containing [`Library` object](#library)
* - `published`*
- Datetime
- The date on which the audio was published over the federation
* - `updated`*
- Datetime
- The date on which the audio was last updated over the federation
* - `url`*
- [`Link` object](https://www.w3.org/TR/activitystreams-vocabulary/#dfn-link)
- A `Link` object object containing the download location of the audio file
* - `track`
- [`Track` object](#track)
- The track associated with the audio file
Example
{
"type": "Audio",
"id": "https://awesome.music/federation/music/uploads/88f0bc20-d7fd-461d-a641-dd9ac485e096",
"name": "Krav Boca - Mortem",
"size": 8656581,
"bitrate": 320000,
"duration": 213,
"library": "https://awesome.music/federation/music/libraries/dc702491-f6ce-441b-9da0-cecbed08bcc6",
"updated": "2018-10-02T19:49:35.646372+00:00",
"published": "2018-10-02T19:49:35.646359+00:00",
"track": {},
"url": {
"href": "https://awesome.music/api/v1/listen/82ece296-6397-4e26-be90-bac5f9990240/?upload=88f0bc20-d7fd-461d-a641-dd9ac485e096",
"type": "Link",
"mediaType": "audio/mpeg"
}
}