]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - server/lib/activitypub/process/misc.ts
Finish admin design
[github/Chocobozzz/PeerTube.git] / server / lib / activitypub / process / misc.ts
1 import * as magnetUtil from 'magnet-uri'
2 import { VideoTorrentObject } from '../../../../shared'
3 import { VideoChannelObject } from '../../../../shared/models/activitypub/objects/video-channel-object'
4 import { VideoPrivacy } from '../../../../shared/models/videos/video-privacy.enum'
5 import { isVideoFileInfoHashValid } from '../../../helpers/custom-validators/videos'
6 import { doRequest } from '../../../helpers/requests'
7 import { database as db } from '../../../initializers'
8 import { ACTIVITY_PUB, VIDEO_MIMETYPE_EXT } from '../../../initializers/constants'
9 import { AccountInstance } from '../../../models/account/account-interface'
10 import { VideoChannelInstance } from '../../../models/video/video-channel-interface'
11 import { VideoFileAttributes } from '../../../models/video/video-file-interface'
12 import { VideoAttributes, VideoInstance } from '../../../models/video/video-interface'
13 import { getOrCreateAccountAndServer } from '../account'
14
15 function videoChannelActivityObjectToDBAttributes (videoChannelObject: VideoChannelObject, account: AccountInstance) {
16 return {
17 name: videoChannelObject.name,
18 description: videoChannelObject.content,
19 uuid: videoChannelObject.uuid,
20 url: videoChannelObject.id,
21 createdAt: new Date(videoChannelObject.published),
22 updatedAt: new Date(videoChannelObject.updated),
23 remote: true,
24 accountId: account.id
25 }
26 }
27
28 async function videoActivityObjectToDBAttributes (
29 videoChannel: VideoChannelInstance,
30 videoObject: VideoTorrentObject,
31 to: string[] = [],
32 cc: string[] = []
33 ) {
34 let privacy = VideoPrivacy.PRIVATE
35 if (to.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.PUBLIC
36 else if (cc.indexOf(ACTIVITY_PUB.PUBLIC) !== -1) privacy = VideoPrivacy.UNLISTED
37
38 const duration = videoObject.duration.replace(/[^\d]+/, '')
39 let language = null
40 if (videoObject.language) {
41 language = parseInt(videoObject.language.identifier, 10)
42 }
43
44 let category = null
45 if (videoObject.category) {
46 category = parseInt(videoObject.category.identifier, 10)
47 }
48
49 let licence = null
50 if (videoObject.licence) {
51 licence = parseInt(videoObject.licence.identifier, 10)
52 }
53
54 let description = null
55 if (videoObject.content) {
56 description = videoObject.content
57 }
58
59 const videoData: VideoAttributes = {
60 name: videoObject.name,
61 uuid: videoObject.uuid,
62 url: videoObject.id,
63 category,
64 licence,
65 language,
66 description,
67 nsfw: videoObject.nsfw,
68 channelId: videoChannel.id,
69 duration: parseInt(duration, 10),
70 createdAt: new Date(videoObject.published),
71 // FIXME: updatedAt does not seems to be considered by Sequelize
72 updatedAt: new Date(videoObject.updated),
73 views: videoObject.views,
74 likes: 0,
75 dislikes: 0,
76 remote: true,
77 privacy
78 }
79
80 return videoData
81 }
82
83 function videoFileActivityUrlToDBAttributes (videoCreated: VideoInstance, videoObject: VideoTorrentObject) {
84 const mimeTypes = Object.keys(VIDEO_MIMETYPE_EXT)
85 const fileUrls = videoObject.url.filter(u => {
86 return mimeTypes.indexOf(u.mimeType) !== -1 && u.mimeType.startsWith('video/')
87 })
88
89 if (fileUrls.length === 0) {
90 throw new Error('Cannot find video files for ' + videoCreated.url)
91 }
92
93 const attributes: VideoFileAttributes[] = []
94 for (const fileUrl of fileUrls) {
95 // Fetch associated magnet uri
96 const magnet = videoObject.url.find(u => {
97 return u.mimeType === 'application/x-bittorrent;x-scheme-handler/magnet' && u.width === fileUrl.width
98 })
99
100 if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.url)
101
102 const parsed = magnetUtil.decode(magnet.url)
103 if (!parsed || isVideoFileInfoHashValid(parsed.infoHash) === false) throw new Error('Cannot parse magnet URI ' + magnet.url)
104
105 const attribute = {
106 extname: VIDEO_MIMETYPE_EXT[fileUrl.mimeType],
107 infoHash: parsed.infoHash,
108 resolution: fileUrl.width,
109 size: fileUrl.size,
110 videoId: videoCreated.id
111 }
112 attributes.push(attribute)
113 }
114
115 return attributes
116 }
117
118 async function addVideoShares (instance: VideoInstance, shares: string[]) {
119 for (const share of shares) {
120 // Fetch url
121 const json = await doRequest({
122 uri: share,
123 json: true
124 })
125 const actor = json['actor']
126 if (!actor) continue
127
128 const account = await getOrCreateAccountAndServer(actor)
129
130 const entry = {
131 accountId: account.id,
132 videoId: instance.id
133 }
134
135 await db.VideoShare.findOrCreate({
136 where: entry,
137 defaults: entry
138 })
139 }
140 }
141
142 async function addVideoChannelShares (instance: VideoChannelInstance, shares: string[]) {
143 for (const share of shares) {
144 // Fetch url
145 const json = await doRequest({
146 uri: share,
147 json: true
148 })
149 const actor = json['actor']
150 if (!actor) continue
151
152 const account = await getOrCreateAccountAndServer(actor)
153
154 const entry = {
155 accountId: account.id,
156 videoChannelId: instance.id
157 }
158
159 await db.VideoChannelShare.findOrCreate({
160 where: entry,
161 defaults: entry
162 })
163 }
164 }
165
166 // ---------------------------------------------------------------------------
167
168 export {
169 videoFileActivityUrlToDBAttributes,
170 videoActivityObjectToDBAttributes,
171 videoChannelActivityObjectToDBAttributes,
172 addVideoChannelShares,
173 addVideoShares
174 }