diff options
Diffstat (limited to 'server/initializers')
-rw-r--r-- | server/initializers/checker.ts | 31 | ||||
-rw-r--r-- | server/initializers/constants.ts | 53 | ||||
-rw-r--r-- | server/initializers/database.ts | 8 |
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 () { | |||
84 | async function checkFFmpeg (CONFIG: { TRANSCODING: { ENABLED: boolean } }) { | 85 | async 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 | ||
108 | let supportedOptionalEncoders: Map<string, boolean> | ||
109 | async 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 () { | |||
126 | export { | 150 | export { |
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' | |||
8 | import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' | 8 | import { buildPath, isTestInstance, root, sanitizeHost, sanitizeUrl } from '../helpers/core-utils' |
9 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' | 9 | import { NSFWPolicyType } from '../../shared/models/videos/nsfw-policy.type' |
10 | import { invert } from 'lodash' | 10 | import { invert } from 'lodash' |
11 | import { 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 |
13 | let config: IConfig = require('config') | 14 | let 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 | } |
90 | const JOB_CONCURRENCY: { [ id in JobType ]: number } = { | 93 | const 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 | } |
103 | const 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 | } | ||
99 | const BROADCAST_CONCURRENCY = 10 // How many requests in parallel we do in activitypub-http-broadcast job | 113 | const BROADCAST_CONCURRENCY = 10 // How many requests in parallel we do in activitypub-http-broadcast job |
100 | const JOB_REQUEST_TIMEOUT = 3000 // 3 seconds | 114 | const JOB_REQUEST_TIMEOUT = 3000 // 3 seconds |
101 | const JOB_REQUEST_TTL = 60000 * 10 // 10 minutes | ||
102 | const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days | 115 | const JOB_COMPLETED_LIFETIME = 60000 * 60 * 24 * 2 // 2 days |
103 | 116 | ||
104 | // 1 hour | 117 | // 1 hour |
105 | let SCHEDULER_INTERVALS_MS = { | 118 | let 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 | ||
343 | const FFMPEG_NICE: { [ id: string ]: number } = { | ||
344 | THUMBNAIL: 2, // 2 just for don't blocking servers | ||
345 | TRANSCODING: 15 | ||
346 | } | ||
347 | |||
316 | const VIDEO_CATEGORIES = { | 348 | const VIDEO_CATEGORIES = { |
317 | 1: 'Music', | 349 | 1: 'Music', |
318 | 2: 'Films', | 350 | 2: 'Films', |
@@ -355,7 +387,14 @@ const VIDEO_PRIVACIES = { | |||
355 | 387 | ||
356 | const VIDEO_STATES = { | 388 | const 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 | |||
394 | const VIDEO_IMPORT_STATES = { | ||
395 | [VideoImportState.FAILED]: 'Failed', | ||
396 | [VideoImportState.PENDING]: 'Pending', | ||
397 | [VideoImportState.SUCCESS]: 'Success' | ||
359 | } | 398 | } |
360 | 399 | ||
361 | const VIDEO_MIMETYPE_EXT = { | 400 | const 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' | |||
24 | import { CONFIG } from './constants' | 24 | import { CONFIG } from './constants' |
25 | import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update' | 25 | import { ScheduleVideoUpdateModel } from '../models/video/schedule-video-update' |
26 | import { VideoCaptionModel } from '../models/video/video-caption' | 26 | import { VideoCaptionModel } from '../models/video/video-caption' |
27 | import { VideoImportModel } from '../models/video/video-import' | ||
27 | 28 | ||
28 | require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string | 29 | require('pg').defaults.parseInt8 = true // Avoid BIGINT to be converted to string |
29 | 30 | ||
@@ -32,6 +33,7 @@ const username = CONFIG.DATABASE.USERNAME | |||
32 | const password = CONFIG.DATABASE.PASSWORD | 33 | const password = CONFIG.DATABASE.PASSWORD |
33 | const host = CONFIG.DATABASE.HOSTNAME | 34 | const host = CONFIG.DATABASE.HOSTNAME |
34 | const port = CONFIG.DATABASE.PORT | 35 | const port = CONFIG.DATABASE.PORT |
36 | const poolMax = CONFIG.DATABASE.POOL.MAX | ||
35 | 37 | ||
36 | const sequelizeTypescript = new SequelizeTypescript({ | 38 | const 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 |