aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/activitypub/crawl.ts2
-rw-r--r--server/lib/activitypub/videos.ts9
-rw-r--r--server/lib/blocklist.ts40
-rw-r--r--server/lib/job-queue/handlers/video-file.ts4
-rw-r--r--server/lib/redis.ts54
-rw-r--r--server/lib/video-comment.ts6
-rw-r--r--server/lib/video-transcoding.ts9
7 files changed, 98 insertions, 26 deletions
diff --git a/server/lib/activitypub/crawl.ts b/server/lib/activitypub/crawl.ts
index 55912341c..db9ce3293 100644
--- a/server/lib/activitypub/crawl.ts
+++ b/server/lib/activitypub/crawl.ts
@@ -1,7 +1,7 @@
1import { ACTIVITY_PUB, JOB_REQUEST_TIMEOUT } from '../../initializers' 1import { ACTIVITY_PUB, JOB_REQUEST_TIMEOUT } from '../../initializers'
2import { doRequest } from '../../helpers/requests' 2import { doRequest } from '../../helpers/requests'
3import { logger } from '../../helpers/logger' 3import { logger } from '../../helpers/logger'
4import Bluebird = require('bluebird') 4import * as Bluebird from 'bluebird'
5 5
6async function crawlCollectionPage <T> (uri: string, handler: (items: T[]) => Promise<any> | Bluebird<any>) { 6async function crawlCollectionPage <T> (uri: string, handler: (items: T[]) => Promise<any> | Bluebird<any>) {
7 logger.info('Crawling ActivityPub data on %s.', uri) 7 logger.info('Crawling ActivityPub data on %s.', uri)
diff --git a/server/lib/activitypub/videos.ts b/server/lib/activitypub/videos.ts
index 54cea542f..3da363c0a 100644
--- a/server/lib/activitypub/videos.ts
+++ b/server/lib/activitypub/videos.ts
@@ -310,7 +310,8 @@ export {
310function isActivityVideoUrlObject (url: ActivityUrlObject): url is ActivityVideoUrlObject { 310function isActivityVideoUrlObject (url: ActivityUrlObject): url is ActivityVideoUrlObject {
311 const mimeTypes = Object.keys(VIDEO_MIMETYPE_EXT) 311 const mimeTypes = Object.keys(VIDEO_MIMETYPE_EXT)
312 312
313 return mimeTypes.indexOf(url.mimeType) !== -1 && url.mimeType.startsWith('video/') 313 const urlMediaType = url.mediaType || url.mimeType
314 return mimeTypes.indexOf(urlMediaType) !== -1 && urlMediaType.startsWith('video/')
314} 315}
315 316
316async function createVideo (videoObject: VideoTorrentObject, channelActor: ActorModel, waitThumbnail = false) { 317async function createVideo (videoObject: VideoTorrentObject, channelActor: ActorModel, waitThumbnail = false) {
@@ -468,7 +469,8 @@ function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: Vid
468 for (const fileUrl of fileUrls) { 469 for (const fileUrl of fileUrls) {
469 // Fetch associated magnet uri 470 // Fetch associated magnet uri
470 const magnet = videoObject.url.find(u => { 471 const magnet = videoObject.url.find(u => {
471 return u.mimeType === 'application/x-bittorrent;x-scheme-handler/magnet' && u.height === fileUrl.height 472 const mediaType = u.mediaType || u.mimeType
473 return mediaType === 'application/x-bittorrent;x-scheme-handler/magnet' && (u as any).height === fileUrl.height
472 }) 474 })
473 475
474 if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.href) 476 if (!magnet) throw new Error('Cannot find associated magnet uri for file ' + fileUrl.href)
@@ -478,8 +480,9 @@ function videoFileActivityUrlToDBAttributes (video: VideoModel, videoObject: Vid
478 throw new Error('Cannot parse magnet URI ' + magnet.href) 480 throw new Error('Cannot parse magnet URI ' + magnet.href)
479 } 481 }
480 482
483 const mediaType = fileUrl.mediaType || fileUrl.mimeType
481 const attribute = { 484 const attribute = {
482 extname: VIDEO_MIMETYPE_EXT[ fileUrl.mimeType ], 485 extname: VIDEO_MIMETYPE_EXT[ mediaType ],
483 infoHash: parsed.infoHash, 486 infoHash: parsed.infoHash,
484 resolution: fileUrl.height, 487 resolution: fileUrl.height,
485 size: fileUrl.size, 488 size: fileUrl.size,
diff --git a/server/lib/blocklist.ts b/server/lib/blocklist.ts
new file mode 100644
index 000000000..1633e500c
--- /dev/null
+++ b/server/lib/blocklist.ts
@@ -0,0 +1,40 @@
1import { sequelizeTypescript } from '../initializers'
2import { AccountBlocklistModel } from '../models/account/account-blocklist'
3import { ServerBlocklistModel } from '../models/server/server-blocklist'
4
5function addAccountInBlocklist (byAccountId: number, targetAccountId: number) {
6 return sequelizeTypescript.transaction(async t => {
7 return AccountBlocklistModel.upsert({
8 accountId: byAccountId,
9 targetAccountId: targetAccountId
10 }, { transaction: t })
11 })
12}
13
14function addServerInBlocklist (byAccountId: number, targetServerId: number) {
15 return sequelizeTypescript.transaction(async t => {
16 return ServerBlocklistModel.upsert({
17 accountId: byAccountId,
18 targetServerId
19 }, { transaction: t })
20 })
21}
22
23function removeAccountFromBlocklist (accountBlock: AccountBlocklistModel) {
24 return sequelizeTypescript.transaction(async t => {
25 return accountBlock.destroy({ transaction: t })
26 })
27}
28
29function removeServerFromBlocklist (serverBlock: ServerBlocklistModel) {
30 return sequelizeTypescript.transaction(async t => {
31 return serverBlock.destroy({ transaction: t })
32 })
33}
34
35export {
36 addAccountInBlocklist,
37 addServerInBlocklist,
38 removeAccountFromBlocklist,
39 removeServerFromBlocklist
40}
diff --git a/server/lib/job-queue/handlers/video-file.ts b/server/lib/job-queue/handlers/video-file.ts
index 1463c93fc..adc0a2a15 100644
--- a/server/lib/job-queue/handlers/video-file.ts
+++ b/server/lib/job-queue/handlers/video-file.ts
@@ -8,7 +8,7 @@ import { retryTransactionWrapper } from '../../../helpers/database-utils'
8import { sequelizeTypescript } from '../../../initializers' 8import { sequelizeTypescript } from '../../../initializers'
9import * as Bluebird from 'bluebird' 9import * as Bluebird from 'bluebird'
10import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils' 10import { computeResolutionsToTranscode } from '../../../helpers/ffmpeg-utils'
11import { importVideoFile, transcodeOriginalVideofile, optimizeOriginalVideofile } from '../../video-transcoding' 11import { importVideoFile, transcodeOriginalVideofile, optimizeVideofile } from '../../video-transcoding'
12 12
13export type VideoFilePayload = { 13export type VideoFilePayload = {
14 videoUUID: string 14 videoUUID: string
@@ -56,7 +56,7 @@ async function processVideoFile (job: Bull.Job) {
56 56
57 await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video) 57 await retryTransactionWrapper(onVideoFileTranscoderOrImportSuccess, video)
58 } else { 58 } else {
59 await optimizeOriginalVideofile(video) 59 await optimizeVideofile(video)
60 60
61 await retryTransactionWrapper(onVideoFileOptimizerSuccess, video, payload.isNewVideo) 61 await retryTransactionWrapper(onVideoFileOptimizerSuccess, video, payload.isNewVideo)
62 } 62 }
diff --git a/server/lib/redis.ts b/server/lib/redis.ts
index e4e435659..abd75d512 100644
--- a/server/lib/redis.ts
+++ b/server/lib/redis.ts
@@ -48,6 +48,8 @@ class Redis {
48 ) 48 )
49 } 49 }
50 50
51 /************* Forgot password *************/
52
51 async setResetPasswordVerificationString (userId: number) { 53 async setResetPasswordVerificationString (userId: number) {
52 const generatedString = await generateRandomString(32) 54 const generatedString = await generateRandomString(32)
53 55
@@ -60,6 +62,8 @@ class Redis {
60 return this.getValue(this.generateResetPasswordKey(userId)) 62 return this.getValue(this.generateResetPasswordKey(userId))
61 } 63 }
62 64
65 /************* Email verification *************/
66
63 async setVerifyEmailVerificationString (userId: number) { 67 async setVerifyEmailVerificationString (userId: number) {
64 const generatedString = await generateRandomString(32) 68 const generatedString = await generateRandomString(32)
65 69
@@ -72,16 +76,20 @@ class Redis {
72 return this.getValue(this.generateVerifyEmailKey(userId)) 76 return this.getValue(this.generateVerifyEmailKey(userId))
73 } 77 }
74 78
79 /************* Views per IP *************/
80
75 setIPVideoView (ip: string, videoUUID: string) { 81 setIPVideoView (ip: string, videoUUID: string) {
76 return this.setValue(this.buildViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME) 82 return this.setValue(this.generateViewKey(ip, videoUUID), '1', VIDEO_VIEW_LIFETIME)
77 } 83 }
78 84
79 async isVideoIPViewExists (ip: string, videoUUID: string) { 85 async isVideoIPViewExists (ip: string, videoUUID: string) {
80 return this.exists(this.buildViewKey(ip, videoUUID)) 86 return this.exists(this.generateViewKey(ip, videoUUID))
81 } 87 }
82 88
89 /************* API cache *************/
90
83 async getCachedRoute (req: express.Request) { 91 async getCachedRoute (req: express.Request) {
84 const cached = await this.getObject(this.buildCachedRouteKey(req)) 92 const cached = await this.getObject(this.generateCachedRouteKey(req))
85 93
86 return cached as CachedRoute 94 return cached as CachedRoute
87 } 95 }
@@ -94,9 +102,11 @@ class Redis {
94 (statusCode) ? { statusCode: statusCode.toString() } : null 102 (statusCode) ? { statusCode: statusCode.toString() } : null
95 ) 103 )
96 104
97 return this.setObject(this.buildCachedRouteKey(req), cached, lifetime) 105 return this.setObject(this.generateCachedRouteKey(req), cached, lifetime)
98 } 106 }
99 107
108 /************* Video views *************/
109
100 addVideoView (videoId: number) { 110 addVideoView (videoId: number) {
101 const keyIncr = this.generateVideoViewKey(videoId) 111 const keyIncr = this.generateVideoViewKey(videoId)
102 const keySet = this.generateVideosViewKey() 112 const keySet = this.generateVideosViewKey()
@@ -131,33 +141,37 @@ class Redis {
131 ]) 141 ])
132 } 142 }
133 143
134 generateVideosViewKey (hour?: number) { 144 /************* Keys generation *************/
145
146 generateCachedRouteKey (req: express.Request) {
147 return req.method + '-' + req.originalUrl
148 }
149
150 private generateVideosViewKey (hour?: number) {
135 if (!hour) hour = new Date().getHours() 151 if (!hour) hour = new Date().getHours()
136 152
137 return `videos-view-h${hour}` 153 return `videos-view-h${hour}`
138 } 154 }
139 155
140 generateVideoViewKey (videoId: number, hour?: number) { 156 private generateVideoViewKey (videoId: number, hour?: number) {
141 if (!hour) hour = new Date().getHours() 157 if (!hour) hour = new Date().getHours()
142 158
143 return `video-view-${videoId}-h${hour}` 159 return `video-view-${videoId}-h${hour}`
144 } 160 }
145 161
146 generateResetPasswordKey (userId: number) { 162 private generateResetPasswordKey (userId: number) {
147 return 'reset-password-' + userId 163 return 'reset-password-' + userId
148 } 164 }
149 165
150 generateVerifyEmailKey (userId: number) { 166 private generateVerifyEmailKey (userId: number) {
151 return 'verify-email-' + userId 167 return 'verify-email-' + userId
152 } 168 }
153 169
154 buildViewKey (ip: string, videoUUID: string) { 170 private generateViewKey (ip: string, videoUUID: string) {
155 return videoUUID + '-' + ip 171 return videoUUID + '-' + ip
156 } 172 }
157 173
158 buildCachedRouteKey (req: express.Request) { 174 /************* Redis helpers *************/
159 return req.method + '-' + req.originalUrl
160 }
161 175
162 private getValue (key: string) { 176 private getValue (key: string) {
163 return new Promise<string>((res, rej) => { 177 return new Promise<string>((res, rej) => {
@@ -197,6 +211,12 @@ class Redis {
197 }) 211 })
198 } 212 }
199 213
214 private deleteFieldInHash (key: string, field: string) {
215 return new Promise<void>((res, rej) => {
216 this.client.hdel(this.prefix + key, field, err => err ? rej(err) : res())
217 })
218 }
219
200 private setValue (key: string, value: string, expirationMilliseconds: number) { 220 private setValue (key: string, value: string, expirationMilliseconds: number) {
201 return new Promise<void>((res, rej) => { 221 return new Promise<void>((res, rej) => {
202 this.client.set(this.prefix + key, value, 'PX', expirationMilliseconds, (err, ok) => { 222 this.client.set(this.prefix + key, value, 'PX', expirationMilliseconds, (err, ok) => {
@@ -235,6 +255,16 @@ class Redis {
235 }) 255 })
236 } 256 }
237 257
258 private setValueInHash (key: string, field: string, value: string) {
259 return new Promise<void>((res, rej) => {
260 this.client.hset(this.prefix + key, field, value, (err) => {
261 if (err) return rej(err)
262
263 return res()
264 })
265 })
266 }
267
238 private increment (key: string) { 268 private increment (key: string) {
239 return new Promise<number>((res, rej) => { 269 return new Promise<number>((res, rej) => {
240 this.client.incr(this.prefix + key, (err, value) => { 270 this.client.incr(this.prefix + key, (err, value) => {
diff --git a/server/lib/video-comment.ts b/server/lib/video-comment.ts
index 70ba7c303..59bce7520 100644
--- a/server/lib/video-comment.ts
+++ b/server/lib/video-comment.ts
@@ -64,10 +64,8 @@ function buildFormattedCommentTree (resultList: ResultList<VideoCommentModel>):
64 } 64 }
65 65
66 const parentCommentThread = idx[childComment.inReplyToCommentId] 66 const parentCommentThread = idx[childComment.inReplyToCommentId]
67 if (!parentCommentThread) { 67 // Maybe the parent comment was blocked by the admin/user
68 const msg = `Cannot format video thread tree, parent ${childComment.inReplyToCommentId} not found for child ${childComment.id}` 68 if (!parentCommentThread) continue
69 throw new Error(msg)
70 }
71 69
72 parentCommentThread.children.push(childCommentThread) 70 parentCommentThread.children.push(childCommentThread)
73 idx[childComment.id] = childCommentThread 71 idx[childComment.id] = childCommentThread
diff --git a/server/lib/video-transcoding.ts b/server/lib/video-transcoding.ts
index bf3ff78c2..a78de61e5 100644
--- a/server/lib/video-transcoding.ts
+++ b/server/lib/video-transcoding.ts
@@ -1,5 +1,5 @@
1import { CONFIG } from '../initializers' 1import { CONFIG } from '../initializers'
2import { join, extname } from 'path' 2import { extname, join } from 'path'
3import { getVideoFileFPS, getVideoFileResolution, transcode } from '../helpers/ffmpeg-utils' 3import { getVideoFileFPS, getVideoFileResolution, transcode } from '../helpers/ffmpeg-utils'
4import { copy, remove, rename, stat } from 'fs-extra' 4import { copy, remove, rename, stat } from 'fs-extra'
5import { logger } from '../helpers/logger' 5import { logger } from '../helpers/logger'
@@ -7,10 +7,11 @@ import { VideoResolution } from '../../shared/models/videos'
7import { VideoFileModel } from '../models/video/video-file' 7import { VideoFileModel } from '../models/video/video-file'
8import { VideoModel } from '../models/video/video' 8import { VideoModel } from '../models/video/video'
9 9
10async function optimizeOriginalVideofile (video: VideoModel) { 10async function optimizeVideofile (video: VideoModel, inputVideoFileArg?: VideoFileModel) {
11 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR 11 const videosDirectory = CONFIG.STORAGE.VIDEOS_DIR
12 const newExtname = '.mp4' 12 const newExtname = '.mp4'
13 const inputVideoFile = video.getOriginalFile() 13
14 const inputVideoFile = inputVideoFileArg ? inputVideoFileArg : video.getOriginalFile()
14 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile)) 15 const videoInputPath = join(videosDirectory, video.getVideoFilename(inputVideoFile))
15 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname) 16 const videoTranscodedPath = join(videosDirectory, video.id + '-transcoded' + newExtname)
16 17
@@ -124,7 +125,7 @@ async function importVideoFile (video: VideoModel, inputFilePath: string) {
124} 125}
125 126
126export { 127export {
127 optimizeOriginalVideofile, 128 optimizeVideofile,
128 transcodeOriginalVideofile, 129 transcodeOriginalVideofile,
129 importVideoFile 130 importVideoFile
130} 131}