aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/helpers
diff options
context:
space:
mode:
Diffstat (limited to 'server/helpers')
-rw-r--r--server/helpers/custom-validators/follows.ts20
-rw-r--r--server/helpers/custom-validators/servers.ts1
-rw-r--r--server/helpers/custom-validators/video-ownership.ts2
-rw-r--r--server/helpers/database-utils.ts41
-rw-r--r--server/helpers/express-utils.ts2
-rw-r--r--server/helpers/ffmpeg-utils.ts15
-rw-r--r--server/helpers/logger.ts23
-rw-r--r--server/helpers/webtorrent.ts5
-rw-r--r--server/helpers/youtube-dl.ts2
9 files changed, 86 insertions, 25 deletions
diff --git a/server/helpers/custom-validators/follows.ts b/server/helpers/custom-validators/follows.ts
index fbef7ad87..8f65552c3 100644
--- a/server/helpers/custom-validators/follows.ts
+++ b/server/helpers/custom-validators/follows.ts
@@ -1,4 +1,4 @@
1import { exists } from './misc' 1import { exists, isArray } from './misc'
2import { FollowState } from '@shared/models' 2import { FollowState } from '@shared/models'
3 3
4function isFollowStateValid (value: FollowState) { 4function isFollowStateValid (value: FollowState) {
@@ -7,8 +7,24 @@ function isFollowStateValid (value: FollowState) {
7 return value === 'pending' || value === 'accepted' 7 return value === 'pending' || value === 'accepted'
8} 8}
9 9
10function isRemoteHandleValid (value: string) {
11 if (!exists(value)) return false
12 if (typeof value !== 'string') return false
13
14 return value.includes('@')
15}
16
17function isEachUniqueHandleValid (handles: string[]) {
18 return isArray(handles) &&
19 handles.every(handle => {
20 return isRemoteHandleValid(handle) && handles.indexOf(handle) === handles.lastIndexOf(handle)
21 })
22}
23
10// --------------------------------------------------------------------------- 24// ---------------------------------------------------------------------------
11 25
12export { 26export {
13 isFollowStateValid 27 isFollowStateValid,
28 isRemoteHandleValid,
29 isEachUniqueHandleValid
14} 30}
diff --git a/server/helpers/custom-validators/servers.ts b/server/helpers/custom-validators/servers.ts
index adf1ea497..c0f8b6aeb 100644
--- a/server/helpers/custom-validators/servers.ts
+++ b/server/helpers/custom-validators/servers.ts
@@ -19,7 +19,6 @@ function isHostValid (host: string) {
19 19
20function isEachUniqueHostValid (hosts: string[]) { 20function isEachUniqueHostValid (hosts: string[]) {
21 return isArray(hosts) && 21 return isArray(hosts) &&
22 hosts.length !== 0 &&
23 hosts.every(host => { 22 hosts.every(host => {
24 return isHostValid(host) && hosts.indexOf(host) === hosts.lastIndexOf(host) 23 return isHostValid(host) && hosts.indexOf(host) === hosts.lastIndexOf(host)
25 }) 24 })
diff --git a/server/helpers/custom-validators/video-ownership.ts b/server/helpers/custom-validators/video-ownership.ts
index 0e1c63bad..cf15b385a 100644
--- a/server/helpers/custom-validators/video-ownership.ts
+++ b/server/helpers/custom-validators/video-ownership.ts
@@ -1,7 +1,7 @@
1import { Response } from 'express' 1import { Response } from 'express'
2import { MUserId } from '@server/types/models' 2import { MUserId } from '@server/types/models'
3import { MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership' 3import { MVideoChangeOwnershipFull } from '@server/types/models/video/video-change-ownership'
4import { HttpStatusCode } from '../../../shared/core-utils/miscs/http-error-codes' 4import { HttpStatusCode } from '../../../shared/models/http/http-error-codes'
5 5
6function checkUserCanTerminateOwnershipChange (user: MUserId, videoChangeOwnership: MVideoChangeOwnershipFull, res: Response) { 6function checkUserCanTerminateOwnershipChange (user: MUserId, videoChangeOwnership: MVideoChangeOwnershipFull, res: Response) {
7 if (videoChangeOwnership.NextOwner.userId === user.id) { 7 if (videoChangeOwnership.NextOwner.userId === user.id) {
diff --git a/server/helpers/database-utils.ts b/server/helpers/database-utils.ts
index b5dc70c17..422774022 100644
--- a/server/helpers/database-utils.ts
+++ b/server/helpers/database-utils.ts
@@ -1,12 +1,12 @@
1import * as retry from 'async/retry' 1import * as retry from 'async/retry'
2import * as Bluebird from 'bluebird' 2import * as Bluebird from 'bluebird'
3import { QueryTypes, Transaction } from 'sequelize' 3import { BindOrReplacements, QueryTypes, Transaction } from 'sequelize'
4import { Model } from 'sequelize-typescript' 4import { Model } from 'sequelize-typescript'
5import { sequelizeTypescript } from '@server/initializers/database' 5import { sequelizeTypescript } from '@server/initializers/database'
6import { logger } from './logger' 6import { logger } from './logger'
7 7
8function retryTransactionWrapper <T, A, B, C, D> ( 8function retryTransactionWrapper <T, A, B, C, D> (
9 functionToRetry: (arg1: A, arg2: B, arg3: C, arg4: D) => Promise<T> | Bluebird<T>, 9 functionToRetry: (arg1: A, arg2: B, arg3: C, arg4: D) => Promise<T>,
10 arg1: A, 10 arg1: A,
11 arg2: B, 11 arg2: B,
12 arg3: C, 12 arg3: C,
@@ -14,20 +14,20 @@ function retryTransactionWrapper <T, A, B, C, D> (
14): Promise<T> 14): Promise<T>
15 15
16function retryTransactionWrapper <T, A, B, C> ( 16function retryTransactionWrapper <T, A, B, C> (
17 functionToRetry: (arg1: A, arg2: B, arg3: C) => Promise<T> | Bluebird<T>, 17 functionToRetry: (arg1: A, arg2: B, arg3: C) => Promise<T>,
18 arg1: A, 18 arg1: A,
19 arg2: B, 19 arg2: B,
20 arg3: C 20 arg3: C
21): Promise<T> 21): Promise<T>
22 22
23function retryTransactionWrapper <T, A, B> ( 23function retryTransactionWrapper <T, A, B> (
24 functionToRetry: (arg1: A, arg2: B) => Promise<T> | Bluebird<T>, 24 functionToRetry: (arg1: A, arg2: B) => Promise<T>,
25 arg1: A, 25 arg1: A,
26 arg2: B 26 arg2: B
27): Promise<T> 27): Promise<T>
28 28
29function retryTransactionWrapper <T, A> ( 29function retryTransactionWrapper <T, A> (
30 functionToRetry: (arg1: A) => Promise<T> | Bluebird<T>, 30 functionToRetry: (arg1: A) => Promise<T>,
31 arg1: A 31 arg1: A
32): Promise<T> 32): Promise<T>
33 33
@@ -36,7 +36,7 @@ function retryTransactionWrapper <T> (
36): Promise<T> 36): Promise<T>
37 37
38function retryTransactionWrapper <T> ( 38function retryTransactionWrapper <T> (
39 functionToRetry: (...args: any[]) => Promise<T> | Bluebird<T>, 39 functionToRetry: (...args: any[]) => Promise<T>,
40 ...args: any[] 40 ...args: any[]
41): Promise<T> { 41): Promise<T> {
42 return transactionRetryer<T>(callback => { 42 return transactionRetryer<T>(callback => {
@@ -84,13 +84,15 @@ function resetSequelizeInstance (instance: Model<any>, savedFields: object) {
84 }) 84 })
85} 85}
86 86
87function deleteNonExistingModels <T extends { hasSameUniqueKeysThan (other: T): boolean } & Pick<Model, 'destroy'>> ( 87function filterNonExistingModels <T extends { hasSameUniqueKeysThan (other: T): boolean }> (
88 fromDatabase: T[], 88 fromDatabase: T[],
89 newModels: T[], 89 newModels: T[]
90 t: Transaction
91) { 90) {
92 return fromDatabase.filter(f => !newModels.find(newModel => newModel.hasSameUniqueKeysThan(f))) 91 return fromDatabase.filter(f => !newModels.find(newModel => newModel.hasSameUniqueKeysThan(f)))
93 .map(f => f.destroy({ transaction: t })) 92}
93
94function deleteAllModels <T extends Pick<Model, 'destroy'>> (models: T[], transaction: Transaction) {
95 return Promise.all(models.map(f => f.destroy({ transaction })))
94} 96}
95 97
96// Sequelize always skip the update if we only update updatedAt field 98// Sequelize always skip the update if we only update updatedAt field
@@ -121,13 +123,28 @@ function afterCommitIfTransaction (t: Transaction, fn: Function) {
121 123
122// --------------------------------------------------------------------------- 124// ---------------------------------------------------------------------------
123 125
126function doesExist (query: string, bind?: BindOrReplacements) {
127 const options = {
128 type: QueryTypes.SELECT as QueryTypes.SELECT,
129 bind,
130 raw: true
131 }
132
133 return sequelizeTypescript.query(query, options)
134 .then(results => results.length === 1)
135}
136
137// ---------------------------------------------------------------------------
138
124export { 139export {
125 resetSequelizeInstance, 140 resetSequelizeInstance,
126 retryTransactionWrapper, 141 retryTransactionWrapper,
127 transactionRetryer, 142 transactionRetryer,
128 updateInstanceWithAnother, 143 updateInstanceWithAnother,
129 afterCommitIfTransaction, 144 afterCommitIfTransaction,
130 deleteNonExistingModels, 145 filterNonExistingModels,
146 deleteAllModels,
131 setAsUpdated, 147 setAsUpdated,
132 runInReadCommittedTransaction 148 runInReadCommittedTransaction,
149 doesExist
133} 150}
diff --git a/server/helpers/express-utils.ts b/server/helpers/express-utils.ts
index 0ff113274..c299b70f1 100644
--- a/server/helpers/express-utils.ts
+++ b/server/helpers/express-utils.ts
@@ -1,6 +1,6 @@
1import * as express from 'express' 1import * as express from 'express'
2import * as multer from 'multer' 2import * as multer from 'multer'
3import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' 3import { HttpStatusCode } from '../../shared/models/http/http-error-codes'
4import { CONFIG } from '../initializers/config' 4import { CONFIG } from '../initializers/config'
5import { REMOTE_SCHEME } from '../initializers/constants' 5import { REMOTE_SCHEME } from '../initializers/constants'
6import { getLowercaseExtension } from './core-utils' 6import { getLowercaseExtension } from './core-utils'
diff --git a/server/helpers/ffmpeg-utils.ts b/server/helpers/ffmpeg-utils.ts
index 6f5a71b4a..9ad4b7f3b 100644
--- a/server/helpers/ffmpeg-utils.ts
+++ b/server/helpers/ffmpeg-utils.ts
@@ -212,14 +212,17 @@ async function transcode (options: TranscodeOptions) {
212 212
213async function getLiveTranscodingCommand (options: { 213async function getLiveTranscodingCommand (options: {
214 rtmpUrl: string 214 rtmpUrl: string
215
215 outPath: string 216 outPath: string
217 masterPlaylistName: string
218
216 resolutions: number[] 219 resolutions: number[]
217 fps: number 220 fps: number
218 221
219 availableEncoders: AvailableEncoders 222 availableEncoders: AvailableEncoders
220 profile: string 223 profile: string
221}) { 224}) {
222 const { rtmpUrl, outPath, resolutions, fps, availableEncoders, profile } = options 225 const { rtmpUrl, outPath, resolutions, fps, availableEncoders, profile, masterPlaylistName } = options
223 const input = rtmpUrl 226 const input = rtmpUrl
224 227
225 const command = getFFmpeg(input, 'live') 228 const command = getFFmpeg(input, 'live')
@@ -301,14 +304,14 @@ async function getLiveTranscodingCommand (options: {
301 304
302 command.complexFilter(complexFilter) 305 command.complexFilter(complexFilter)
303 306
304 addDefaultLiveHLSParams(command, outPath) 307 addDefaultLiveHLSParams(command, outPath, masterPlaylistName)
305 308
306 command.outputOption('-var_stream_map', varStreamMap.join(' ')) 309 command.outputOption('-var_stream_map', varStreamMap.join(' '))
307 310
308 return command 311 return command
309} 312}
310 313
311function getLiveMuxingCommand (rtmpUrl: string, outPath: string) { 314function getLiveMuxingCommand (rtmpUrl: string, outPath: string, masterPlaylistName: string) {
312 const command = getFFmpeg(rtmpUrl, 'live') 315 const command = getFFmpeg(rtmpUrl, 'live')
313 316
314 command.outputOption('-c:v copy') 317 command.outputOption('-c:v copy')
@@ -316,7 +319,7 @@ function getLiveMuxingCommand (rtmpUrl: string, outPath: string) {
316 command.outputOption('-map 0:a?') 319 command.outputOption('-map 0:a?')
317 command.outputOption('-map 0:v?') 320 command.outputOption('-map 0:v?')
318 321
319 addDefaultLiveHLSParams(command, outPath) 322 addDefaultLiveHLSParams(command, outPath, masterPlaylistName)
320 323
321 return command 324 return command
322} 325}
@@ -371,12 +374,12 @@ function addDefaultEncoderParams (options: {
371 } 374 }
372} 375}
373 376
374function addDefaultLiveHLSParams (command: ffmpeg.FfmpegCommand, outPath: string) { 377function addDefaultLiveHLSParams (command: ffmpeg.FfmpegCommand, outPath: string, masterPlaylistName: string) {
375 command.outputOption('-hls_time ' + VIDEO_LIVE.SEGMENT_TIME_SECONDS) 378 command.outputOption('-hls_time ' + VIDEO_LIVE.SEGMENT_TIME_SECONDS)
376 command.outputOption('-hls_list_size ' + VIDEO_LIVE.SEGMENTS_LIST_SIZE) 379 command.outputOption('-hls_list_size ' + VIDEO_LIVE.SEGMENTS_LIST_SIZE)
377 command.outputOption('-hls_flags delete_segments+independent_segments') 380 command.outputOption('-hls_flags delete_segments+independent_segments')
378 command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%06d.ts')}`) 381 command.outputOption(`-hls_segment_filename ${join(outPath, '%v-%06d.ts')}`)
379 command.outputOption('-master_pl_name master.m3u8') 382 command.outputOption('-master_pl_name ' + masterPlaylistName)
380 command.outputOption(`-f hls`) 383 command.outputOption(`-f hls`)
381 384
382 command.output(join(outPath, '%v.m3u8')) 385 command.output(join(outPath, '%v.m3u8'))
diff --git a/server/helpers/logger.ts b/server/helpers/logger.ts
index 29e06860d..20c3c3edb 100644
--- a/server/helpers/logger.ts
+++ b/server/helpers/logger.ts
@@ -1,5 +1,5 @@
1// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/ 1// Thanks http://tostring.it/2014/06/23/advanced-logging-with-nodejs/
2import { mkdirpSync } from 'fs-extra' 2import { mkdirpSync, stat } from 'fs-extra'
3import { omit } from 'lodash' 3import { omit } from 'lodash'
4import * as path from 'path' 4import * as path from 'path'
5import { format as sqlFormat } from 'sql-formatter' 5import { format as sqlFormat } from 'sql-formatter'
@@ -158,6 +158,26 @@ function loggerTagsFactory (...defaultTags: string[]): LoggerTagsFn {
158 } 158 }
159} 159}
160 160
161async function mtimeSortFilesDesc (files: string[], basePath: string) {
162 const promises = []
163 const out: { file: string, mtime: number }[] = []
164
165 for (const file of files) {
166 const p = stat(basePath + '/' + file)
167 .then(stats => {
168 if (stats.isFile()) out.push({ file, mtime: stats.mtime.getTime() })
169 })
170
171 promises.push(p)
172 }
173
174 await Promise.all(promises)
175
176 out.sort((a, b) => b.mtime - a.mtime)
177
178 return out
179}
180
161// --------------------------------------------------------------------------- 181// ---------------------------------------------------------------------------
162 182
163export { 183export {
@@ -168,6 +188,7 @@ export {
168 labelFormatter, 188 labelFormatter,
169 consoleLoggerFormat, 189 consoleLoggerFormat,
170 jsonLoggerFormat, 190 jsonLoggerFormat,
191 mtimeSortFilesDesc,
171 logger, 192 logger,
172 loggerTagsFactory, 193 loggerTagsFactory,
173 bunyanLogger 194 bunyanLogger
diff --git a/server/helpers/webtorrent.ts b/server/helpers/webtorrent.ts
index d8220ba9c..ecf63e93e 100644
--- a/server/helpers/webtorrent.ts
+++ b/server/helpers/webtorrent.ts
@@ -103,6 +103,11 @@ async function createTorrentAndSetInfoHash (
103 103
104 await writeFile(torrentPath, torrent) 104 await writeFile(torrentPath, torrent)
105 105
106 // Remove old torrent file if it existed
107 if (videoFile.hasTorrent()) {
108 await remove(join(CONFIG.STORAGE.TORRENTS_DIR, videoFile.torrentFilename))
109 }
110
106 const parsedTorrent = parseTorrent(torrent) 111 const parsedTorrent = parseTorrent(torrent)
107 videoFile.infoHash = parsedTorrent.infoHash 112 videoFile.infoHash = parsedTorrent.infoHash
108 videoFile.torrentFilename = torrentFilename 113 videoFile.torrentFilename = torrentFilename
diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts
index fdd361390..3c80e7d41 100644
--- a/server/helpers/youtube-dl.ts
+++ b/server/helpers/youtube-dl.ts
@@ -3,7 +3,7 @@ import { ensureDir, move, pathExists, remove, writeFile } from 'fs-extra'
3import got from 'got' 3import got from 'got'
4import { join } from 'path' 4import { join } from 'path'
5import { CONFIG } from '@server/initializers/config' 5import { CONFIG } from '@server/initializers/config'
6import { HttpStatusCode } from '../../shared/core-utils/miscs/http-error-codes' 6import { HttpStatusCode } from '../../shared/models/http/http-error-codes'
7import { VideoResolution } from '../../shared/models/videos' 7import { VideoResolution } from '../../shared/models/videos'
8import { CONSTRAINTS_FIELDS, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES } from '../initializers/constants' 8import { CONSTRAINTS_FIELDS, VIDEO_CATEGORIES, VIDEO_LANGUAGES, VIDEO_LICENCES } from '../initializers/constants'
9import { peertubeTruncate, pipelinePromise, root } from './core-utils' 9import { peertubeTruncate, pipelinePromise, root } from './core-utils'