PeerTube/server/lib/activitypub/process/misc.ts

160 lines
5.0 KiB
TypeScript

import * as magnetUtil from 'magnet-uri'
import { VideoTorrentObject } from '../../../../shared'
import { VideoChannelObject } from '../../../../shared/models/activitypub/objects/video-channel-object'
import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
import { isVideoFileInfoHashValid } from '../../../helpers/custom-validators/videos'
import { doRequest } from '../../../helpers/requests'
import { database as db } from '../../../initializers'
import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../../initializers/constants'
import { AccountInstance } from '../../../models/account/account-interface'
import { VideoChannelInstance } from '../../../models/video/video-channel-interface'
import { VideoFileAttributes } from '../../../models/video/video-file-interface'
import { VideoAttributes, VideoInstance } from '../../../models/video/video-interface'
import { getOrCreateAccountAndServer } from '../account'
function videoChannelActivityObjectToDBAttributes (videoChannelObject: VideoChannelObject, account: AccountInstance) {
return {
name: videoChannelObject.name,
description: videoChannelObject.content,
uuid: videoChannelObject.uuid,
url: videoChannelObject.id,
createdAt: new Date(videoChannelObject.published),
updatedAt: new Date(videoChannelObject.updated),
remote: true,
accountId: account.id
}
}
async function videoActivityObjectToDBAttributes (
videoChannel: VideoChannelInstance,
videoObject: VideoTorrentObject,
to: string[] = [],
cc: string[] = []
) {
let privacy = VideoPrivacy.PRIVATE
if (to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.PUBLIC
else if (cc.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.UNLISTED
const duration = videoObject.duration.replace(/[^\d]+/, '')
let language = null
if (videoObject.language) {
language = parseInt(videoObject.language.identifier, 10)
}
const videoData: VideoAttributes = {
name: videoObject.name,
uuid: videoObject.uuid,
url: videoObject.id,
category: parseInt(videoObject.category.identifier, 10),
licence: parseInt(videoObject.licence.identifier, 10),
language,
nsfw: videoObject.nsfw,
description: videoObject.content,
channelId: videoChannel.id,
duration: parseInt(duration, 10),
createdAt: new Date(videoObject.published),
// FIXME: updatedAt does not seems to be considered by Sequelize
updatedAt: new Date(videoObject.updated),
views: videoObject.views,
likes: 0,
dislikes: 0,
remote: true,
privacy
}
return videoData
}
function videoFileActivityUrlToDBAttributes (videoCreated: VideoInstance, videoObject: VideoTorrentObject) {
const mimeTypes = Object.keys(VIDEO_MIMETYPE_EXT)
const fileUrls = videoObject.url.filter(u => {
return mimeTypes.indexOf(u.mimeType) !== -1 && u.mimeType.startsWith('video/')
})
if (fileUrls.length === 0) {
throw new Error('Cannot find video files for ' + videoCreated.url)
}
const attributes: VideoFileAttributes[] = []
for (const fileUrl of fileUrls) {
// Fetch associated magnet uri
const magnet = videoObject.url.find(u => {
return u.mimeType === 'application/x-bittorrent;x-scheme-handler/magnet' && u.width === fileUrl.width
})
if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.url)
const parsed = magnetUtil.decode(magnet.url)
if (!parsed || isVideoFileInfoHashValid(parsed.infoHash) === false) throw new Error('Cannot parse magnet URI ' + magnet.url)
const attribute = {
extname: VIDEO_MIMETYPE_EXT[fileUrl.mimeType],
infoHash: parsed.infoHash,
resolution: fileUrl.width,
size: fileUrl.size,
videoId: videoCreated.id
}
attributes.push(attribute)
}
return attributes
}
async function addVideoShares (instance: VideoInstance, shares: string[]) {
for (const share of shares) {
// Fetch url
const json = await doRequest({
uri: share,
json: true
})
const actor = json['actor']
if (!actor) continue
const account = await getOrCreateAccountAndServer(actor)
const entry = {
accountId: account.id,
videoId: instance.id
}
await db.VideoShare.findOrCreate({
where: entry,
defaults: entry
})
}
}
async function addVideoChannelShares (instance: VideoChannelInstance, shares: string[]) {
for (const share of shares) {
// Fetch url
const json = await doRequest({
uri: share,
json: true
})
const actor = json['actor']
if (!actor) continue
const account = await getOrCreateAccountAndServer(actor)
const entry = {
accountId: account.id,
videoChannelId: instance.id
}
await db.VideoChannelShare.findOrCreate({
where: entry,
defaults: entry
})
}
}
// ---------------------------------------------------------------------------
export {
videoFileActivityUrlToDBAttributes,
videoActivityObjectToDBAttributes,
videoChannelActivityObjectToDBAttributes,
addVideoChannelShares,
addVideoShares
}