]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blame - server/lib/activitypub/process/misc.ts
Fix lint
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / process / misc.ts
CommitLineData
0d0e8dd0 1import * as magnetUtil from 'magnet-uri'
54141398 2import { VideoTorrentObject } from '../../../../shared'
da854ddd 3import { VideoCommentObject } from '../../../../shared/models/activitypub/objects/video-comment-object'
3fd3ab2d 4import { VideoPrivacy } from '../../../../shared/models/videos'
54141398 5import { isVideoFileInfoHashValid } from '../../../helpers/custom-validators/videos'
da854ddd
C
6import { logger } from '../../../helpers/logger'
7import { doRequest } from '../../../helpers/requests'
3fd3ab2d 8import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../../initializers'
da854ddd 9import { ActorModel } from '../../../models/activitypub/actor'
3fd3ab2d
C
10import { VideoModel } from '../../../models/video/video'
11import { VideoChannelModel } from '../../../models/video/video-channel'
da854ddd 12import { VideoCommentModel } from '../../../models/video/video-comment'
3fd3ab2d 13import { VideoShareModel } from '../../../models/video/video-share'
50d6de9c 14import { getOrCreateActorAndServerAndModel } from '../actor'
0d0e8dd0 15
571389d4 16async function videoActivityObjectToDBAttributes (
3fd3ab2d 17 videoChannel: VideoChannelModel,
9a27cdc2
C
18 videoObject: VideoTorrentObject,
19 to: string[] = [],
20 cc: string[] = []
571389d4 21) {
9a27cdc2
C
22 let privacy = VideoPrivacy.PRIVATE
23 if (to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.PUBLIC
24 else if (cc.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.UNLISTED
25
0d0e8dd0 26 const duration = videoObject.duration.replace(/[^\d]+/, '')
40ff5707
C
27 let language = null
28 if (videoObject.language) {
29 language = parseInt(videoObject.language.identifier, 10)
30 }
31
f595d394
C
32 let category = null
33 if (videoObject.category) {
34 category = parseInt(videoObject.category.identifier, 10)
35 }
36
37 let licence = null
38 if (videoObject.licence) {
39 licence = parseInt(videoObject.licence.identifier, 10)
40 }
41
42 let description = null
43 if (videoObject.content) {
44 description = videoObject.content
45 }
46
3fd3ab2d 47 return {
0d0e8dd0
C
48 name: videoObject.name,
49 uuid: videoObject.uuid,
50 url: videoObject.id,
f595d394
C
51 category,
52 licence,
40ff5707 53 language,
f595d394 54 description,
0d0e8dd0 55 nsfw: videoObject.nsfw,
47564bbe 56 commentsEnabled: videoObject.commentsEnabled,
0d0e8dd0
C
57 channelId: videoChannel.id,
58 duration: parseInt(duration, 10),
efc32059 59 createdAt: new Date(videoObject.published),
0d0e8dd0 60 // FIXME: updatedAt does not seems to be considered by Sequelize
efc32059 61 updatedAt: new Date(videoObject.updated),
0d0e8dd0
C
62 views: videoObject.views,
63 likes: 0,
64 dislikes: 0,
0d0e8dd0 65 remote: true,
9a27cdc2 66 privacy
0d0e8dd0 67 }
0d0e8dd0
C
68}
69
3fd3ab2d 70function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObject: VideoTorrentObject) {
20494f12
C
71 const mimeTypes = Object.keys(VIDEO_MIMETYPE_EXT)
72 const fileUrls = videoObject.url.filter(u => {
73 return mimeTypes.indexOf(u.mimeType) !== -1 && u.mimeType.startsWith('video/')
74 })
75
76 if (fileUrls.length === 0) {
77 throw new Error('Cannot find video files for ' + videoCreated.url)
78 }
0d0e8dd0 79
3fd3ab2d 80 const attributes = []
20494f12 81 for (const fileUrl of fileUrls) {
0d0e8dd0 82 // Fetch associated magnet uri
20494f12
C
83 const magnet = videoObject.url.find(u => {
84 return u.mimeType === 'application/x-bittorrent;x-scheme-handler/magnet' && u.width === fileUrl.width
85 })
86
87 if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.url)
0d0e8dd0
C
88
89 const parsed = magnetUtil.decode(magnet.url)
90 if (!parsed || isVideoFileInfoHashValid(parsed.infoHash) === false) throw new Error('Cannot parse magnet URI ' + magnet.url)
91
92 const attribute = {
20494f12 93 extname: VIDEO_MIMETYPE_EXT[fileUrl.mimeType],
0d0e8dd0 94 infoHash: parsed.infoHash,
20494f12
C
95 resolution: fileUrl.width,
96 size: fileUrl.size,
0d0e8dd0
C
97 videoId: videoCreated.id
98 }
99 attributes.push(attribute)
100 }
101
102 return attributes
103}
104
da854ddd
C
105async function videoCommentActivityObjectToDBAttributes (video: VideoModel, actor: ActorModel, comment: VideoCommentObject) {
106 let originCommentId: number = null
107 let inReplyToCommentId: number = null
108
109 // If this is not a reply to the video (thread), create or get the parent comment
110 if (video.url !== comment.inReplyTo) {
111 const [ parent ] = await addVideoComment(video, comment.inReplyTo)
112 if (!parent) {
113 logger.warn('Cannot fetch or get parent comment %s of comment %s.', comment.inReplyTo, comment.id)
114 return undefined
115 }
116
117 originCommentId = parent.originCommentId || parent.id
118 inReplyToCommentId = parent.id
119 }
120
121 return {
122 url: comment.url,
123 text: comment.content,
124 videoId: video.id,
125 accountId: actor.Account.id,
126 inReplyToCommentId,
127 originCommentId,
128 createdAt: new Date(comment.published),
129 updatedAt: new Date(comment.updated)
130 }
131}
132
133async function addVideoShares (instance: VideoModel, shareUrls: string[]) {
134 for (const shareUrl of shareUrls) {
4e50b6a1 135 // Fetch url
da854ddd
C
136 const { body } = await doRequest({
137 uri: shareUrl,
138 json: true,
139 activityPub: true
4e50b6a1 140 })
da854ddd 141 const actorUrl = body.actor
50d6de9c 142 if (!actorUrl) continue
4e50b6a1 143
50d6de9c 144 const actor = await getOrCreateActorAndServerAndModel(actorUrl)
4e50b6a1
C
145
146 const entry = {
50d6de9c 147 actorId: actor.id,
4e50b6a1
C
148 videoId: instance.id
149 }
150
3fd3ab2d 151 await VideoShareModel.findOrCreate({
4e50b6a1
C
152 where: entry,
153 defaults: entry
154 })
155 }
156}
157
da854ddd
C
158async function addVideoComments (instance: VideoModel, commentUrls: string[]) {
159 for (const commentUrl of commentUrls) {
160 await addVideoComment(instance, commentUrl)
161 }
162}
163
164async function addVideoComment (instance: VideoModel, commentUrl: string) {
165 // Fetch url
166 const { body } = await doRequest({
167 uri: commentUrl,
168 json: true,
169 activityPub: true
170 })
171
172 const actorUrl = body.attributedTo
173 if (!actorUrl) return []
174
175 const actor = await getOrCreateActorAndServerAndModel(actorUrl)
176 const entry = await videoCommentActivityObjectToDBAttributes(instance, actor, body)
177 if (!entry) return []
178
179 return VideoCommentModel.findOrCreate({
180 where: {
181 url: body.id
182 },
183 defaults: entry
184 })
185}
186
0d0e8dd0
C
187// ---------------------------------------------------------------------------
188
189export {
190 videoFileActivityUrlToDBAttributes,
20494f12 191 videoActivityObjectToDBAttributes,
da854ddd
C
192 addVideoShares,
193 addVideoComments
0d0e8dd0 194}