123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import * as Bluebird from 'bluebird'
- import validator from 'validator'
- import { ResultList } from '../../shared/models'
- import { Activity } from '../../shared/models/activitypub'
- import { ACTIVITY_PUB, REMOTE_SCHEME } from '../initializers/constants'
- import { signJsonLDObject } from './peertube-crypto'
- import { pageToStartAndCount } from './core-utils'
- import { URL } from 'url'
- import { MActor, MVideoAccountLight } from '../types/models'
- import { ContextType } from '@shared/models/activitypub/context'
- function getContextData (type: ContextType) {
- const context: any[] = [
- 'https://www.w3.org/ns/activitystreams',
- 'https://w3id.org/security/v1',
- {
- RsaSignature2017: 'https://w3id.org/security#RsaSignature2017'
- }
- ]
- if (type !== 'View' && type !== 'Announce') {
- const additional = {
- pt: 'https://joinpeertube.org/ns#',
- sc: 'http://schema.org#'
- }
- if (type === 'CacheFile') {
- Object.assign(additional, {
- expires: 'sc:expires',
- CacheFile: 'pt:CacheFile'
- })
- } else {
- Object.assign(additional, {
- Hashtag: 'as:Hashtag',
- uuid: 'sc:identifier',
- category: 'sc:category',
- licence: 'sc:license',
- subtitleLanguage: 'sc:subtitleLanguage',
- sensitive: 'as:sensitive',
- language: 'sc:inLanguage',
- isLiveBroadcast: 'sc:isLiveBroadcast',
- liveSaveReplay: {
- '@type': 'sc:Boolean',
- '@id': 'pt:liveSaveReplay'
- },
- permanentLive: {
- '@type': 'sc:Boolean',
- '@id': 'pt:permanentLive'
- },
- Infohash: 'pt:Infohash',
- Playlist: 'pt:Playlist',
- PlaylistElement: 'pt:PlaylistElement',
- originallyPublishedAt: 'sc:datePublished',
- 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'
- },
- startTimestamp: {
- '@type': 'sc:Number',
- '@id': 'pt:startTimestamp'
- },
- stopTimestamp: {
- '@type': 'sc:Number',
- '@id': 'pt:stopTimestamp'
- },
- position: {
- '@type': 'sc:Number',
- '@id': 'pt:position'
- },
- commentsEnabled: {
- '@type': 'sc:Boolean',
- '@id': 'pt:commentsEnabled'
- },
- 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'
- },
- playlists: {
- '@id': 'pt:playlists',
- '@type': '@id'
- },
- shares: {
- '@id': 'as:shares',
- '@type': '@id'
- },
- comments: {
- '@id': 'as:comments',
- '@type': '@id'
- }
- })
- }
- context.push(additional)
- }
- return {
- '@context': context
- }
- }
- function activityPubContextify <T> (data: T, type: ContextType = 'All') {
- return Object.assign({}, data, getContextData(type))
- }
- type ActivityPubCollectionPaginationHandler = (start: number, count: number) => Bluebird<ResultList<any>> | Promise<ResultList<any>>
- async function activityPubCollectionPagination (
- baseUrl: string,
- handler: ActivityPubCollectionPaginationHandler,
- page?: any,
- size = ACTIVITY_PUB.COLLECTION_ITEMS_PER_PAGE
- ) {
- if (!page || !validator.isInt(page)) {
- // We just display the first page URL, we only need the total items
- const result = await handler(0, 1)
- return {
- id: baseUrl,
- type: 'OrderedCollectionPage',
- totalItems: result.total,
- first: baseUrl + '?page=1'
- }
- }
- const { start, count } = pageToStartAndCount(page, size)
- const result = await handler(start, count)
- let next: string | undefined
- let prev: string | undefined
- // Assert page is a number
- page = parseInt(page, 10)
- // There are more results
- if (result.total > page * size) {
- next = baseUrl + '?page=' + (page + 1)
- }
- if (page > 1) {
- prev = baseUrl + '?page=' + (page - 1)
- }
- return {
- id: baseUrl + '?page=' + page,
- type: 'OrderedCollectionPage',
- prev,
- next,
- partOf: baseUrl,
- orderedItems: result.data,
- totalItems: result.total
- }
- }
- function buildSignedActivity (byActor: MActor, data: Object, contextType?: ContextType) {
- const activity = activityPubContextify(data, contextType)
- return signJsonLDObject(byActor, activity) as Promise<Activity>
- }
- function getAPId (activity: string | { id: string }) {
- if (typeof activity === 'string') return activity
- return activity.id
- }
- function checkUrlsSameHost (url1: string, url2: string) {
- const idHost = new URL(url1).host
- const actorHost = new URL(url2).host
- return idHost && actorHost && idHost.toLowerCase() === actorHost.toLowerCase()
- }
- function buildRemoteVideoBaseUrl (video: MVideoAccountLight, path: string) {
- const host = video.VideoChannel.Account.Actor.Server.host
- return REMOTE_SCHEME.HTTP + '://' + host + path
- }
- // ---------------------------------------------------------------------------
- export {
- checkUrlsSameHost,
- getAPId,
- activityPubContextify,
- activityPubCollectionPagination,
- buildSignedActivity,
- buildRemoteVideoBaseUrl
- }
|