config.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746
  1. import bytes from 'bytes'
  2. import { IConfig } from 'config'
  3. import { createRequire } from 'module'
  4. import { dirname, join } from 'path'
  5. import {
  6. BroadcastMessageLevel,
  7. NSFWPolicyType,
  8. VideoPrivacyType,
  9. VideoRedundancyConfigFilter,
  10. VideosRedundancyStrategy
  11. } from '@peertube/peertube-models'
  12. import { decacheModule } from '@server/helpers/decache.js'
  13. import { buildPath, root } from '@peertube/peertube-node-utils'
  14. import { parseBytes, parseDurationToMs } from '../helpers/core-utils.js'
  15. const require = createRequire(import.meta.url)
  16. let config: IConfig = require('config')
  17. const configChangedHandlers: Function[] = []
  18. const CONFIG = {
  19. CUSTOM_FILE: getLocalConfigFilePath(),
  20. LISTEN: {
  21. PORT: config.get<number>('listen.port'),
  22. HOSTNAME: config.get<string>('listen.hostname')
  23. },
  24. SECRETS: {
  25. PEERTUBE: config.get<string>('secrets.peertube')
  26. },
  27. DATABASE: {
  28. DBNAME: config.has('database.name') ? config.get<string>('database.name') : 'peertube' + config.get<string>('database.suffix'),
  29. HOSTNAME: config.get<string>('database.hostname'),
  30. PORT: config.get<number>('database.port'),
  31. SSL: config.get<boolean>('database.ssl'),
  32. USERNAME: config.get<string>('database.username'),
  33. PASSWORD: config.get<string>('database.password'),
  34. POOL: {
  35. MAX: config.get<number>('database.pool.max')
  36. }
  37. },
  38. REDIS: {
  39. HOSTNAME: config.has('redis.hostname') ? config.get<string>('redis.hostname') : null,
  40. PORT: config.has('redis.port') ? config.get<number>('redis.port') : null,
  41. SOCKET: config.has('redis.socket') ? config.get<string>('redis.socket') : null,
  42. AUTH: config.has('redis.auth') ? config.get<string>('redis.auth') : null,
  43. DB: config.has('redis.db') ? config.get<number>('redis.db') : null,
  44. SENTINEL: {
  45. ENABLED: config.has('redis.sentinel.enabled') ? config.get<boolean>('redis.sentinel.enabled') : false,
  46. ENABLE_TLS: config.has('redis.sentinel.enable_tls') ? config.get<boolean>('redis.sentinel.enable_tls') : false,
  47. SENTINELS: config.has('redis.sentinel.sentinels') ? config.get<{ hostname: string, port: number }[]>('redis.sentinel.sentinels') : [],
  48. MASTER_NAME: config.has('redis.sentinel.master_name') ? config.get<string>('redis.sentinel.master_name') : null
  49. }
  50. },
  51. SMTP: {
  52. TRANSPORT: config.has('smtp.transport') ? config.get<string>('smtp.transport') : 'smtp',
  53. SENDMAIL: config.has('smtp.sendmail') ? config.get<string>('smtp.sendmail') : null,
  54. HOSTNAME: config.get<string>('smtp.hostname'),
  55. PORT: config.get<number>('smtp.port'),
  56. USERNAME: config.get<string>('smtp.username'),
  57. PASSWORD: config.get<string>('smtp.password'),
  58. TLS: config.get<boolean>('smtp.tls'),
  59. DISABLE_STARTTLS: config.get<boolean>('smtp.disable_starttls'),
  60. CA_FILE: config.get<string>('smtp.ca_file'),
  61. FROM_ADDRESS: config.get<string>('smtp.from_address')
  62. },
  63. EMAIL: {
  64. BODY: {
  65. SIGNATURE: config.get<string>('email.body.signature')
  66. },
  67. SUBJECT: {
  68. PREFIX: config.get<string>('email.subject.prefix') + ' '
  69. }
  70. },
  71. CLIENT: {
  72. VIDEOS: {
  73. MINIATURE: {
  74. get PREFER_AUTHOR_DISPLAY_NAME () { return config.get<boolean>('client.videos.miniature.prefer_author_display_name') },
  75. get DISPLAY_AUTHOR_AVATAR () { return config.get<boolean>('client.videos.miniature.display_author_avatar') }
  76. },
  77. RESUMABLE_UPLOAD: {
  78. get MAX_CHUNK_SIZE () { return parseBytes(config.get<number>('client.videos.resumable_upload.max_chunk_size') || 0) }
  79. }
  80. },
  81. MENU: {
  82. LOGIN: {
  83. get REDIRECT_ON_SINGLE_EXTERNAL_AUTH () { return config.get<boolean>('client.menu.login.redirect_on_single_external_auth') }
  84. }
  85. }
  86. },
  87. DEFAULTS: {
  88. PUBLISH: {
  89. DOWNLOAD_ENABLED: config.get<boolean>('defaults.publish.download_enabled'),
  90. COMMENTS_ENABLED: config.get<boolean>('defaults.publish.comments_enabled'),
  91. PRIVACY: config.get<VideoPrivacyType>('defaults.publish.privacy'),
  92. LICENCE: config.get<number>('defaults.publish.licence')
  93. },
  94. P2P: {
  95. WEBAPP: {
  96. ENABLED: config.get<boolean>('defaults.p2p.webapp.enabled')
  97. },
  98. EMBED: {
  99. ENABLED: config.get<boolean>('defaults.p2p.embed.enabled')
  100. }
  101. }
  102. },
  103. STORAGE: {
  104. TMP_DIR: buildPath(config.get<string>('storage.tmp')),
  105. TMP_PERSISTENT_DIR: buildPath(config.get<string>('storage.tmp_persistent')),
  106. BIN_DIR: buildPath(config.get<string>('storage.bin')),
  107. ACTOR_IMAGES_DIR: buildPath(config.get<string>('storage.avatars')),
  108. LOG_DIR: buildPath(config.get<string>('storage.logs')),
  109. WEB_VIDEOS_DIR: buildPath(config.get<string>('storage.web_videos')),
  110. STREAMING_PLAYLISTS_DIR: buildPath(config.get<string>('storage.streaming_playlists')),
  111. REDUNDANCY_DIR: buildPath(config.get<string>('storage.redundancy')),
  112. THUMBNAILS_DIR: buildPath(config.get<string>('storage.thumbnails')),
  113. STORYBOARDS_DIR: buildPath(config.get<string>('storage.storyboards')),
  114. PREVIEWS_DIR: buildPath(config.get<string>('storage.previews')),
  115. CAPTIONS_DIR: buildPath(config.get<string>('storage.captions')),
  116. TORRENTS_DIR: buildPath(config.get<string>('storage.torrents')),
  117. CACHE_DIR: buildPath(config.get<string>('storage.cache')),
  118. PLUGINS_DIR: buildPath(config.get<string>('storage.plugins')),
  119. CLIENT_OVERRIDES_DIR: buildPath(config.get<string>('storage.client_overrides')),
  120. WELL_KNOWN_DIR: buildPath(config.get<string>('storage.well_known'))
  121. },
  122. STATIC_FILES: {
  123. PRIVATE_FILES_REQUIRE_AUTH: config.get<boolean>('static_files.private_files_require_auth')
  124. },
  125. OBJECT_STORAGE: {
  126. ENABLED: config.get<boolean>('object_storage.enabled'),
  127. MAX_UPLOAD_PART: bytes.parse(config.get<string>('object_storage.max_upload_part')),
  128. ENDPOINT: config.get<string>('object_storage.endpoint'),
  129. REGION: config.get<string>('object_storage.region'),
  130. UPLOAD_ACL: {
  131. PUBLIC: config.get<string>('object_storage.upload_acl.public'),
  132. PRIVATE: config.get<string>('object_storage.upload_acl.private')
  133. },
  134. CREDENTIALS: {
  135. ACCESS_KEY_ID: config.get<string>('object_storage.credentials.access_key_id'),
  136. SECRET_ACCESS_KEY: config.get<string>('object_storage.credentials.secret_access_key')
  137. },
  138. PROXY: {
  139. PROXIFY_PRIVATE_FILES: config.get<boolean>('object_storage.proxy.proxify_private_files')
  140. },
  141. WEB_VIDEOS: {
  142. BUCKET_NAME: config.get<string>('object_storage.web_videos.bucket_name'),
  143. PREFIX: config.get<string>('object_storage.web_videos.prefix'),
  144. BASE_URL: config.get<string>('object_storage.web_videos.base_url')
  145. },
  146. STREAMING_PLAYLISTS: {
  147. BUCKET_NAME: config.get<string>('object_storage.streaming_playlists.bucket_name'),
  148. PREFIX: config.get<string>('object_storage.streaming_playlists.prefix'),
  149. BASE_URL: config.get<string>('object_storage.streaming_playlists.base_url'),
  150. STORE_LIVE_STREAMS: config.get<string>('object_storage.streaming_playlists.store_live_streams')
  151. },
  152. USER_EXPORTS: {
  153. BUCKET_NAME: config.get<string>('object_storage.user_exports.bucket_name'),
  154. PREFIX: config.get<string>('object_storage.user_exports.prefix'),
  155. BASE_URL: config.get<string>('object_storage.user_exports.base_url')
  156. }
  157. },
  158. WEBSERVER: {
  159. SCHEME: config.get<boolean>('webserver.https') === true ? 'https' : 'http',
  160. WS: config.get<boolean>('webserver.https') === true ? 'wss' : 'ws',
  161. HOSTNAME: config.get<string>('webserver.hostname'),
  162. PORT: config.get<number>('webserver.port')
  163. },
  164. OAUTH2: {
  165. TOKEN_LIFETIME: {
  166. ACCESS_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.access_token')),
  167. REFRESH_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.refresh_token'))
  168. }
  169. },
  170. RATES_LIMIT: {
  171. API: {
  172. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')),
  173. MAX: config.get<number>('rates_limit.api.max')
  174. },
  175. SIGNUP: {
  176. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.signup.window')),
  177. MAX: config.get<number>('rates_limit.signup.max')
  178. },
  179. LOGIN: {
  180. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.login.window')),
  181. MAX: config.get<number>('rates_limit.login.max')
  182. },
  183. RECEIVE_CLIENT_LOG: {
  184. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.receive_client_log.window')),
  185. MAX: config.get<number>('rates_limit.receive_client_log.max')
  186. },
  187. ASK_SEND_EMAIL: {
  188. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.ask_send_email.window')),
  189. MAX: config.get<number>('rates_limit.ask_send_email.max')
  190. },
  191. PLUGINS: {
  192. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.plugins.window')),
  193. MAX: config.get<number>('rates_limit.plugins.max')
  194. },
  195. WELL_KNOWN: {
  196. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.well_known.window')),
  197. MAX: config.get<number>('rates_limit.well_known.max')
  198. },
  199. FEEDS: {
  200. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.feeds.window')),
  201. MAX: config.get<number>('rates_limit.feeds.max')
  202. },
  203. ACTIVITY_PUB: {
  204. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.activity_pub.window')),
  205. MAX: config.get<number>('rates_limit.activity_pub.max')
  206. },
  207. CLIENT: {
  208. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.client.window')),
  209. MAX: config.get<number>('rates_limit.client.max')
  210. }
  211. },
  212. TRUST_PROXY: config.get<string[]>('trust_proxy'),
  213. LOG: {
  214. LEVEL: config.get<string>('log.level'),
  215. ROTATION: {
  216. ENABLED: config.get<boolean>('log.rotation.enabled'),
  217. MAX_FILE_SIZE: bytes.parse(config.get<string>('log.rotation.max_file_size')),
  218. MAX_FILES: config.get<number>('log.rotation.max_files')
  219. },
  220. ANONYMIZE_IP: config.get<boolean>('log.anonymize_ip'),
  221. LOG_PING_REQUESTS: config.get<boolean>('log.log_ping_requests'),
  222. LOG_TRACKER_UNKNOWN_INFOHASH: config.get<boolean>('log.log_tracker_unknown_infohash'),
  223. LOG_HTTP_REQUESTS: config.get<boolean>('log.log_http_requests'),
  224. PRETTIFY_SQL: config.get<boolean>('log.prettify_sql'),
  225. ACCEPT_CLIENT_LOG: config.get<boolean>('log.accept_client_log')
  226. },
  227. OPEN_TELEMETRY: {
  228. METRICS: {
  229. ENABLED: config.get<boolean>('open_telemetry.metrics.enabled'),
  230. PLAYBACK_STATS_INTERVAL: parseDurationToMs(config.get<string>('open_telemetry.metrics.playback_stats_interval')),
  231. HTTP_REQUEST_DURATION: {
  232. ENABLED: config.get<boolean>('open_telemetry.metrics.http_request_duration.enabled')
  233. },
  234. PROMETHEUS_EXPORTER: {
  235. HOSTNAME: config.get<string>('open_telemetry.metrics.prometheus_exporter.hostname'),
  236. PORT: config.get<number>('open_telemetry.metrics.prometheus_exporter.port')
  237. }
  238. },
  239. TRACING: {
  240. ENABLED: config.get<boolean>('open_telemetry.tracing.enabled'),
  241. JAEGER_EXPORTER: {
  242. ENDPOINT: config.get<string>('open_telemetry.tracing.jaeger_exporter.endpoint')
  243. }
  244. }
  245. },
  246. TRENDING: {
  247. VIDEOS: {
  248. INTERVAL_DAYS: config.get<number>('trending.videos.interval_days'),
  249. ALGORITHMS: {
  250. get ENABLED () { return config.get<string[]>('trending.videos.algorithms.enabled') },
  251. get DEFAULT () { return config.get<string>('trending.videos.algorithms.default') }
  252. }
  253. }
  254. },
  255. REDUNDANCY: {
  256. VIDEOS: {
  257. CHECK_INTERVAL: parseDurationToMs(config.get<string>('redundancy.videos.check_interval')),
  258. STRATEGIES: buildVideosRedundancy(config.get<any[]>('redundancy.videos.strategies'))
  259. }
  260. },
  261. REMOTE_REDUNDANCY: {
  262. VIDEOS: {
  263. ACCEPT_FROM: config.get<VideoRedundancyConfigFilter>('remote_redundancy.videos.accept_from')
  264. }
  265. },
  266. CSP: {
  267. ENABLED: config.get<boolean>('csp.enabled'),
  268. REPORT_ONLY: config.get<boolean>('csp.report_only'),
  269. REPORT_URI: config.get<string>('csp.report_uri')
  270. },
  271. SECURITY: {
  272. FRAMEGUARD: {
  273. ENABLED: config.get<boolean>('security.frameguard.enabled')
  274. },
  275. POWERED_BY_HEADER: {
  276. ENABLED: config.get<boolean>('security.powered_by_header.enabled')
  277. }
  278. },
  279. TRACKER: {
  280. ENABLED: config.get<boolean>('tracker.enabled'),
  281. PRIVATE: config.get<boolean>('tracker.private'),
  282. REJECT_TOO_MANY_ANNOUNCES: config.get<boolean>('tracker.reject_too_many_announces')
  283. },
  284. HISTORY: {
  285. VIDEOS: {
  286. MAX_AGE: parseDurationToMs(config.get('history.videos.max_age'))
  287. }
  288. },
  289. VIEWS: {
  290. VIDEOS: {
  291. REMOTE: {
  292. MAX_AGE: parseDurationToMs(config.get('views.videos.remote.max_age'))
  293. },
  294. LOCAL_BUFFER_UPDATE_INTERVAL: parseDurationToMs(config.get('views.videos.local_buffer_update_interval')),
  295. IP_VIEW_EXPIRATION: parseDurationToMs(config.get('views.videos.ip_view_expiration')),
  296. WATCHING_INTERVAL: {
  297. ANONYMOUS: parseDurationToMs(config.get<string>('views.videos.watching_interval.anonymous')),
  298. USERS: parseDurationToMs(config.get<string>('views.videos.watching_interval.users'))
  299. }
  300. }
  301. },
  302. GEO_IP: {
  303. ENABLED: config.get<boolean>('geo_ip.enabled'),
  304. COUNTRY: {
  305. DATABASE_URL: config.get<string>('geo_ip.country.database_url')
  306. },
  307. CITY: {
  308. DATABASE_URL: config.get<string>('geo_ip.city.database_url')
  309. }
  310. },
  311. PLUGINS: {
  312. INDEX: {
  313. ENABLED: config.get<boolean>('plugins.index.enabled'),
  314. CHECK_LATEST_VERSIONS_INTERVAL: parseDurationToMs(config.get<string>('plugins.index.check_latest_versions_interval')),
  315. URL: config.get<string>('plugins.index.url')
  316. }
  317. },
  318. FEDERATION: {
  319. VIDEOS: {
  320. FEDERATE_UNLISTED: config.get<boolean>('federation.videos.federate_unlisted'),
  321. CLEANUP_REMOTE_INTERACTIONS: config.get<boolean>('federation.videos.cleanup_remote_interactions')
  322. },
  323. SIGN_FEDERATED_FETCHES: config.get<boolean>('federation.sign_federated_fetches')
  324. },
  325. PEERTUBE: {
  326. CHECK_LATEST_VERSION: {
  327. ENABLED: config.get<boolean>('peertube.check_latest_version.enabled'),
  328. URL: config.get<string>('peertube.check_latest_version.url')
  329. }
  330. },
  331. WEBADMIN: {
  332. CONFIGURATION: {
  333. EDITION: {
  334. ALLOWED: config.get<boolean>('webadmin.configuration.edition.allowed')
  335. }
  336. }
  337. },
  338. FEEDS: {
  339. VIDEOS: {
  340. COUNT: config.get<number>('feeds.videos.count')
  341. },
  342. COMMENTS: {
  343. COUNT: config.get<number>('feeds.comments.count')
  344. }
  345. },
  346. REMOTE_RUNNERS: {
  347. STALLED_JOBS: {
  348. LIVE: parseDurationToMs(config.get<string>('remote_runners.stalled_jobs.live')),
  349. VOD: parseDurationToMs(config.get<string>('remote_runners.stalled_jobs.vod'))
  350. }
  351. },
  352. THUMBNAILS: {
  353. GENERATION_FROM_VIDEO: {
  354. FRAMES_TO_ANALYZE: config.get<number>('thumbnails.generation_from_video.frames_to_analyze')
  355. }
  356. },
  357. STATS: {
  358. REGISTRATION_REQUESTS: {
  359. ENABLED: config.get<boolean>('stats.registration_requests.enabled')
  360. },
  361. ABUSES: {
  362. ENABLED: config.get<boolean>('stats.abuses.enabled')
  363. },
  364. TOTAL_MODERATORS: {
  365. ENABLED: config.get<boolean>('stats.total_moderators.enabled')
  366. },
  367. TOTAL_ADMINS: {
  368. ENABLED: config.get<boolean>('stats.total_admins.enabled')
  369. }
  370. },
  371. ADMIN: {
  372. get EMAIL () { return config.get<string>('admin.email') }
  373. },
  374. CONTACT_FORM: {
  375. get ENABLED () { return config.get<boolean>('contact_form.enabled') }
  376. },
  377. SIGNUP: {
  378. get ENABLED () { return config.get<boolean>('signup.enabled') },
  379. get REQUIRES_APPROVAL () { return config.get<boolean>('signup.requires_approval') },
  380. get LIMIT () { return config.get<number>('signup.limit') },
  381. get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') },
  382. get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') },
  383. FILTERS: {
  384. CIDR: {
  385. get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },
  386. get BLACKLIST () { return config.get<string[]>('signup.filters.cidr.blacklist') }
  387. }
  388. }
  389. },
  390. USER: {
  391. HISTORY: {
  392. VIDEOS: {
  393. get ENABLED () { return config.get<boolean>('user.history.videos.enabled') }
  394. }
  395. },
  396. get VIDEO_QUOTA () { return parseBytes(config.get<number>('user.video_quota')) },
  397. get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) },
  398. get DEFAULT_CHANNEL_NAME () { return config.get<string>('user.default_channel_name') }
  399. },
  400. VIDEO_CHANNELS: {
  401. get MAX_PER_USER () { return config.get<number>('video_channels.max_per_user') }
  402. },
  403. TRANSCODING: {
  404. get ENABLED () { return config.get<boolean>('transcoding.enabled') },
  405. get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
  406. get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') },
  407. get THREADS () { return config.get<number>('transcoding.threads') },
  408. get CONCURRENCY () { return config.get<number>('transcoding.concurrency') },
  409. get PROFILE () { return config.get<string>('transcoding.profile') },
  410. get ALWAYS_TRANSCODE_ORIGINAL_RESOLUTION () { return config.get<boolean>('transcoding.always_transcode_original_resolution') },
  411. RESOLUTIONS: {
  412. get '0p' () { return config.get<boolean>('transcoding.resolutions.0p') },
  413. get '144p' () { return config.get<boolean>('transcoding.resolutions.144p') },
  414. get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') },
  415. get '360p' () { return config.get<boolean>('transcoding.resolutions.360p') },
  416. get '480p' () { return config.get<boolean>('transcoding.resolutions.480p') },
  417. get '720p' () { return config.get<boolean>('transcoding.resolutions.720p') },
  418. get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') },
  419. get '1440p' () { return config.get<boolean>('transcoding.resolutions.1440p') },
  420. get '2160p' () { return config.get<boolean>('transcoding.resolutions.2160p') }
  421. },
  422. HLS: {
  423. get ENABLED () { return config.get<boolean>('transcoding.hls.enabled') }
  424. },
  425. WEB_VIDEOS: {
  426. get ENABLED () { return config.get<boolean>('transcoding.web_videos.enabled') }
  427. },
  428. REMOTE_RUNNERS: {
  429. get ENABLED () { return config.get<boolean>('transcoding.remote_runners.enabled') }
  430. }
  431. },
  432. LIVE: {
  433. get ENABLED () { return config.get<boolean>('live.enabled') },
  434. get MAX_DURATION () { return parseDurationToMs(config.get<string>('live.max_duration')) },
  435. get MAX_INSTANCE_LIVES () { return config.get<number>('live.max_instance_lives') },
  436. get MAX_USER_LIVES () { return config.get<number>('live.max_user_lives') },
  437. get ALLOW_REPLAY () { return config.get<boolean>('live.allow_replay') },
  438. LATENCY_SETTING: {
  439. get ENABLED () { return config.get<boolean>('live.latency_setting.enabled') }
  440. },
  441. RTMP: {
  442. get ENABLED () { return config.get<boolean>('live.rtmp.enabled') },
  443. get PORT () { return config.get<number>('live.rtmp.port') },
  444. get HOSTNAME () { return config.get<number>('live.rtmp.hostname') },
  445. get PUBLIC_HOSTNAME () { return config.get<number>('live.rtmp.public_hostname') }
  446. },
  447. RTMPS: {
  448. get ENABLED () { return config.get<boolean>('live.rtmps.enabled') },
  449. get PORT () { return config.get<number>('live.rtmps.port') },
  450. get HOSTNAME () { return config.get<number>('live.rtmps.hostname') },
  451. get PUBLIC_HOSTNAME () { return config.get<number>('live.rtmps.public_hostname') },
  452. get KEY_FILE () { return config.get<string>('live.rtmps.key_file') },
  453. get CERT_FILE () { return config.get<string>('live.rtmps.cert_file') }
  454. },
  455. TRANSCODING: {
  456. get ENABLED () { return config.get<boolean>('live.transcoding.enabled') },
  457. get THREADS () { return config.get<number>('live.transcoding.threads') },
  458. get PROFILE () { return config.get<string>('live.transcoding.profile') },
  459. get ALWAYS_TRANSCODE_ORIGINAL_RESOLUTION () { return config.get<boolean>('live.transcoding.always_transcode_original_resolution') },
  460. RESOLUTIONS: {
  461. get '144p' () { return config.get<boolean>('live.transcoding.resolutions.144p') },
  462. get '240p' () { return config.get<boolean>('live.transcoding.resolutions.240p') },
  463. get '360p' () { return config.get<boolean>('live.transcoding.resolutions.360p') },
  464. get '480p' () { return config.get<boolean>('live.transcoding.resolutions.480p') },
  465. get '720p' () { return config.get<boolean>('live.transcoding.resolutions.720p') },
  466. get '1080p' () { return config.get<boolean>('live.transcoding.resolutions.1080p') },
  467. get '1440p' () { return config.get<boolean>('live.transcoding.resolutions.1440p') },
  468. get '2160p' () { return config.get<boolean>('live.transcoding.resolutions.2160p') }
  469. },
  470. REMOTE_RUNNERS: {
  471. get ENABLED () { return config.get<boolean>('live.transcoding.remote_runners.enabled') }
  472. }
  473. }
  474. },
  475. VIDEO_STUDIO: {
  476. get ENABLED () { return config.get<boolean>('video_studio.enabled') },
  477. REMOTE_RUNNERS: {
  478. get ENABLED () { return config.get<boolean>('video_studio.remote_runners.enabled') }
  479. }
  480. },
  481. VIDEO_FILE: {
  482. UPDATE: {
  483. get ENABLED () { return config.get<boolean>('video_file.update.enabled') }
  484. }
  485. },
  486. IMPORT: {
  487. VIDEOS: {
  488. get CONCURRENCY () { return config.get<number>('import.videos.concurrency') },
  489. get TIMEOUT () { return parseDurationToMs(config.get<string>('import.videos.timeout')) },
  490. HTTP: {
  491. get ENABLED () { return config.get<boolean>('import.videos.http.enabled') },
  492. YOUTUBE_DL_RELEASE: {
  493. get URL () { return config.get<string>('import.videos.http.youtube_dl_release.url') },
  494. get NAME () { return config.get<string>('import.videos.http.youtube_dl_release.name') },
  495. get PYTHON_PATH () { return config.get<string>('import.videos.http.youtube_dl_release.python_path') }
  496. },
  497. get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') }
  498. },
  499. TORRENT: {
  500. get ENABLED () { return config.get<boolean>('import.videos.torrent.enabled') }
  501. }
  502. },
  503. VIDEO_CHANNEL_SYNCHRONIZATION: {
  504. get ENABLED () { return config.get<boolean>('import.video_channel_synchronization.enabled') },
  505. get MAX_PER_USER () { return config.get<number>('import.video_channel_synchronization.max_per_user') },
  506. get CHECK_INTERVAL () { return parseDurationToMs(config.get<string>('import.video_channel_synchronization.check_interval')) },
  507. get VIDEOS_LIMIT_PER_SYNCHRONIZATION () {
  508. return config.get<number>('import.video_channel_synchronization.videos_limit_per_synchronization')
  509. },
  510. get FULL_SYNC_VIDEOS_LIMIT () {
  511. return config.get<number>('import.video_channel_synchronization.full_sync_videos_limit')
  512. }
  513. },
  514. USERS: {
  515. get ENABLED () { return config.get<boolean>('import.users.enabled') }
  516. }
  517. },
  518. EXPORT: {
  519. USERS: {
  520. get ENABLED () { return config.get<boolean>('export.users.enabled') },
  521. get MAX_USER_VIDEO_QUOTA () { return parseBytes(config.get<string>('export.users.max_user_video_quota')) },
  522. get EXPORT_EXPIRATION () { return parseDurationToMs(config.get<string>('export.users.export_expiration')) }
  523. }
  524. },
  525. AUTO_BLACKLIST: {
  526. VIDEOS: {
  527. OF_USERS: {
  528. get ENABLED () { return config.get<boolean>('auto_blacklist.videos.of_users.enabled') }
  529. }
  530. }
  531. },
  532. CACHE: {
  533. PREVIEWS: {
  534. get SIZE () { return config.get<number>('cache.previews.size') }
  535. },
  536. VIDEO_CAPTIONS: {
  537. get SIZE () { return config.get<number>('cache.captions.size') }
  538. },
  539. TORRENTS: {
  540. get SIZE () { return config.get<number>('cache.torrents.size') }
  541. },
  542. STORYBOARDS: {
  543. get SIZE () { return config.get<number>('cache.storyboards.size') }
  544. }
  545. },
  546. INSTANCE: {
  547. get NAME () { return config.get<string>('instance.name') },
  548. get SHORT_DESCRIPTION () { return config.get<string>('instance.short_description') },
  549. get DESCRIPTION () { return config.get<string>('instance.description') },
  550. get TERMS () { return config.get<string>('instance.terms') },
  551. get CODE_OF_CONDUCT () { return config.get<string>('instance.code_of_conduct') },
  552. get CREATION_REASON () { return config.get<string>('instance.creation_reason') },
  553. get MODERATION_INFORMATION () { return config.get<string>('instance.moderation_information') },
  554. get ADMINISTRATOR () { return config.get<string>('instance.administrator') },
  555. get MAINTENANCE_LIFETIME () { return config.get<string>('instance.maintenance_lifetime') },
  556. get BUSINESS_MODEL () { return config.get<string>('instance.business_model') },
  557. get HARDWARE_INFORMATION () { return config.get<string>('instance.hardware_information') },
  558. get LANGUAGES () { return config.get<string[]>('instance.languages') || [] },
  559. get CATEGORIES () { return config.get<number[]>('instance.categories') || [] },
  560. get IS_NSFW () { return config.get<boolean>('instance.is_nsfw') },
  561. get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') },
  562. get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') },
  563. CUSTOMIZATIONS: {
  564. get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') },
  565. get CSS () { return config.get<string>('instance.customizations.css') }
  566. },
  567. get ROBOTS () { return config.get<string>('instance.robots') },
  568. get SECURITYTXT () { return config.get<string>('instance.securitytxt') }
  569. },
  570. SERVICES: {
  571. TWITTER: {
  572. get USERNAME () { return config.get<string>('services.twitter.username') },
  573. get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') }
  574. }
  575. },
  576. FOLLOWERS: {
  577. INSTANCE: {
  578. get ENABLED () { return config.get<boolean>('followers.instance.enabled') },
  579. get MANUAL_APPROVAL () { return config.get<boolean>('followers.instance.manual_approval') }
  580. }
  581. },
  582. FOLLOWINGS: {
  583. INSTANCE: {
  584. AUTO_FOLLOW_BACK: {
  585. get ENABLED () {
  586. return config.get<boolean>('followings.instance.auto_follow_back.enabled')
  587. }
  588. },
  589. AUTO_FOLLOW_INDEX: {
  590. get ENABLED () {
  591. return config.get<boolean>('followings.instance.auto_follow_index.enabled')
  592. },
  593. get INDEX_URL () {
  594. return config.get<string>('followings.instance.auto_follow_index.index_url')
  595. }
  596. }
  597. }
  598. },
  599. THEME: {
  600. get DEFAULT () { return config.get<string>('theme.default') }
  601. },
  602. BROADCAST_MESSAGE: {
  603. get ENABLED () { return config.get<boolean>('broadcast_message.enabled') },
  604. get MESSAGE () { return config.get<string>('broadcast_message.message') },
  605. get LEVEL () { return config.get<BroadcastMessageLevel>('broadcast_message.level') },
  606. get DISMISSABLE () { return config.get<boolean>('broadcast_message.dismissable') }
  607. },
  608. SEARCH: {
  609. REMOTE_URI: {
  610. get USERS () { return config.get<boolean>('search.remote_uri.users') },
  611. get ANONYMOUS () { return config.get<boolean>('search.remote_uri.anonymous') }
  612. },
  613. SEARCH_INDEX: {
  614. get ENABLED () { return config.get<boolean>('search.search_index.enabled') },
  615. get URL () { return config.get<string>('search.search_index.url') },
  616. get DISABLE_LOCAL_SEARCH () { return config.get<boolean>('search.search_index.disable_local_search') },
  617. get IS_DEFAULT_SEARCH () { return config.get<boolean>('search.search_index.is_default_search') }
  618. }
  619. },
  620. STORYBOARDS: {
  621. get ENABLED () { return config.get<boolean>('storyboards.enabled') }
  622. }
  623. }
  624. function registerConfigChangedHandler (fun: Function) {
  625. configChangedHandlers.push(fun)
  626. }
  627. function isEmailEnabled () {
  628. if (CONFIG.SMTP.TRANSPORT === 'sendmail' && CONFIG.SMTP.SENDMAIL) return true
  629. if (CONFIG.SMTP.TRANSPORT === 'smtp' && CONFIG.SMTP.HOSTNAME && CONFIG.SMTP.PORT) return true
  630. return false
  631. }
  632. function getLocalConfigFilePath () {
  633. const localConfigDir = getLocalConfigDir()
  634. let filename = 'local'
  635. if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
  636. if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
  637. return join(localConfigDir, filename + '.json')
  638. }
  639. function getConfigModule () {
  640. return config
  641. }
  642. // ---------------------------------------------------------------------------
  643. export {
  644. CONFIG,
  645. getConfigModule,
  646. getLocalConfigFilePath,
  647. registerConfigChangedHandler,
  648. isEmailEnabled
  649. }
  650. // ---------------------------------------------------------------------------
  651. function getLocalConfigDir () {
  652. if (process.env.PEERTUBE_LOCAL_CONFIG) return process.env.PEERTUBE_LOCAL_CONFIG
  653. const configSources = config.util.getConfigSources()
  654. if (configSources.length === 0) throw new Error('Invalid config source.')
  655. return dirname(configSources[0].name)
  656. }
  657. function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] {
  658. if (!objs) return []
  659. if (!Array.isArray(objs)) return objs
  660. return objs.map(obj => {
  661. return Object.assign({}, obj, {
  662. minLifetime: parseDurationToMs(obj.min_lifetime),
  663. size: bytes.parse(obj.size),
  664. minViews: obj.min_views
  665. })
  666. })
  667. }
  668. export function reloadConfig () {
  669. function getConfigDirectories () {
  670. if (process.env.NODE_CONFIG_DIR) {
  671. return process.env.NODE_CONFIG_DIR.split(':')
  672. }
  673. return [ join(root(), 'config') ]
  674. }
  675. function purge () {
  676. const directories = getConfigDirectories()
  677. for (const fileName in require.cache) {
  678. if (directories.some((dir) => fileName.includes(dir)) === false) {
  679. continue
  680. }
  681. delete require.cache[fileName]
  682. }
  683. decacheModule(require, 'config')
  684. }
  685. purge()
  686. config = require('config')
  687. for (const configChangedHandler of configChangedHandlers) {
  688. configChangedHandler()
  689. }
  690. return Promise.resolve()
  691. }