Begin moving video channel to actor
[oweals/peertube.git] / server / lib / activitypub / process / misc.ts
1 import * as magnetUtil from 'magnet-uri'
2 import { VideoTorrentObject } from '../../../../shared'
3 import { VideoPrivacy } from '../../../../shared/models/videos'
4 import { doRequest } from '../../../helpers'
5 import { isVideoFileInfoHashValid } from '../../../helpers/custom-validators/videos'
6 import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../../initializers'
7 import { VideoModel } from '../../../models/video/video'
8 import { VideoChannelModel } from '../../../models/video/video-channel'
9 import { VideoShareModel } from '../../../models/video/video-share'
10 import { getOrCreateActorAndServerAndModel } from '../actor'
11
12 async function videoActivityObjectToDBAttributes (
13   videoChannel: VideoChannelModel,
14   videoObject: VideoTorrentObject,
15   to: string[] = [],
16   cc: string[] = []
17 ) {
18   let privacy = VideoPrivacy.PRIVATE
19   if (to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.PUBLIC
20   else if (cc.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.UNLISTED
21
22   const duration = videoObject.duration.replace(/[^\d]+/, '')
23   let language = null
24   if (videoObject.language) {
25     language = parseInt(videoObject.language.identifier, 10)
26   }
27
28   let category = null
29   if (videoObject.category) {
30     category = parseInt(videoObject.category.identifier, 10)
31   }
32
33   let licence = null
34   if (videoObject.licence) {
35     licence = parseInt(videoObject.licence.identifier, 10)
36   }
37
38   let description = null
39   if (videoObject.content) {
40     description = videoObject.content
41   }
42
43   return {
44     name: videoObject.name,
45     uuid: videoObject.uuid,
46     url: videoObject.id,
47     category,
48     licence,
49     language,
50     description,
51     nsfw: videoObject.nsfw,
52     channelId: videoChannel.id,
53     duration: parseInt(duration, 10),
54     createdAt: new Date(videoObject.published),
55     // FIXME: updatedAt does not seems to be considered by Sequelize
56     updatedAt: new Date(videoObject.updated),
57     views: videoObject.views,
58     likes: 0,
59     dislikes: 0,
60     remote: true,
61     privacy
62   }
63 }
64
65 function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObject: VideoTorrentObject) {
66   const mimeTypes = Object.keys(VIDEO_MIMETYPE_EXT)
67   const fileUrls = videoObject.url.filter(u => {
68     return mimeTypes.indexOf(u.mimeType) !== -1 && u.mimeType.startsWith('video/')
69   })
70
71   if (fileUrls.length === 0) {
72     throw new Error('Cannot find video files for ' + videoCreated.url)
73   }
74
75   const attributes = []
76   for (const fileUrl of fileUrls) {
77     // Fetch associated magnet uri
78     const magnet = videoObject.url.find(u => {
79       return u.mimeType === 'application/x-bittorrent;x-scheme-handler/magnet' && u.width === fileUrl.width
80     })
81
82     if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.url)
83
84     const parsed = magnetUtil.decode(magnet.url)
85     if (!parsed || isVideoFileInfoHashValid(parsed.infoHash) === false) throw new Error('Cannot parse magnet URI ' + magnet.url)
86
87     const attribute = {
88       extname: VIDEO_MIMETYPE_EXT[fileUrl.mimeType],
89       infoHash: parsed.infoHash,
90       resolution: fileUrl.width,
91       size: fileUrl.size,
92       videoId: videoCreated.id
93     }
94     attributes.push(attribute)
95   }
96
97   return attributes
98 }
99
100 async function addVideoShares (instance: VideoModel, shares: string[]) {
101   for (const share of shares) {
102     // Fetch url
103     const json = await doRequest({
104       uri: share,
105       json: true
106     })
107     const actorUrl = json['actor']
108     if (!actorUrl) continue
109
110     const actor = await getOrCreateActorAndServerAndModel(actorUrl)
111
112     const entry = {
113       actorId: actor.id,
114       videoId: instance.id
115     }
116
117     await VideoShareModel.findOrCreate({
118       where: entry,
119       defaults: entry
120     })
121   }
122 }
123
124 // ---------------------------------------------------------------------------
125
126 export {
127   videoFileActivityUrlToDBAttributes,
128   videoActivityObjectToDBAttributes,
129   addVideoShares
130 }