aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/initializers
diff options
context:
space:
mode:
Diffstat (limited to 'server/initializers')
-rw-r--r--server/initializers/checker.ts31
-rw-r--r--server/initializers/constants.ts53
-rw-r--r--server/initializers/database.ts8
3 files changed, 82 insertions, 10 deletions
diff --git a/server/initializers/checker.ts b/server/initializers/checker.ts
index 52a1aeb50..608123607 100644
--- a/server/initializers/checker.ts
+++ b/server/initializers/checker.ts
@@ -43,7 +43,7 @@ function checkMissedConfig () {
43 const required = [ 'listen.port', 'listen.hostname', 43 const required = [ 'listen.port', 'listen.hostname',
44 'webserver.https', 'webserver.hostname', 'webserver.port', 44 'webserver.https', 'webserver.hostname', 'webserver.port',
45 'trust_proxy', 45 'trust_proxy',
46 'database.hostname', 'database.port', 'database.suffix', 'database.username', 'database.password', 46 'database.hostname', 'database.port', 'database.suffix', 'database.username', 'database.password', 'database.pool.max',
47 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address', 47 'smtp.hostname', 'smtp.port', 'smtp.username', 'smtp.password', 'smtp.tls', 'smtp.from_address',
48 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache', 48 'storage.avatars', 'storage.videos', 'storage.logs', 'storage.previews', 'storage.thumbnails', 'storage.torrents', 'storage.cache',
49 'log.level', 49 'log.level',
@@ -51,6 +51,7 @@ function checkMissedConfig () {
51 'cache.previews.size', 'admin.email', 51 'cache.previews.size', 'admin.email',
52 'signup.enabled', 'signup.limit', 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist', 52 'signup.enabled', 'signup.limit', 'signup.filters.cidr.whitelist', 'signup.filters.cidr.blacklist',
53 'transcoding.enabled', 'transcoding.threads', 53 'transcoding.enabled', 'transcoding.threads',
54 'import.videos.http.enabled',
54 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route', 55 'instance.name', 'instance.short_description', 'instance.description', 'instance.terms', 'instance.default_client_route',
55 'instance.default_nsfw_policy', 'instance.robots', 56 'instance.default_nsfw_policy', 'instance.robots',
56 'services.twitter.username', 'services.twitter.whitelisted' 57 'services.twitter.username', 'services.twitter.whitelisted'
@@ -84,11 +85,11 @@ function checkMissedConfig () {
84async function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) { 85async function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) {
85 const Ffmpeg = require('fluent-ffmpeg') 86 const Ffmpeg = require('fluent-ffmpeg')
86 const getAvailableCodecsPromise = promisify0(Ffmpeg.getAvailableCodecs) 87 const getAvailableCodecsPromise = promisify0(Ffmpeg.getAvailableCodecs)
87
88 const codecs = await getAvailableCodecsPromise() 88 const codecs = await getAvailableCodecsPromise()
89 const canEncode = [ 'libx264' ]
90
89 if (CONFIG.TRANSCODING.ENABLED === false) return undefined 91 if (CONFIG.TRANSCODING.ENABLED === false) return undefined
90 92
91 const canEncode = [ 'libx264' ]
92 for (const codec of canEncode) { 93 for (const codec of canEncode) {
93 if (codecs[codec] === undefined) { 94 if (codecs[codec] === undefined) {
94 throw new Error('Unknown codec ' + codec + ' in FFmpeg.') 95 throw new Error('Unknown codec ' + codec + ' in FFmpeg.')
@@ -98,6 +99,29 @@ async function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) {
98 throw new Error('Unavailable encode codec ' + codec + ' in FFmpeg') 99 throw new Error('Unavailable encode codec ' + codec + ' in FFmpeg')
99 } 100 }
100 } 101 }
102
103 checkFFmpegEncoders()
104}
105
106// Optional encoders, if present, can be used to improve transcoding
107// Here we ask ffmpeg if it detects their presence on the system, so that we can later use them
108let supportedOptionalEncoders: Map<string, boolean>
109async function checkFFmpegEncoders (): Promise<Map<string, boolean>> {
110 if (supportedOptionalEncoders !== undefined) {
111 return supportedOptionalEncoders
112 }
113
114 const Ffmpeg = require('fluent-ffmpeg')
115 const getAvailableEncodersPromise = promisify0(Ffmpeg.getAvailableEncoders)
116 const encoders = await getAvailableEncodersPromise()
117 const optionalEncoders = [ 'libfdk_aac' ]
118 supportedOptionalEncoders = new Map<string, boolean>()
119
120 for (const encoder of optionalEncoders) {
121 supportedOptionalEncoders.set(encoder,
122 encoders[encoder] !== undefined
123 )
124 }
101} 125}
102 126
103// We get db by param to not import it in this file (import orders) 127// We get db by param to not import it in this file (import orders)
@@ -126,6 +150,7 @@ async function applicationExist () {
126export { 150export {
127 checkConfig, 151 checkConfig,
128 checkFFmpeg, 152 checkFFmpeg,
153 checkFFmpegEncoders,
129 checkMissedConfig, 154 checkMissedConfig,
130 clientsExist, 155 clientsExist,
131 usersExist, 156 usersExist,
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts
index 3aa979668..069d9b2e8 100644
--- a/server/initializers/constants.ts
+++ b/server/initializers/constants.ts
@@ -8,6 +8,7 @@ import { VideoPrivacy } from '../../shared/models/videos'
8import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' 8import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils'
9import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' 9import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type'
10import { invert } from 'lodash' 10import { invert } from 'lodash'
11import { VideoImportState } from '../../shared/models/videos/video-import-state.enum'
11 12
12// Use a variable to reload the configuration if we need 13// Use a variable to reload the configuration if we need
13let config: IConfig = require('config') 14let config: IConfig = require('config')
@@ -36,6 +37,7 @@ const SORTABLE_COLUMNS = {
36 VIDEO_ABUSES: [ 'id', 'createdAt' ], 37 VIDEO_ABUSES: [ 'id', 'createdAt' ],
37 VIDEO_CHANNELS: [ 'id', 'name', 'updatedAt', 'createdAt' ], 38 VIDEO_CHANNELS: [ 'id', 'name', 'updatedAt', 'createdAt' ],
38 VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'views', 'likes' ], 39 VIDEOS: [ 'name', 'duration', 'createdAt', 'publishedAt', 'views', 'likes' ],
40 VIDEO_IMPORTS: [ 'createdAt' ],
39 VIDEO_COMMENT_THREADS: [ 'createdAt' ], 41 VIDEO_COMMENT_THREADS: [ 'createdAt' ],
40 BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ], 42 BLACKLISTS: [ 'id', 'name', 'duration', 'views', 'likes', 'dislikes', 'uuid', 'createdAt' ],
41 FOLLOWERS: [ 'createdAt' ], 43 FOLLOWERS: [ 'createdAt' ],
@@ -85,6 +87,7 @@ const JOB_ATTEMPTS: { [ id in JobType ]: number } = {
85 'activitypub-follow': 5, 87 'activitypub-follow': 5,
86 'video-file-import': 1, 88 'video-file-import': 1,
87 'video-file': 1, 89 'video-file': 1,
90 'video-import': 1,
88 'email': 5 91 'email': 5
89} 92}
90const JOB_CONCURRENCY: { [ id in JobType ]: number } = { 93const JOB_CONCURRENCY: { [ id in JobType ]: number } = {
@@ -94,18 +97,29 @@ const JOB_CONCURRENCY: { [ id in JobType ]: number } = {
94 'activitypub-follow': 3, 97 'activitypub-follow': 3,
95 'video-file-import': 1, 98 'video-file-import': 1,
96 'video-file': 1, 99 'video-file': 1,
100 'video-import': 1,
97 'email': 5 101 'email': 5
98} 102}
103const JOB_TTL: { [ id in JobType ]: number } = {
104 'activitypub-http-broadcast': 60000 * 10, // 10 minutes
105 'activitypub-http-unicast': 60000 * 10, // 10 minutes
106 'activitypub-http-fetcher': 60000 * 10, // 10 minutes
107 'activitypub-follow': 60000 * 10, // 10 minutes
108 'video-file-import': 1000 * 3600, // 1 hour
109 'video-file': 1000 * 3600 * 48, // 2 days, transcoding could be long
110 'video-import': 1000 * 3600 * 5, // 5 hours
111 'email': 60000 * 10 // 10 minutes
112}
99const BROADCAST_CONCURRENCY = 10 // How many requests in parallel we do in activitypub-http-broadcast job 113const BROADCAST_CONCURRENCY = 10 // How many requests in parallel we do in activitypub-http-broadcast job
100const JOB_REQUEST_TIMEOUT = 3000 // 3 seconds 114const JOB_REQUEST_TIMEOUT = 3000 // 3 seconds
101const JOB_REQUEST_TTL = 60000 * 10 // 10 minutes
102const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days 115const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days
103 116
104// 1 hour 117// 1 hour
105let SCHEDULER_INTERVALS_MS = { 118let SCHEDULER_INTERVALS_MS = {
106 badActorFollow: 60000 * 60, // 1 hour 119 badActorFollow: 60000 * 60, // 1 hour
107 removeOldJobs: 60000 * 60, // 1 hour 120 removeOldJobs: 60000 * 60, // 1 hour
108 updateVideos: 60000 // 1 minute 121 updateVideos: 60000, // 1 minute
122 youtubeDLUpdate: 60000 * 60 * 24 // 1 day
109} 123}
110 124
111// --------------------------------------------------------------------------- 125// ---------------------------------------------------------------------------
@@ -121,7 +135,10 @@ const CONFIG = {
121 HOSTNAME: config.get<string>('database.hostname'), 135 HOSTNAME: config.get<string>('database.hostname'),
122 PORT: config.get<number>('database.port'), 136 PORT: config.get<number>('database.port'),
123 USERNAME: config.get<string>('database.username'), 137 USERNAME: config.get<string>('database.username'),
124 PASSWORD: config.get<string>('database.password') 138 PASSWORD: config.get<string>('database.password'),
139 POOL: {
140 MAX: config.get<number>('database.pool.max')
141 }
125 }, 142 },
126 REDIS: { 143 REDIS: {
127 HOSTNAME: config.has('redis.hostname') ? config.get<string>('redis.hostname') : null, 144 HOSTNAME: config.has('redis.hostname') ? config.get<string>('redis.hostname') : null,
@@ -189,6 +206,13 @@ const CONFIG = {
189 get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') } 206 get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') }
190 } 207 }
191 }, 208 },
209 IMPORT: {
210 VIDEOS: {
211 HTTP: {
212 get ENABLED () { return config.get<boolean>('import.videos.http.enabled') }
213 }
214 }
215 },
192 CACHE: { 216 CACHE: {
193 PREVIEWS: { 217 PREVIEWS: {
194 get SIZE () { return config.get<number>('cache.previews.size') } 218 get SIZE () { return config.get<number>('cache.previews.size') }
@@ -245,6 +269,9 @@ const CONSTRAINTS_FIELDS = {
245 } 269 }
246 } 270 }
247 }, 271 },
272 VIDEO_IMPORTS: {
273 URL: { min: 3, max: 2000 } // Length
274 },
248 VIDEOS: { 275 VIDEOS: {
249 NAME: { min: 3, max: 120 }, // Length 276 NAME: { min: 3, max: 120 }, // Length
250 LANGUAGE: { min: 1, max: 10 }, // Length 277 LANGUAGE: { min: 1, max: 10 }, // Length
@@ -259,7 +286,7 @@ const CONSTRAINTS_FIELDS = {
259 }, 286 },
260 EXTNAME: [ '.mp4', '.ogv', '.webm' ], 287 EXTNAME: [ '.mp4', '.ogv', '.webm' ],
261 INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2 288 INFO_HASH: { min: 40, max: 40 }, // Length, info hash is 20 bytes length but we represent it in hexadecimal so 20 * 2
262 DURATION: { min: 1 }, // Number 289 DURATION: { min: 0 }, // Number
263 TAGS: { min: 0, max: 5 }, // Number of total tags 290 TAGS: { min: 0, max: 5 }, // Number of total tags
264 TAG: { min: 2, max: 30 }, // Length 291 TAG: { min: 2, max: 30 }, // Length
265 THUMBNAIL: { min: 2, max: 30 }, 292 THUMBNAIL: { min: 2, max: 30 },
@@ -313,6 +340,11 @@ const VIDEO_RATE_TYPES: { [ id: string ]: VideoRateType } = {
313 DISLIKE: 'dislike' 340 DISLIKE: 'dislike'
314} 341}
315 342
343const FFMPEG_NICE: { [ id: string ]: number } = {
344 THUMBNAIL: 2, // 2 just for don't blocking servers
345 TRANSCODING: 15
346}
347
316const VIDEO_CATEGORIES = { 348const VIDEO_CATEGORIES = {
317 1: 'Music', 349 1: 'Music',
318 2: 'Films', 350 2: 'Films',
@@ -355,7 +387,14 @@ const VIDEO_PRIVACIES = {
355 387
356const VIDEO_STATES = { 388const VIDEO_STATES = {
357 [VideoState.PUBLISHED]: 'Published', 389 [VideoState.PUBLISHED]: 'Published',
358 [VideoState.TO_TRANSCODE]: 'To transcode' 390 [VideoState.TO_TRANSCODE]: 'To transcode',
391 [VideoState.TO_IMPORT]: 'To import'
392}
393
394const VIDEO_IMPORT_STATES = {
395 [VideoImportState.FAILED]: 'Failed',
396 [VideoImportState.PENDING]: 'Pending',
397 [VideoImportState.SUCCESS]: 'Success'
359} 398}
360 399
361const VIDEO_MIMETYPE_EXT = { 400const VIDEO_MIMETYPE_EXT = {
@@ -553,6 +592,7 @@ export {
553 ROUTE_CACHE_LIFETIME, 592 ROUTE_CACHE_LIFETIME,
554 SORTABLE_COLUMNS, 593 SORTABLE_COLUMNS,
555 FEEDS, 594 FEEDS,
595 JOB_TTL,
556 NSFW_POLICY_TYPES, 596 NSFW_POLICY_TYPES,
557 STATIC_MAX_AGE, 597 STATIC_MAX_AGE,
558 STATIC_PATHS, 598 STATIC_PATHS,
@@ -567,8 +607,8 @@ export {
567 VIDEO_RATE_TYPES, 607 VIDEO_RATE_TYPES,
568 VIDEO_MIMETYPE_EXT, 608 VIDEO_MIMETYPE_EXT,
569 VIDEO_TRANSCODING_FPS, 609 VIDEO_TRANSCODING_FPS,
610 FFMPEG_NICE,
570 JOB_REQUEST_TIMEOUT, 611 JOB_REQUEST_TIMEOUT,
571 JOB_REQUEST_TTL,
572 USER_PASSWORD_RESET_LIFETIME, 612 USER_PASSWORD_RESET_LIFETIME,
573 IMAGE_MIMETYPE_EXT, 613 IMAGE_MIMETYPE_EXT,
574 SCHEDULER_INTERVALS_MS, 614 SCHEDULER_INTERVALS_MS,
@@ -576,6 +616,7 @@ export {
576 RATES_LIMIT, 616 RATES_LIMIT,
577 VIDEO_EXT_MIMETYPE, 617 VIDEO_EXT_MIMETYPE,
578 JOB_COMPLETED_LIFETIME, 618 JOB_COMPLETED_LIFETIME,
619 VIDEO_IMPORT_STATES,
579 VIDEO_VIEW_LIFETIME, 620 VIDEO_VIEW_LIFETIME,
580 buildLanguages 621 buildLanguages
581} 622}
diff --git a/server/initializers/database.ts b/server/initializers/database.ts
index 1a9ce5a61..0be752363 100644
--- a/server/initializers/database.ts
+++ b/server/initializers/database.ts
@@ -24,6 +24,7 @@ import { VideoTagModel } from '../models/video/video-tag'
24import { CONFIG } from './constants' 24import { CONFIG } from './constants'
25import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update' 25import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update'
26import { VideoCaptionModel } from '../models/video/video-caption' 26import { VideoCaptionModel } from '../models/video/video-caption'
27import { VideoImportModel } from '../models/video/video-import'
27 28
28require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string 29require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string
29 30
@@ -32,6 +33,7 @@ const username = CONFIG.DATABASE.USERNAME
32const password = CONFIG.DATABASE.PASSWORD 33const password = CONFIG.DATABASE.PASSWORD
33const host = CONFIG.DATABASE.HOSTNAME 34const host = CONFIG.DATABASE.HOSTNAME
34const port = CONFIG.DATABASE.PORT 35const port = CONFIG.DATABASE.PORT
36const poolMax = CONFIG.DATABASE.POOL.MAX
35 37
36const sequelizeTypescript = new SequelizeTypescript({ 38const sequelizeTypescript = new SequelizeTypescript({
37 database: dbname, 39 database: dbname,
@@ -40,6 +42,9 @@ const sequelizeTypescript = new SequelizeTypescript({
40 port, 42 port,
41 username, 43 username,
42 password, 44 password,
45 pool: {
46 max: poolMax
47 },
43 benchmark: isTestInstance(), 48 benchmark: isTestInstance(),
44 isolationLevel: SequelizeTypescript.Transaction.ISOLATION_LEVELS.SERIALIZABLE, 49 isolationLevel: SequelizeTypescript.Transaction.ISOLATION_LEVELS.SERIALIZABLE,
45 operatorsAliases: false, 50 operatorsAliases: false,
@@ -77,7 +82,8 @@ async function initDatabaseModels (silent: boolean) {
77 VideoTagModel, 82 VideoTagModel,
78 VideoModel, 83 VideoModel,
79 VideoCommentModel, 84 VideoCommentModel,
80 ScheduleVideoUpdateModel 85 ScheduleVideoUpdateModel,
86 VideoImportModel
81 ]) 87 ])
82 88
83 // Check extensions exist in the database 89 // Check extensions exist in the database