diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/controllers/api/config.ts | 2 | ||||
-rw-r--r-- | server/helpers/activitypub.ts | 1 | ||||
-rw-r--r-- | server/helpers/custom-validators/activitypub/videos.ts | 3 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-update.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/videos.ts | 3 | ||||
-rw-r--r-- | server/models/video/video.ts | 3 | ||||
-rw-r--r-- | server/tests/api/videos/video-transcoder.ts | 168 |
7 files changed, 98 insertions, 84 deletions
diff --git a/server/controllers/api/config.ts b/server/controllers/api/config.ts index acbeab70b..950a1498e 100644 --- a/server/controllers/api/config.ts +++ b/server/controllers/api/config.ts | |||
@@ -66,7 +66,7 @@ async function getConfig (req: express.Request, res: express.Response, next: exp | |||
66 | enabledResolutions | 66 | enabledResolutions |
67 | }, | 67 | }, |
68 | import: { | 68 | import: { |
69 | video: { | 69 | videos: { |
70 | http: { | 70 | http: { |
71 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED | 71 | enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED |
72 | } | 72 | } |
diff --git a/server/helpers/activitypub.ts b/server/helpers/activitypub.ts index d710f5c97..a9de11fb0 100644 --- a/server/helpers/activitypub.ts +++ b/server/helpers/activitypub.ts | |||
@@ -24,6 +24,7 @@ function activityPubContextify <T> (data: T) { | |||
24 | views: 'http://schema.org/Number', | 24 | views: 'http://schema.org/Number', |
25 | stats: 'http://schema.org/Number', | 25 | stats: 'http://schema.org/Number', |
26 | size: 'http://schema.org/Number', | 26 | size: 'http://schema.org/Number', |
27 | fps: 'http://schema.org/Number', | ||
27 | commentsEnabled: 'http://schema.org/Boolean', | 28 | commentsEnabled: 'http://schema.org/Boolean', |
28 | waitTranscoding: 'http://schema.org/Boolean', | 29 | waitTranscoding: 'http://schema.org/Boolean', |
29 | support: 'http://schema.org/Text' | 30 | support: 'http://schema.org/Text' |
diff --git a/server/helpers/custom-validators/activitypub/videos.ts b/server/helpers/custom-validators/activitypub/videos.ts index c6a350236..b8075f3c7 100644 --- a/server/helpers/custom-validators/activitypub/videos.ts +++ b/server/helpers/custom-validators/activitypub/videos.ts | |||
@@ -153,7 +153,8 @@ function isRemoteVideoUrlValid (url: any) { | |||
153 | ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mimeType) !== -1 && | 153 | ACTIVITY_PUB.URL_MIME_TYPES.VIDEO.indexOf(url.mimeType) !== -1 && |
154 | isActivityPubUrlValid(url.href) && | 154 | isActivityPubUrlValid(url.href) && |
155 | validator.isInt(url.width + '', { min: 0 }) && | 155 | validator.isInt(url.width + '', { min: 0 }) && |
156 | validator.isInt(url.size + '', { min: 0 }) | 156 | validator.isInt(url.size + '', { min: 0 }) && |
157 | (!url.fps || validator.isInt(url.fps + '', { min: 0 })) | ||
157 | ) || | 158 | ) || |
158 | ( | 159 | ( |
159 | ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mimeType) !== -1 && | 160 | ACTIVITY_PUB.URL_MIME_TYPES.TORRENT.indexOf(url.mimeType) !== -1 && |
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index 62791ff1b..82b661a03 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -108,7 +108,7 @@ async function processUpdateVideo (actor: ActorModel, activity: ActivityUpdate) | |||
108 | await Promise.all(videoFileDestroyTasks) | 108 | await Promise.all(videoFileDestroyTasks) |
109 | 109 | ||
110 | const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoInstance, videoObject) | 110 | const videoFileAttributes = videoFileActivityUrlToDBAttributes(videoInstance, videoObject) |
111 | const tasks = videoFileAttributes.map(f => VideoFileModel.create(f)) | 111 | const tasks = videoFileAttributes.map(f => VideoFileModel.create(f, sequelizeOptions)) |
112 | await Promise.all(tasks) | 112 | await Promise.all(tasks) |
113 | 113 | ||
114 | // Update Tags | 114 | // Update Tags |
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts index b3fbf88d0..e2f46bd02 100644 --- a/server/lib/activitypub/videos.ts +++ b/server/lib/activitypub/videos.ts | |||
@@ -162,7 +162,8 @@ function videoFileActivityUrlToDBAttributes (videoCreated: VideoModel, videoObje | |||
162 | infoHash: parsed.infoHash, | 162 | infoHash: parsed.infoHash, |
163 | resolution: fileUrl.width, | 163 | resolution: fileUrl.width, |
164 | size: fileUrl.size, | 164 | size: fileUrl.size, |
165 | videoId: videoCreated.id | 165 | videoId: videoCreated.id, |
166 | fps: fileUrl.fps | ||
166 | } as VideoFileModel | 167 | } as VideoFileModel |
167 | attributes.push(attribute) | 168 | attributes.push(attribute) |
168 | } | 169 | } |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 67711b102..39fe21007 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -1355,7 +1355,8 @@ export class VideoModel extends Model<VideoModel> { | |||
1355 | mimeType: VIDEO_EXT_MIMETYPE[file.extname], | 1355 | mimeType: VIDEO_EXT_MIMETYPE[file.extname], |
1356 | href: this.getVideoFileUrl(file, baseUrlHttp), | 1356 | href: this.getVideoFileUrl(file, baseUrlHttp), |
1357 | width: file.resolution, | 1357 | width: file.resolution, |
1358 | size: file.size | 1358 | size: file.size, |
1359 | fps: file.fps | ||
1359 | }) | 1360 | }) |
1360 | 1361 | ||
1361 | url.push({ | 1362 | url.push({ |
diff --git a/server/tests/api/videos/video-transcoder.ts b/server/tests/api/videos/video-transcoder.ts index 4a39ee3e3..0f83d4d57 100644 --- a/server/tests/api/videos/video-transcoder.ts +++ b/server/tests/api/videos/video-transcoder.ts | |||
@@ -35,6 +35,8 @@ describe('Test video transcoding', function () { | |||
35 | servers = await flushAndRunMultipleServers(2) | 35 | servers = await flushAndRunMultipleServers(2) |
36 | 36 | ||
37 | await setAccessTokensToServers(servers) | 37 | await setAccessTokensToServers(servers) |
38 | |||
39 | await doubleFollow(servers[0], servers[1]) | ||
38 | }) | 40 | }) |
39 | 41 | ||
40 | it('Should not transcode video on server 1', async function () { | 42 | it('Should not transcode video on server 1', async function () { |
@@ -49,20 +51,22 @@ describe('Test video transcoding', function () { | |||
49 | 51 | ||
50 | await waitJobs(servers) | 52 | await waitJobs(servers) |
51 | 53 | ||
52 | const res = await getVideosList(servers[0].url) | 54 | for (const server of servers) { |
53 | const video = res.body.data[0] | 55 | const res = await getVideosList(server.url) |
56 | const video = res.body.data[ 0 ] | ||
54 | 57 | ||
55 | const res2 = await getVideo(servers[0].url, video.id) | 58 | const res2 = await getVideo(server.url, video.id) |
56 | const videoDetails = res2.body | 59 | const videoDetails = res2.body |
57 | expect(videoDetails.files).to.have.lengthOf(1) | 60 | expect(videoDetails.files).to.have.lengthOf(1) |
58 | 61 | ||
59 | const magnetUri = videoDetails.files[0].magnetUri | 62 | const magnetUri = videoDetails.files[ 0 ].magnetUri |
60 | expect(magnetUri).to.match(/\.webm/) | 63 | expect(magnetUri).to.match(/\.webm/) |
61 | 64 | ||
62 | const torrent = await webtorrentAdd(magnetUri) | 65 | const torrent = await webtorrentAdd(magnetUri, true) |
63 | expect(torrent.files).to.be.an('array') | 66 | expect(torrent.files).to.be.an('array') |
64 | expect(torrent.files.length).to.equal(1) | 67 | expect(torrent.files.length).to.equal(1) |
65 | expect(torrent.files[0].path).match(/\.webm$/) | 68 | expect(torrent.files[ 0 ].path).match(/\.webm$/) |
69 | } | ||
66 | }) | 70 | }) |
67 | 71 | ||
68 | it('Should transcode video on server 2', async function () { | 72 | it('Should transcode video on server 2', async function () { |
@@ -77,21 +81,23 @@ describe('Test video transcoding', function () { | |||
77 | 81 | ||
78 | await waitJobs(servers) | 82 | await waitJobs(servers) |
79 | 83 | ||
80 | const res = await getVideosList(servers[1].url) | 84 | for (const server of servers) { |
85 | const res = await getVideosList(server.url) | ||
81 | 86 | ||
82 | const video = res.body.data[0] | 87 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
83 | const res2 = await getVideo(servers[1].url, video.id) | 88 | const res2 = await getVideo(server.url, video.id) |
84 | const videoDetails = res2.body | 89 | const videoDetails = res2.body |
85 | 90 | ||
86 | expect(videoDetails.files).to.have.lengthOf(4) | 91 | expect(videoDetails.files).to.have.lengthOf(4) |
87 | 92 | ||
88 | const magnetUri = videoDetails.files[0].magnetUri | 93 | const magnetUri = videoDetails.files[ 0 ].magnetUri |
89 | expect(magnetUri).to.match(/\.mp4/) | 94 | expect(magnetUri).to.match(/\.mp4/) |
90 | 95 | ||
91 | const torrent = await webtorrentAdd(magnetUri) | 96 | const torrent = await webtorrentAdd(magnetUri, true) |
92 | expect(torrent.files).to.be.an('array') | 97 | expect(torrent.files).to.be.an('array') |
93 | expect(torrent.files.length).to.equal(1) | 98 | expect(torrent.files.length).to.equal(1) |
94 | expect(torrent.files[0].path).match(/\.mp4$/) | 99 | expect(torrent.files[ 0 ].path).match(/\.mp4$/) |
100 | } | ||
95 | }) | 101 | }) |
96 | 102 | ||
97 | it('Should transcode high bit rate mp3 to proper bit rate', async function () { | 103 | it('Should transcode high bit rate mp3 to proper bit rate', async function () { |
@@ -105,22 +111,24 @@ describe('Test video transcoding', function () { | |||
105 | 111 | ||
106 | await waitJobs(servers) | 112 | await waitJobs(servers) |
107 | 113 | ||
108 | const res = await getVideosList(servers[1].url) | 114 | for (const server of servers) { |
115 | const res = await getVideosList(server.url) | ||
109 | 116 | ||
110 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 117 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
111 | const res2 = await getVideo(servers[1].url, video.id) | 118 | const res2 = await getVideo(server.url, video.id) |
112 | const videoDetails: VideoDetails = res2.body | 119 | const videoDetails: VideoDetails = res2.body |
113 | 120 | ||
114 | expect(videoDetails.files).to.have.lengthOf(4) | 121 | expect(videoDetails.files).to.have.lengthOf(4) |
115 | 122 | ||
116 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') | 123 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') |
117 | const probe = await audio.get(ffmpeg, path) | 124 | const probe = await audio.get(ffmpeg, path) |
118 | 125 | ||
119 | if (probe.audioStream) { | 126 | if (probe.audioStream) { |
120 | expect(probe.audioStream['codec_name']).to.be.equal('aac') | 127 | expect(probe.audioStream[ 'codec_name' ]).to.be.equal('aac') |
121 | expect(probe.audioStream['bit_rate']).to.be.at.most(384 * 8000) | 128 | expect(probe.audioStream[ 'bit_rate' ]).to.be.at.most(384 * 8000) |
122 | } else { | 129 | } else { |
123 | this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) | 130 | this.fail('Could not retrieve the audio stream on ' + probe.absolutePath) |
131 | } | ||
124 | } | 132 | } |
125 | }) | 133 | }) |
126 | 134 | ||
@@ -135,16 +143,18 @@ describe('Test video transcoding', function () { | |||
135 | 143 | ||
136 | await waitJobs(servers) | 144 | await waitJobs(servers) |
137 | 145 | ||
138 | const res = await getVideosList(servers[1].url) | 146 | for (const server of servers) { |
147 | const res = await getVideosList(server.url) | ||
139 | 148 | ||
140 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 149 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
141 | const res2 = await getVideo(servers[1].url, video.id) | 150 | const res2 = await getVideo(server.url, video.id) |
142 | const videoDetails: VideoDetails = res2.body | 151 | const videoDetails: VideoDetails = res2.body |
143 | 152 | ||
144 | expect(videoDetails.files).to.have.lengthOf(4) | 153 | expect(videoDetails.files).to.have.lengthOf(4) |
145 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') | 154 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') |
146 | const probe = await audio.get(ffmpeg, path) | 155 | const probe = await audio.get(ffmpeg, path) |
147 | expect(probe).to.not.have.property('audioStream') | 156 | expect(probe).to.not.have.property('audioStream') |
157 | } | ||
148 | }) | 158 | }) |
149 | 159 | ||
150 | it('Should leave the audio untouched, but properly transcode the video', async function () { | 160 | it('Should leave the audio untouched, but properly transcode the video', async function () { |
@@ -158,22 +168,24 @@ describe('Test video transcoding', function () { | |||
158 | 168 | ||
159 | await waitJobs(servers) | 169 | await waitJobs(servers) |
160 | 170 | ||
161 | const res = await getVideosList(servers[1].url) | 171 | for (const server of servers) { |
162 | 172 | const res = await getVideosList(server.url) | |
163 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 173 | |
164 | const res2 = await getVideo(servers[1].url, video.id) | 174 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
165 | const videoDetails: VideoDetails = res2.body | 175 | const res2 = await getVideo(server.url, video.id) |
166 | 176 | const videoDetails: VideoDetails = res2.body | |
167 | expect(videoDetails.files).to.have.lengthOf(4) | 177 | |
168 | const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture) | 178 | expect(videoDetails.files).to.have.lengthOf(4) |
169 | const fixtureVideoProbe = await audio.get(ffmpeg, fixturePath) | 179 | const fixturePath = buildAbsoluteFixturePath(videoAttributes.fixture) |
170 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') | 180 | const fixtureVideoProbe = await audio.get(ffmpeg, fixturePath) |
171 | const videoProbe = await audio.get(ffmpeg, path) | 181 | const path = join(root(), 'test2', 'videos', video.uuid + '-240.mp4') |
172 | if (videoProbe.audioStream && fixtureVideoProbe.audioStream) { | 182 | const videoProbe = await audio.get(ffmpeg, path) |
173 | const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ] | 183 | if (videoProbe.audioStream && fixtureVideoProbe.audioStream) { |
174 | expect(omit(videoProbe.audioStream, toOmit)).to.be.deep.equal(omit(fixtureVideoProbe.audioStream, toOmit)) | 184 | const toOmit = [ 'max_bit_rate', 'duration', 'duration_ts', 'nb_frames', 'start_time', 'start_pts' ] |
175 | } else { | 185 | expect(omit(videoProbe.audioStream, toOmit)).to.be.deep.equal(omit(fixtureVideoProbe.audioStream, toOmit)) |
176 | this.fail('Could not retrieve the audio stream on ' + videoProbe.absolutePath) | 186 | } else { |
187 | this.fail('Could not retrieve the audio stream on ' + videoProbe.absolutePath) | ||
188 | } | ||
177 | } | 189 | } |
178 | }) | 190 | }) |
179 | 191 | ||
@@ -189,38 +201,36 @@ describe('Test video transcoding', function () { | |||
189 | 201 | ||
190 | await waitJobs(servers) | 202 | await waitJobs(servers) |
191 | 203 | ||
192 | const res = await getVideosList(servers[1].url) | 204 | for (const server of servers) { |
205 | const res = await getVideosList(server.url) | ||
193 | 206 | ||
194 | const video = res.body.data.find(v => v.name === videoAttributes.name) | 207 | const video = res.body.data.find(v => v.name === videoAttributes.name) |
195 | const res2 = await getVideo(servers[1].url, video.id) | 208 | const res2 = await getVideo(server.url, video.id) |
196 | const videoDetails: VideoDetails = res2.body | 209 | const videoDetails: VideoDetails = res2.body |
197 | 210 | ||
198 | expect(videoDetails.files).to.have.lengthOf(4) | 211 | expect(videoDetails.files).to.have.lengthOf(4) |
199 | expect(videoDetails.files[0].fps).to.be.above(58).and.below(62) | 212 | expect(videoDetails.files[ 0 ].fps).to.be.above(58).and.below(62) |
200 | expect(videoDetails.files[1].fps).to.be.below(31) | 213 | expect(videoDetails.files[ 1 ].fps).to.be.below(31) |
201 | expect(videoDetails.files[2].fps).to.be.below(31) | 214 | expect(videoDetails.files[ 2 ].fps).to.be.below(31) |
202 | expect(videoDetails.files[3].fps).to.be.below(31) | 215 | expect(videoDetails.files[ 3 ].fps).to.be.below(31) |
203 | 216 | ||
204 | for (const resolution of [ '240', '360', '480' ]) { | 217 | for (const resolution of [ '240', '360', '480' ]) { |
205 | const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4') | 218 | const path = join(root(), 'test2', 'videos', video.uuid + '-' + resolution + '.mp4') |
206 | const fps = await getVideoFileFPS(path) | 219 | const fps = await getVideoFileFPS(path) |
207 | 220 | ||
208 | expect(fps).to.be.below(31) | 221 | expect(fps).to.be.below(31) |
209 | } | 222 | } |
210 | 223 | ||
211 | const path = join(root(), 'test2', 'videos', video.uuid + '-720.mp4') | 224 | const path = join(root(), 'test2', 'videos', video.uuid + '-720.mp4') |
212 | const fps = await getVideoFileFPS(path) | 225 | const fps = await getVideoFileFPS(path) |
213 | 226 | ||
214 | expect(fps).to.be.above(58).and.below(62) | 227 | expect(fps).to.be.above(58).and.below(62) |
228 | } | ||
215 | }) | 229 | }) |
216 | 230 | ||
217 | it('Should wait transcoding before publishing the video', async function () { | 231 | it('Should wait transcoding before publishing the video', async function () { |
218 | this.timeout(80000) | 232 | this.timeout(80000) |
219 | 233 | ||
220 | await doubleFollow(servers[0], servers[1]) | ||
221 | |||
222 | await waitJobs(servers) | ||
223 | |||
224 | { | 234 | { |
225 | // Upload the video, but wait transcoding | 235 | // Upload the video, but wait transcoding |
226 | const videoAttributes = { | 236 | const videoAttributes = { |