ActivityPub
Each PeerTube instance is able to fetch videos from other compatible servers it follows, in a process known as “federation”. Federation is implemented using the ActivityPub protocol, in order to leverage existing tools and be compatible with other services such as Mastodon, Pleroma and many more.
Federation in PeerTube is twofold: videos metadata are shared as activities for inter-server communication in what amounts to sharing parts of one's database, and user interaction via comments which are compatible with the kind of activity textual platforms like Mastodon use.
Federate with PeerTube
TIP
If you have any problem or question about PeerTube federation, don't hesitate to discuss about them on our forum
PeerTube has the concept of video channels (Group
actor) that are owned by accounts (Person
actor). In ActivityPub, a PeerTube video is created by the account and Announce
d by the video channel.
To federate videos, PeerTube requires the video to have an attributedTo
field that contains a Group
actor. The Group
actor also contains an attributedTo
field pointing to the owner Person
actor (see the documentation for more information and examples).
If your video platform doesn't have the concept of channels, we recommend you either:
- simulate a
Group
actor representing your account (automatically adding_channel
to your account username example) - put your
Person
actor as aGroup
actor inattributedTo
that is owned by a globalPerson
actor that would own all your fake channels
Supported Activities
Supported Objects
Activities
Follow
Follow is an activity standardized in the ActivityPub specification (see Follow Activity). The Follow activity is used to subscribe to the activities of another actor (a server subscribing to another server's videos, a user subscribing to another user's videos).
Supported on
- Actor (
peertube
actor, account actor or channel actor)
Accept
Supported on
- Follow
Reject
Reject is an activity standardized in the ActivityPub specification (see Reject Activity).
Supported on
- Follow
Undo
Undo is an activity standardized in the ActivityPub specification (see Undo Activity). The Undo activity is used to undo a previous activity.
Supported on
Like
Like is an activity standardized in the ActivityPub specification (see Like Activity). Supported on
Dislike
Dislike is an activity standardized in the ActivityStream specification (see Dislike Activity).
Supported on
Update
Update is an activity standardized in the ActivityPub specification (see Update Activity). The Update activity is used when updating an already existing object.
Supported on
Create
Create is an activity standardized in the ActivityPub specification (see Create Activity). The Create activity is used when posting a new object. This has the side effect that the object
embedded within the Activity (in the object property) is created.
Supported on
- Video
- Playlist
- CacheFile
- Note (a comment)
- WatchAction
Example
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{}
],
"to": ["https://peertube2.cpy.re/accounts/root/activity"],
"type": "Create",
"actor": "https://peertube2.cpy.re/accounts/root",
"object": {}
}
Delete
Delete is an activity standardized in the ActivityPub specification (see Delete Activity).
Supported on
Announce
Announce is an activity standardized in the ActivityPub specification (see Announce Activity).
Supported on
Example
{
"type": "Announce",
"id": "https://peertube2.cpy.re/videos/watch/997111d4-e8d8-4f45-99d3-857905785d05/announces/1",
"actor": "https://peertube2.cpy.re/accounts/root",
"object": "https://peertube2.cpy.re/videos/watch/997111d4-e8d8-4f45-99d3-857905785d05",
"to": [
"https://www.w3.org/ns/activitystreams#Public",
"https://peertube2.cpy.re/accounts/root/followers",
"https://peertube2.cpy.re/video-channels/root_channel/followers"
],
"cc": []
}
Flag
Flag is an activity standardized in the ActivityStream specification (see Flag Activity).
Supported on
View
View is an activity standardized in the ActivityStream specification (see View Activity).
A PeerTube instance sends a View
activity every time a user watched a video so the origin server can increment video views counter.
If the View
activity includes an expires
attribute, it means a user is currently watching a video. This kind of event is sent periodically until the user stops watching the video. The same View
action can be sent multiple times using a different expires
attribute, meaning the user is still watching the video.
Supported on
ApproveReply PeerTube >= 6.2
PeerTube implements FEP-5624 draft so users can moderate comments of their videos.
If the video requires comments approval, the Video
object includes
"canReply": "https://www.w3.org/ns/activitystreams#Public"
PeerTube sends back an ApproveReply
activity to the Note
origin server when the comment is approved. The Video
origin server also forwards the Note
to actors involved in the video.
Supported on
Objects
Video
INFO
This object extends the ActivityPub specification, and therefore some properties are not part of it.
TypeScript model: packages/models/src/activitypub/objects/video-object.ts.
import { LiveVideoLatencyModeType, VideoCommentPolicyType, VideoStateType } from '../../videos/index.js'
import {
ActivityIconObject,
ActivityIdentifierObject,
ActivityPubAttributedTo,
ActivityTagObject,
ActivityUrlObject
} from './common-objects.js'
import { VideoCaptionObject } from './video-caption-object.js'
import { VideoChapterObject } from './video-chapters-object.js'
export interface VideoObject {
type: 'Video'
id: string
name: string
duration: string
uuid: string
tag: ActivityTagObject[]
category: ActivityIdentifierObject
licence: ActivityIdentifierObject
language: ActivityIdentifierObject
subtitleLanguage: VideoCaptionObject[]
views: number
sensitive: boolean
isLiveBroadcast: boolean
liveSaveReplay: boolean
permanentLive: boolean
latencyMode: LiveVideoLatencyModeType
commentsEnabled?: boolean
commentsPolicy: VideoCommentPolicyType
canReply: 'as:Public' | 'https://www.w3.org/ns/activitystreams#Public'
downloadEnabled: boolean
waitTranscoding: boolean
state: VideoStateType
published: string
originallyPublishedAt: string
updated: string
uploadDate: string
mediaType: 'text/markdown'
content: string
support: string
aspectRatio: number
icon: ActivityIconObject[]
url: ActivityUrlObject[]
likes: string
dislikes: string
shares: string
comments: string
hasParts: string | VideoChapterObject[]
attributedTo: ActivityPubAttributedTo[]
preview?: ActivityPubStoryboard[]
to?: string[]
cc?: string[]
// For export
attachment?: {
type: 'Video'
url: string
mediaType: string
height: number
size: number
fps: number
}[]
}
export interface ActivityPubStoryboard {
type: 'Image'
rel: [ 'storyboard' ]
url: {
href: string
mediaType: string
width: number
height: number
tileWidth: number
tileHeight: number
tileDuration: string
}[]
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"Hashtag": "as:Hashtag",
"category": "sc:category",
"licence": "sc:license",
"subtitleLanguage": "sc:subtitleLanguage",
"sensitive": "as:sensitive",
"language": "sc:inLanguage",
"identifier": "sc:identifier",
"isLiveBroadcast": "sc:isLiveBroadcast",
"liveSaveReplay": {
"@type": "sc:Boolean",
"@id": "pt:liveSaveReplay"
},
"permanentLive": {
"@type": "sc:Boolean",
"@id": "pt:permanentLive"
},
"latencyMode": {
"@type": "sc:Number",
"@id": "pt:latencyMode"
},
"Infohash": "pt:Infohash",
"tileWidth": {
"@type": "sc:Number",
"@id": "pt:tileWidth"
},
"tileHeight": {
"@type": "sc:Number",
"@id": "pt:tileHeight"
},
"tileDuration": {
"@type": "sc:Number",
"@id": "pt:tileDuration"
},
"aspectRatio": {
"@type": "sc:Float",
"@id": "pt:aspectRatio"
},
"uuid": {
"@type": "sc:identifier",
"@id": "pt:uuid"
},
"originallyPublishedAt": "sc:datePublished",
"uploadDate": "sc:uploadDate",
"hasParts": "sc:hasParts",
"views": {
"@type": "sc:Number",
"@id": "pt:views"
},
"state": {
"@type": "sc:Number",
"@id": "pt:state"
},
"size": {
"@type": "sc:Number",
"@id": "pt:size"
},
"fps": {
"@type": "sc:Number",
"@id": "pt:fps"
},
"commentsEnabled": {
"@type": "sc:Boolean",
"@id": "pt:commentsEnabled"
},
"canReply": "pt:canReply",
"commentsPolicy": {
"@type": "sc:Number",
"@id": "pt:commentsPolicy"
},
"downloadEnabled": {
"@type": "sc:Boolean",
"@id": "pt:downloadEnabled"
},
"waitTranscoding": {
"@type": "sc:Boolean",
"@id": "pt:waitTranscoding"
},
"support": {
"@type": "sc:Text",
"@id": "pt:support"
},
"likes": {
"@id": "as:likes",
"@type": "@id"
},
"dislikes": {
"@id": "as:dislikes",
"@type": "@id"
},
"shares": {
"@id": "as:shares",
"@type": "@id"
},
"comments": {
"@id": "as:comments",
"@type": "@id"
}
}
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://peertube2.cpy.re/accounts/root/followers"
],
"type": "Video",
"id": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a",
"name": "The Internet's Own Boy",
"duration": "PT6299S",
"uuid": "04af977f-4201-4697-be67-a8d8cae6fa7a",
"category": {
"identifier": "2",
"name": "Films"
},
"licence": {
"identifier": "5",
"name": "Attribution - Non Commercial - Share Alike"
},
"language": {
"identifier": "en",
"name": "English"
},
"views": 11025,
"sensitive": false,
"waitTranscoding": false,
"state": 1,
"commentsEnabled": true,
"canReply": null,
"commentsPolicy": 1,
"downloadEnabled": true,
"published": "2017-10-17T14:04:23.288Z",
"originallyPublishedAt": null,
"updated": "2024-05-31T08:02:44.917Z",
"tag": [
{
"type": "Hashtag",
"name": "eertherth"
}
],
"mediaType": "text/markdown",
"content": "The story of programming prodigy and information activist Aaron Swartz, who took his own life at the age of 26.",
"support": null,
"subtitleLanguage": [],
"icon": [
{
"type": "Image",
"url": "https://peertube2.cpy.re/lazy-static/thumbnails/22efe749-bd30-4b4e-83f3-3c9912d69b67.jpg",
"mediaType": "image/jpeg",
"width": 280,
"height": 157
},
{
"type": "Image",
"url": "https://peertube2.cpy.re/lazy-static/previews/04af977f-4201-4697-be67-a8d8cae6fa7a.jpg",
"mediaType": "image/jpeg",
"width": 560,
"height": 315
}
],
"preview": [
{
"type": "Image",
"rel": [
"storyboard"
],
"url": [
{
"mediaType": "image/jpeg",
"href": "https://peertube2.cpy.re/lazy-static/storyboards/3598a6b5-d9a6-4ef1-b3ae-ab3f79a8c5ac.jpg",
"width": 1920,
"height": 1080,
"tileWidth": 192,
"tileHeight": 108,
"tileDuration": "PT63S"
}
]
}
],
"aspectRatio": null,
"url": [
{
"type": "Link",
"mediaType": "text/html",
"href": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a"
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/web-videos/04af977f-4201-4697-be67-a8d8cae6fa7a-720.mp4",
"height": 720,
"width": null,
"size": 942586378,
"fps": -1
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/14",
"height": 720,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/04af977f-4201-4697-be67-a8d8cae6fa7a-720.torrent",
"height": 720,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2F04af977f-4201-4697-be67-a8d8cae6fa7a-720.torrent&xt=urn:btih:96bc64e8731aa86269c1f9266177bc9f92581437&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fweb-videos%2F04af977f-4201-4697-be67-a8d8cae6fa7a-720.mp4",
"height": 720,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/web-videos/04af977f-4201-4697-be67-a8d8cae6fa7a-480.mp4",
"height": 480,
"width": null,
"size": 535692756,
"fps": -1
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/17",
"height": 480,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/04af977f-4201-4697-be67-a8d8cae6fa7a-480.torrent",
"height": 480,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2F04af977f-4201-4697-be67-a8d8cae6fa7a-480.torrent&xt=urn:btih:c962cbdcff46ded985b5dd2a56672040f46200bb&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fweb-videos%2F04af977f-4201-4697-be67-a8d8cae6fa7a-480.mp4",
"height": 480,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/web-videos/04af977f-4201-4697-be67-a8d8cae6fa7a-360.mp4",
"height": 360,
"width": null,
"size": 394767560,
"fps": -1
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/16",
"height": 360,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/04af977f-4201-4697-be67-a8d8cae6fa7a-360.torrent",
"height": 360,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2F04af977f-4201-4697-be67-a8d8cae6fa7a-360.torrent&xt=urn:btih:0db617d3091abf1b3a84e238028ccc008c1cbf3d&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fweb-videos%2F04af977f-4201-4697-be67-a8d8cae6fa7a-360.mp4",
"height": 360,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/web-videos/04af977f-4201-4697-be67-a8d8cae6fa7a-240.mp4",
"height": 240,
"width": null,
"size": 261723796,
"fps": -1
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/15",
"height": 240,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/04af977f-4201-4697-be67-a8d8cae6fa7a-240.torrent",
"height": 240,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2F04af977f-4201-4697-be67-a8d8cae6fa7a-240.torrent&xt=urn:btih:90cf3a384cc09737780f715eb77a2fe5a02ead15&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fweb-videos%2F04af977f-4201-4697-be67-a8d8cae6fa7a-240.mp4",
"height": 240,
"width": null,
"fps": -1
},
{
"type": "Link",
"mediaType": "application/x-mpegURL",
"href": "https://peertube2.cpy.re/static/streaming-playlists/hls/04af977f-4201-4697-be67-a8d8cae6fa7a/754c65d0-ee08-4779-9133-229a0bda2ee2-master.m3u8",
"tag": [
{
"type": "Infohash",
"name": "a527fb0ec592862ec593d06f9bb70eab8c4092c6"
},
{
"type": "Infohash",
"name": "1d593a9ff05246a46a5f67bd32acaf97d4ff0e35"
},
{
"type": "Infohash",
"name": "5ae66b6da67306b2e60341217230775d9064d3a9"
},
{
"type": "Infohash",
"name": "abd4318e5a0904ab4bf6d7521a2214ab4b2d0b47"
},
{
"type": "Link",
"name": "sha256",
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/static/streaming-playlists/hls/04af977f-4201-4697-be67-a8d8cae6fa7a/2cae232e-6eb2-4268-863f-5036deef8e97-segments-sha256.json"
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/streaming-playlists/hls/04af977f-4201-4697-be67-a8d8cae6fa7a/c7cc2798-5f06-418d-bf70-e03976f99e3f-720-fragmented.mp4",
"height": 720,
"width": null,
"size": 818499517,
"fps": 24
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/5314509",
"height": 720,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/e18ea17a-6cd9-43ce-97f3-a680f4d45b3b-720-hls.torrent",
"height": 720,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2Fe18ea17a-6cd9-43ce-97f3-a680f4d45b3b-720-hls.torrent&xt=urn:btih:c14330f9b7fb491cca0e72dbc511bdfd31a8da83&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fstreaming-playlists%2Fhls%2F04af977f-4201-4697-be67-a8d8cae6fa7a%2Fc7cc2798-5f06-418d-bf70-e03976f99e3f-720-fragmented.mp4",
"height": 720,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/streaming-playlists/hls/04af977f-4201-4697-be67-a8d8cae6fa7a/861a614e-42cb-4fdf-adf3-ae0655401884-480-fragmented.mp4",
"height": 480,
"width": null,
"size": 485243564,
"fps": 24
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/5314512",
"height": 480,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/5f249584-ab89-4e95-863b-71ec060cceb3-480-hls.torrent",
"height": 480,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2F5f249584-ab89-4e95-863b-71ec060cceb3-480-hls.torrent&xt=urn:btih:1cd5a3ebd0b494f0e6ad7f12e84482db36b862c4&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fstreaming-playlists%2Fhls%2F04af977f-4201-4697-be67-a8d8cae6fa7a%2F861a614e-42cb-4fdf-adf3-ae0655401884-480-fragmented.mp4",
"height": 480,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/streaming-playlists/hls/04af977f-4201-4697-be67-a8d8cae6fa7a/fc0116a8-6406-423a-bb8b-14f12325c501-240-fragmented.mp4",
"height": 240,
"width": null,
"size": 247981291,
"fps": 24
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/5314511",
"height": 240,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/c0315cb6-75bc-49f7-bed1-b0f62faaa9fa-240-hls.torrent",
"height": 240,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2Fc0315cb6-75bc-49f7-bed1-b0f62faaa9fa-240-hls.torrent&xt=urn:btih:0c49d76ac9027b5a8497f7cab2931d9c140e5a79&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fstreaming-playlists%2Fhls%2F04af977f-4201-4697-be67-a8d8cae6fa7a%2Ffc0116a8-6406-423a-bb8b-14f12325c501-240-fragmented.mp4",
"height": 240,
"width": null,
"fps": 24
},
{
"type": "Link",
"mediaType": "video/mp4",
"href": "https://peertube2.cpy.re/static/streaming-playlists/hls/04af977f-4201-4697-be67-a8d8cae6fa7a/cc3c82be-16bf-47b9-b6af-28dca8bb8ff2-0-fragmented.mp4",
"height": 0,
"width": null,
"size": 104103486,
"fps": 0
},
{
"type": "Link",
"rel": [
"metadata",
"video/mp4"
],
"mediaType": "application/json",
"href": "https://peertube2.cpy.re/api/v1/videos/04af977f-4201-4697-be67-a8d8cae6fa7a/metadata/5314510",
"height": 0,
"width": null,
"fps": 0
},
{
"type": "Link",
"mediaType": "application/x-bittorrent",
"href": "https://peertube2.cpy.re/lazy-static/torrents/f79313be-0d3f-4538-ab19-b5ca67e34967-0-hls.torrent",
"height": 0,
"width": null,
"fps": 0
},
{
"type": "Link",
"mediaType": "application/x-bittorrent;x-scheme-handler/magnet",
"href": "magnet:?xs=https%3A%2F%2Fpeertube2.cpy.re%2Flazy-static%2Ftorrents%2Ff79313be-0d3f-4538-ab19-b5ca67e34967-0-hls.torrent&xt=urn:btih:4310a4e63a3a57bbc823a756a542f18a97131e50&dn=The+Internet's+Own+Boy&tr=https%3A%2F%2Fpeertube2.cpy.re%2Ftracker%2Fannounce&tr=wss%3A%2F%2Fpeertube2.cpy.re%3A443%2Ftracker%2Fsocket&ws=https%3A%2F%2Fpeertube2.cpy.re%2Fstatic%2Fstreaming-playlists%2Fhls%2F04af977f-4201-4697-be67-a8d8cae6fa7a%2Fcc3c82be-16bf-47b9-b6af-28dca8bb8ff2-0-fragmented.mp4",
"height": 0,
"width": null,
"fps": 0
}
]
},
{
"type": "Link",
"name": "tracker-http",
"rel": [
"tracker",
"http"
],
"href": "https://peertube2.cpy.re/tracker/announce"
},
{
"type": "Link",
"name": "tracker-websocket",
"rel": [
"tracker",
"websocket"
],
"href": "wss://peertube2.cpy.re:443/tracker/socket"
}
],
"likes": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/likes",
"dislikes": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/dislikes",
"shares": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/announces",
"comments": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/comments",
"hasParts": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/chapters",
"attributedTo": [
{
"type": "Person",
"id": "https://peertube2.cpy.re/accounts/root"
},
{
"type": "Group",
"id": "https://peertube2.cpy.re/video-channels/a75cbdf4-acf2-45c0-a491-e9b28939f8db"
}
],
"isLiveBroadcast": false,
"liveSaveReplay": null,
"permanentLive": null,
"latencyMode": null
}
Playlist
INFO
This object is not standard to the ActivityPub specification.
TypeScript model: packages/models/src/activitypub/objects/playlist-object.ts.
import { ActivityIconObject, ActivityPubAttributedTo } from './common-objects.js'
export interface PlaylistObject {
id: string
type: 'Playlist'
name: string
content: string
mediaType: 'text/markdown'
uuid: string
totalItems: number
attributedTo: ActivityPubAttributedTo[]
icon?: ActivityIconObject
published: string
updated: string
orderedItems?: string[]
partOf?: string
next?: string
first?: string
to?: string[]
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"Playlist": "pt:Playlist",
"PlaylistElement": "pt:PlaylistElement",
"position": {
"@type": "sc:Number",
"@id": "pt:position"
},
"startTimestamp": {
"@type": "sc:Number",
"@id": "pt:startTimestamp"
},
"stopTimestamp": {
"@type": "sc:Number",
"@id": "pt:stopTimestamp"
},
"uuid": {
"@type": "sc:identifier",
"@id": "pt:uuid"
}
}
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://peertube2.cpy.re/accounts/chocobozzz/followers"
],
"id": "https://peertube2.cpy.re/video-playlists/979ac324-4f2a-4554-a260-e0364e62d00f",
"type": "Playlist",
"totalItems": 3,
"first": "https://peertube2.cpy.re/video-playlists/979ac324-4f2a-4554-a260-e0364e62d00f?page=1",
"name": "Test",
"content": "Test playlist",
"mediaType": "text/markdown",
"uuid": "979ac324-4f2a-4554-a260-e0364e62d00f",
"published": "2020-08-20T08:49:01.196Z",
"updated": "2020-08-20T08:53:26.402Z",
"attributedTo": [
"https://peertube2.cpy.re/video-channels/chocobozzz_channel"
],
"icon": {
"type": "Image",
"url": "https://peertube2.cpy.re/lazy-static/thumbnails/playlist-979ac324-4f2a-4554-a260-e0364e62d00f.jpg",
"mediaType": "image/jpeg",
"width": 280,
"height": 157
}
}
CacheFile
INFO
This object is not standard to the ActivityPub specification.
The object is used to represent a cached file. It is usually sent by third-party servers to the origin server hosting a video file (a resolution from a Video
), to notify they have put up a copy of that file. The origin server then adds the server emitting the CacheFile
to the list of WebSeeds for that file so video players can download the video from multiple servers.
TypeScript model: packages/models/src/activitypub/objects/cache-file-object.ts.
import { ActivityVideoUrlObject, ActivityPlaylistUrlObject } from './common-objects.js'
export interface CacheFileObject {
id: string
type: 'CacheFile'
object: string
expires: string
url: ActivityVideoUrlObject | ActivityPlaylistUrlObject
}
Note
A Note
is a comment made to a video. Since most ActivityPub textual platforms use the Note
object for their messages, most of them can interact in the same way with PeerTube videos, making them able to comment PeerTube videos directly!
TypeScript model: packages/models/src/activitypub/objects/video-comment-object.ts.
import { ActivityPubAttributedTo, ActivityTagObject } from './common-objects.js'
export interface VideoCommentObject {
type: 'Note'
id: string
content: string
mediaType: 'text/markdown'
inReplyTo: string
published: string
updated: string
url: string
attributedTo: ActivityPubAttributedTo
tag: ActivityTagObject[]
replyApproval: string | null
to?: string[]
cc?: string[]
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"replyApproval": "pt:replyApproval"
}
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://peertube2.cpy.re/accounts/chocobozzz/followers"
],
"type": "Note",
"id": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/comments/177352",
"content": "Nice video!!!",
"mediaType": "text/markdown",
"inReplyTo": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a",
"updated": "2024-05-31T08:28:39.825Z",
"published": "2024-05-31T08:28:39.805Z",
"url": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/comments/177352",
"attributedTo": "https://peertube2.cpy.re/accounts/chocobozzz",
"replyApproval": "https://peertube2.cpy.re/videos/watch/04af977f-4201-4697-be67-a8d8cae6fa7a/comments/177352/approve-reply",
"tag": []
}
Playlist
INFO
This object is not standard to the ActivityPub specification.
The object is used to represent a video playlist. It extends OrderedCollectionPage and items are PlaylistElement.
TypeScript model: packages/models/src/activitypub/objects/playlist-object.ts.
import { ActivityIconObject, ActivityPubAttributedTo } from './common-objects.js'
export interface PlaylistObject {
id: string
type: 'Playlist'
name: string
content: string
mediaType: 'text/markdown'
uuid: string
totalItems: number
attributedTo: ActivityPubAttributedTo[]
icon?: ActivityIconObject
published: string
updated: string
orderedItems?: string[]
partOf?: string
next?: string
first?: string
to?: string[]
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"Playlist": "pt:Playlist",
"PlaylistElement": "pt:PlaylistElement",
"position": {
"@type": "sc:Number",
"@id": "pt:position"
},
"startTimestamp": {
"@type": "sc:Number",
"@id": "pt:startTimestamp"
},
"stopTimestamp": {
"@type": "sc:Number",
"@id": "pt:stopTimestamp"
},
"uuid": {
"@type": "sc:identifier",
"@id": "pt:uuid"
}
}
],
"to": [
"https://www.w3.org/ns/activitystreams#Public"
],
"cc": [
"https://peertube2.cpy.re/accounts/chocobozzz/followers"
],
"id": "https://peertube2.cpy.re/video-playlists/979ac324-4f2a-4554-a260-e0364e62d00f",
"type": "Playlist",
"totalItems": 3,
"first": "https://peertube2.cpy.re/video-playlists/979ac324-4f2a-4554-a260-e0364e62d00f?page=1",
"name": "Test",
"content": "Test playlist",
"mediaType": "text/markdown",
"uuid": "979ac324-4f2a-4554-a260-e0364e62d00f",
"published": "2020-08-20T08:49:01.196Z",
"updated": "2020-08-20T08:53:26.402Z",
"attributedTo": [
"https://peertube2.cpy.re/video-channels/chocobozzz_channel"
],
"icon": {
"type": "Image",
"url": "https://peertube2.cpy.re/lazy-static/thumbnails/playlist-979ac324-4f2a-4554-a260-e0364e62d00f.jpg",
"mediaType": "image/jpeg",
"width": 280,
"height": 157
}
}
PlaylistElement
INFO
This object is not standard to the ActivityPub specification.
The object is used to represent a video playlist element inside the Playlist
object.
TypeScript model: packages/models/src/activitypub/objects/playlist-element-object.ts.
export interface PlaylistElementObject {
id: string
type: 'PlaylistElement'
url: string
position: number
startTimestamp?: number
stopTimestamp?: number
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"Playlist": "pt:Playlist",
"PlaylistElement": "pt:PlaylistElement",
"position": {
"@type": "sc:Number",
"@id": "pt:position"
},
"startTimestamp": {
"@type": "sc:Number",
"@id": "pt:startTimestamp"
},
"stopTimestamp": {
"@type": "sc:Number",
"@id": "pt:stopTimestamp"
},
"uuid": {
"@type": "sc:identifier",
"@id": "pt:uuid"
}
}
],
"id": "https://peertube2.cpy.re/video-playlists/979ac324-4f2a-4554-a260-e0364e62d00f/videos/398616",
"type": "PlaylistElement",
"url": "https://peertube2.cpy.re/videos/watch/923a178d-d63a-41d4-8dd7-76b31625629a",
"position": 1
}
Actor
An PeerTube Actor
can be:
- The instance (
Application
), used to follow otherActor
or share anonymous activities likeView
orWatchAction
- An account (
Person
), used to publish or comment videos, report abuses or create video channels - A video channel (
Group
), owned by an account and also used to publish videos. The channel is aGroup
because we plan to have multiple accounts that can manage the same channel in the future
When a video is published, the account sends a Create
activity and the channel sends an Announce
activity, both referencing the Video
object.
A Video
object has the attributedTo
property to know the Person
and the Group
that own it.
import { ActivityIconObject, ActivityPubAttributedTo } from './objects/common-objects.js'
export type ActivityPubActorType = 'Person' | 'Application' | 'Group' | 'Service' | 'Organization'
export interface ActivityPubActor {
'@context': any[]
type: ActivityPubActorType
id: string
following: string
followers: string
playlists?: string
inbox: string
outbox: string
preferredUsername: string
url: string
name: string
endpoints: {
sharedInbox: string
}
summary: string
attributedTo?: ActivityPubAttributedTo[]
support?: string
publicKey: {
id: string
owner: string
publicKeyPem: string
}
// Lemmy attribute for groups
postingRestrictedToMods?: boolean
image?: ActivityIconObject | ActivityIconObject[]
icon?: ActivityIconObject | ActivityIconObject[]
published?: string
// For export
likes?: string
dislikes?: string
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"playlists": {
"@id": "pt:playlists",
"@type": "@id"
},
"support": {
"@type": "sc:Text",
"@id": "pt:support"
},
"lemmy": "https://join-lemmy.org/ns#",
"postingRestrictedToMods": "lemmy:postingRestrictedToMods",
"icons": "as:icon"
}
],
"type": "Application",
"id": "https://peertube2.cpy.re/accounts/peertube",
"following": "https://peertube2.cpy.re/accounts/peertube/following",
"followers": "https://peertube2.cpy.re/accounts/peertube/followers",
"playlists": "https://peertube2.cpy.re/accounts/peertube/playlists",
"inbox": "https://peertube2.cpy.re/accounts/peertube/inbox",
"outbox": "https://peertube2.cpy.re/accounts/peertube/outbox",
"preferredUsername": "peertube",
"url": "https://peertube2.cpy.re/accounts/peertube",
"name": "peertube",
"endpoints": {
"sharedInbox": "https://peertube2.cpy.re/inbox"
},
"publicKey": {
"id": "https://peertube2.cpy.re/accounts/peertube#main-key",
"owner": "https://peertube2.cpy.re/accounts/peertube",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq2szShm/NJow/5pQ2KOU\n73UIYl7Hvy55hBLTlsGPK4jmcYbg5CnjUYmj51jsEunX/grstDzySY3UkZXYm+Ov\n6FVz1A++CQYlMkhWP5tu3PU62zxNKkZHpTHTa28DEJMbcLdwrTAYSHHEN3Th9vp4\n9noMdrNjeF4qmiFd493I5PC7S0zGyrSmSGAjV+AwRNPikBC52KpNfYbsryWnlvgl\nUWUibQVTc8NAbY4WE/d0sTZWLmM3Yk7UtJtQXjjsVXC9xMJfiNvnaInoY88BUri6\n4wvvAwhI0ddvvq4/wQLqY0aztQ8+lfV1bSWw4sqkwY+cY2f4QXGRx6kIwr+oypNi\nuQIDAQAB\n-----END PUBLIC KEY-----"
},
"published": "2017-11-28T08:30:56.514Z",
"icon": [
{
"type": "Image",
"mediaType": "image/png",
"height": 48,
"width": 48,
"url": "https://peertube2.cpy.re/lazy-static/avatars/abace30f-69ad-4ff2-a954-dea06c5db6eb.png"
},
{
"type": "Image",
"mediaType": "image/png",
"height": 120,
"width": 120,
"url": "https://peertube2.cpy.re/lazy-static/avatars/1163da44-0367-4df9-bf10-a1b0dc0e3fb9.png"
},
{
"type": "Image",
"mediaType": "image/png",
"height": 600,
"width": 600,
"url": "https://peertube2.cpy.re/lazy-static/avatars/177f70c4-ddef-4bb6-bc96-b00d5e2a0e05.png"
},
{
"type": "Image",
"mediaType": "image/png",
"height": 1500,
"width": 1500,
"url": "https://peertube2.cpy.re/lazy-static/avatars/82936e50-9560-42e7-9e4b-d96309f5c9c9.png"
}
],
"summary": null
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"playlists": {
"@id": "pt:playlists",
"@type": "@id"
},
"support": {
"@type": "sc:Text",
"@id": "pt:support"
},
"lemmy": "https://join-lemmy.org/ns#",
"postingRestrictedToMods": "lemmy:postingRestrictedToMods",
"icons": "as:icon"
}
],
"type": "Person",
"id": "https://peertube2.cpy.re/accounts/chocobozzz",
"following": "https://peertube2.cpy.re/accounts/chocobozzz/following",
"followers": "https://peertube2.cpy.re/accounts/chocobozzz/followers",
"playlists": "https://peertube2.cpy.re/accounts/chocobozzz/playlists",
"inbox": "https://peertube2.cpy.re/accounts/chocobozzz/inbox",
"outbox": "https://peertube2.cpy.re/accounts/chocobozzz/outbox",
"preferredUsername": "chocobozzz",
"url": "https://peertube2.cpy.re/accounts/chocobozzz",
"name": "chocobozzz",
"endpoints": {
"sharedInbox": "https://peertube2.cpy.re/inbox"
},
"publicKey": {
"id": "https://peertube2.cpy.re/accounts/chocobozzz#main-key",
"owner": "https://peertube2.cpy.re/accounts/chocobozzz",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy9i2I+4Bf3p+l8hELlqG\n4mtYC6tjFp5S6lNtM/9mgJTXHe35GI38gXY3uGKm0eF0DZFZZCWr5kKrz4U0hzEV\now6n0q4MIspq7FV8dOH8+e37W3d9+PJpkOarJry7/Kxvjir6U/uHUucIkTKFuPU5\nzbzImwxN5gg8T3ApjGhn3OQMBxdHR0zufqkakKiDK15KULVrONB/T/BmBafjD7C6\njB//dWtpKQPGUWGtLd5JkxBLwb1gTIfQe13pbhy85jMpjTQQ0+tMULldN3a7xbpB\n4m4MViqZXBzT1mrK66lKMxLRgluMPJUWgkkfzPXrtMhSlrwgG+v7FArTq+ci8wog\ntwIDAQAB\n-----END PUBLIC KEY-----"
},
"published": "2019-03-29T15:49:24.036Z",
"icon": [
{
"type": "Image",
"mediaType": "image/png",
"height": 48,
"width": 48,
"url": "https://peertube2.cpy.re/lazy-static/avatars/b24bc0df-e472-4e60-8c2f-9ccada1599af.png"
},
{
"type": "Image",
"mediaType": "image/png",
"height": 120,
"width": 120,
"url": "https://peertube2.cpy.re/lazy-static/avatars/69e95cbe-9293-4859-a996-a24a4ab7befb.png"
}
],
"summary": null
}
{
"@context": [
"https://www.w3.org/ns/activitystreams",
"https://w3id.org/security/v1",
{
"RsaSignature2017": "https://w3id.org/security#RsaSignature2017"
},
{
"pt": "https://joinpeertube.org/ns#",
"sc": "http://schema.org/",
"playlists": {
"@id": "pt:playlists",
"@type": "@id"
},
"support": {
"@type": "sc:Text",
"@id": "pt:support"
},
"lemmy": "https://join-lemmy.org/ns#",
"postingRestrictedToMods": "lemmy:postingRestrictedToMods",
"icons": "as:icon"
}
],
"type": "Group",
"id": "https://peertube2.cpy.re/video-channels/chocobozzz_channel",
"following": "https://peertube2.cpy.re/video-channels/chocobozzz_channel/following",
"followers": "https://peertube2.cpy.re/video-channels/chocobozzz_channel/followers",
"playlists": "https://peertube2.cpy.re/video-channels/chocobozzz_channel/playlists",
"inbox": "https://peertube2.cpy.re/video-channels/chocobozzz_channel/inbox",
"outbox": "https://peertube2.cpy.re/video-channels/chocobozzz_channel/outbox",
"preferredUsername": "chocobozzz_channel",
"url": "https://peertube2.cpy.re/video-channels/chocobozzz_channel",
"name": "Main chocobozzz channel",
"endpoints": {
"sharedInbox": "https://peertube2.cpy.re/inbox"
},
"publicKey": {
"id": "https://peertube2.cpy.re/video-channels/chocobozzz_channel#main-key",
"owner": "https://peertube2.cpy.re/video-channels/chocobozzz_channel",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1Wq/69fJRaBK4RQE88Kc\nv1yyGtgphMNdw4cqGSN1dDyes4eCH2EHPKdMav61eP3bc2AjBnpwJXf07UKL/+N+\nFZO3NVTChwm9H1wvYVuXUeOQOMDRevvabrRL7OkmaRKJ1t1INFwe8fMnMgXKpaM7\n92OkFc+nUbkPdbR4HkjEZgVFDIXItoTiIKY/7cez4QxTv4wVOTBaZkJFLfYolryV\nbGvuwtzoVw83/P65Ig3f/BnFnXKmvx55VaE+7EDlIVWERRnahWI+MI/hLb5OkQAc\nU0z8YuJvz+NqLecuFNOIHOW1u++yGm9doDOEhNTuF6N1pjTunCjvkfTtRaY+qlpL\nNwIDAQAB\n-----END PUBLIC KEY-----"
},
"published": "2019-03-29T15:49:24.067Z",
"icon": [
{
"type": "Image",
"mediaType": "image/jpeg",
"height": 48,
"width": 48,
"url": "https://peertube2.cpy.re/lazy-static/avatars/5b9bf735-d9a7-4967-836d-161496fcb0b3.jpg"
},
{
"type": "Image",
"mediaType": "image/jpeg",
"height": 120,
"width": 120,
"url": "https://peertube2.cpy.re/lazy-static/avatars/14ee9081-9d4c-444e-af97-9cfb69fef83d.jpg"
}
],
"image": [
{
"type": "Image",
"mediaType": "image/jpeg",
"height": 317,
"width": 1920,
"url": "https://peertube2.cpy.re/lazy-static/banners/49081f1e-f9c3-403a-b657-dff113b023b4.jpg"
}
],
"summary": null,
"support": null,
"postingRestrictedToMods": true,
"attributedTo": [
{
"type": "Person",
"id": "https://peertube2.cpy.re/accounts/chocobozzz"
}
]
}
WatchAction
INFO
This object is not standard to the ActivityPub specification. It comes from Schema.org
The object is used to represent a viewer that watched a video. Allows origin server to aggregate viewer statistics.
TypeScript model: packages/models/src/activitypub/objects/watch-action-object.ts.
export interface WatchActionObject {
id: string
type: 'WatchAction'
startTime: string
endTime: string
location?: {
addressCountry: string
addressRegion: string
}
uuid: string
object: string
actionStatus: 'CompletedActionStatus'
duration: string
watchSections: {
startTimestamp: number
endTimestamp: number
}[]
}