config.ts 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731
  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. },
  151. USER_EXPORTS: {
  152. BUCKET_NAME: config.get<string>('object_storage.user_exports.bucket_name'),
  153. PREFIX: config.get<string>('object_storage.user_exports.prefix'),
  154. BASE_URL: config.get<string>('object_storage.user_exports.base_url')
  155. }
  156. },
  157. WEBSERVER: {
  158. SCHEME: config.get<boolean>('webserver.https') === true ? 'https' : 'http',
  159. WS: config.get<boolean>('webserver.https') === true ? 'wss' : 'ws',
  160. HOSTNAME: config.get<string>('webserver.hostname'),
  161. PORT: config.get<number>('webserver.port')
  162. },
  163. OAUTH2: {
  164. TOKEN_LIFETIME: {
  165. ACCESS_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.access_token')),
  166. REFRESH_TOKEN: parseDurationToMs(config.get<string>('oauth2.token_lifetime.refresh_token'))
  167. }
  168. },
  169. RATES_LIMIT: {
  170. API: {
  171. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.api.window')),
  172. MAX: config.get<number>('rates_limit.api.max')
  173. },
  174. SIGNUP: {
  175. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.signup.window')),
  176. MAX: config.get<number>('rates_limit.signup.max')
  177. },
  178. LOGIN: {
  179. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.login.window')),
  180. MAX: config.get<number>('rates_limit.login.max')
  181. },
  182. RECEIVE_CLIENT_LOG: {
  183. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.receive_client_log.window')),
  184. MAX: config.get<number>('rates_limit.receive_client_log.max')
  185. },
  186. ASK_SEND_EMAIL: {
  187. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.ask_send_email.window')),
  188. MAX: config.get<number>('rates_limit.ask_send_email.max')
  189. },
  190. PLUGINS: {
  191. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.plugins.window')),
  192. MAX: config.get<number>('rates_limit.plugins.max')
  193. },
  194. WELL_KNOWN: {
  195. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.well_known.window')),
  196. MAX: config.get<number>('rates_limit.well_known.max')
  197. },
  198. FEEDS: {
  199. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.feeds.window')),
  200. MAX: config.get<number>('rates_limit.feeds.max')
  201. },
  202. ACTIVITY_PUB: {
  203. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.activity_pub.window')),
  204. MAX: config.get<number>('rates_limit.activity_pub.max')
  205. },
  206. CLIENT: {
  207. WINDOW_MS: parseDurationToMs(config.get<string>('rates_limit.client.window')),
  208. MAX: config.get<number>('rates_limit.client.max')
  209. }
  210. },
  211. TRUST_PROXY: config.get<string[]>('trust_proxy'),
  212. LOG: {
  213. LEVEL: config.get<string>('log.level'),
  214. ROTATION: {
  215. ENABLED: config.get<boolean>('log.rotation.enabled'),
  216. MAX_FILE_SIZE: bytes.parse(config.get<string>('log.rotation.max_file_size')),
  217. MAX_FILES: config.get<number>('log.rotation.max_files')
  218. },
  219. ANONYMIZE_IP: config.get<boolean>('log.anonymize_ip'),
  220. LOG_PING_REQUESTS: config.get<boolean>('log.log_ping_requests'),
  221. LOG_TRACKER_UNKNOWN_INFOHASH: config.get<boolean>('log.log_tracker_unknown_infohash'),
  222. LOG_HTTP_REQUESTS: config.get<boolean>('log.log_http_requests'),
  223. PRETTIFY_SQL: config.get<boolean>('log.prettify_sql'),
  224. ACCEPT_CLIENT_LOG: config.get<boolean>('log.accept_client_log')
  225. },
  226. OPEN_TELEMETRY: {
  227. METRICS: {
  228. ENABLED: config.get<boolean>('open_telemetry.metrics.enabled'),
  229. PLAYBACK_STATS_INTERVAL: parseDurationToMs(config.get<string>('open_telemetry.metrics.playback_stats_interval')),
  230. HTTP_REQUEST_DURATION: {
  231. ENABLED: config.get<boolean>('open_telemetry.metrics.http_request_duration.enabled')
  232. },
  233. PROMETHEUS_EXPORTER: {
  234. HOSTNAME: config.get<string>('open_telemetry.metrics.prometheus_exporter.hostname'),
  235. PORT: config.get<number>('open_telemetry.metrics.prometheus_exporter.port')
  236. }
  237. },
  238. TRACING: {
  239. ENABLED: config.get<boolean>('open_telemetry.tracing.enabled'),
  240. JAEGER_EXPORTER: {
  241. ENDPOINT: config.get<string>('open_telemetry.tracing.jaeger_exporter.endpoint')
  242. }
  243. }
  244. },
  245. TRENDING: {
  246. VIDEOS: {
  247. INTERVAL_DAYS: config.get<number>('trending.videos.interval_days'),
  248. ALGORITHMS: {
  249. get ENABLED () { return config.get<string[]>('trending.videos.algorithms.enabled') },
  250. get DEFAULT () { return config.get<string>('trending.videos.algorithms.default') }
  251. }
  252. }
  253. },
  254. REDUNDANCY: {
  255. VIDEOS: {
  256. CHECK_INTERVAL: parseDurationToMs(config.get<string>('redundancy.videos.check_interval')),
  257. STRATEGIES: buildVideosRedundancy(config.get<any[]>('redundancy.videos.strategies'))
  258. }
  259. },
  260. REMOTE_REDUNDANCY: {
  261. VIDEOS: {
  262. ACCEPT_FROM: config.get<VideoRedundancyConfigFilter>('remote_redundancy.videos.accept_from')
  263. }
  264. },
  265. CSP: {
  266. ENABLED: config.get<boolean>('csp.enabled'),
  267. REPORT_ONLY: config.get<boolean>('csp.report_only'),
  268. REPORT_URI: config.get<string>('csp.report_uri')
  269. },
  270. SECURITY: {
  271. FRAMEGUARD: {
  272. ENABLED: config.get<boolean>('security.frameguard.enabled')
  273. },
  274. POWERED_BY_HEADER: {
  275. ENABLED: config.get<boolean>('security.powered_by_header.enabled')
  276. }
  277. },
  278. TRACKER: {
  279. ENABLED: config.get<boolean>('tracker.enabled'),
  280. PRIVATE: config.get<boolean>('tracker.private'),
  281. REJECT_TOO_MANY_ANNOUNCES: config.get<boolean>('tracker.reject_too_many_announces')
  282. },
  283. HISTORY: {
  284. VIDEOS: {
  285. MAX_AGE: parseDurationToMs(config.get('history.videos.max_age'))
  286. }
  287. },
  288. VIEWS: {
  289. VIDEOS: {
  290. REMOTE: {
  291. MAX_AGE: parseDurationToMs(config.get('views.videos.remote.max_age'))
  292. },
  293. LOCAL_BUFFER_UPDATE_INTERVAL: parseDurationToMs(config.get('views.videos.local_buffer_update_interval')),
  294. IP_VIEW_EXPIRATION: parseDurationToMs(config.get('views.videos.ip_view_expiration')),
  295. WATCHING_INTERVAL: {
  296. ANONYMOUS: parseDurationToMs(config.get<string>('views.videos.watching_interval.anonymous')),
  297. USERS: parseDurationToMs(config.get<string>('views.videos.watching_interval.users'))
  298. }
  299. }
  300. },
  301. GEO_IP: {
  302. ENABLED: config.get<boolean>('geo_ip.enabled'),
  303. COUNTRY: {
  304. DATABASE_URL: config.get<string>('geo_ip.country.database_url')
  305. },
  306. CITY: {
  307. DATABASE_URL: config.get<string>('geo_ip.city.database_url')
  308. }
  309. },
  310. PLUGINS: {
  311. INDEX: {
  312. ENABLED: config.get<boolean>('plugins.index.enabled'),
  313. CHECK_LATEST_VERSIONS_INTERVAL: parseDurationToMs(config.get<string>('plugins.index.check_latest_versions_interval')),
  314. URL: config.get<string>('plugins.index.url')
  315. }
  316. },
  317. FEDERATION: {
  318. VIDEOS: {
  319. FEDERATE_UNLISTED: config.get<boolean>('federation.videos.federate_unlisted'),
  320. CLEANUP_REMOTE_INTERACTIONS: config.get<boolean>('federation.videos.cleanup_remote_interactions')
  321. },
  322. SIGN_FEDERATED_FETCHES: config.get<boolean>('federation.sign_federated_fetches')
  323. },
  324. PEERTUBE: {
  325. CHECK_LATEST_VERSION: {
  326. ENABLED: config.get<boolean>('peertube.check_latest_version.enabled'),
  327. URL: config.get<string>('peertube.check_latest_version.url')
  328. }
  329. },
  330. WEBADMIN: {
  331. CONFIGURATION: {
  332. EDITION: {
  333. ALLOWED: config.get<boolean>('webadmin.configuration.edition.allowed')
  334. }
  335. }
  336. },
  337. FEEDS: {
  338. VIDEOS: {
  339. COUNT: config.get<number>('feeds.videos.count')
  340. },
  341. COMMENTS: {
  342. COUNT: config.get<number>('feeds.comments.count')
  343. }
  344. },
  345. REMOTE_RUNNERS: {
  346. STALLED_JOBS: {
  347. LIVE: parseDurationToMs(config.get<string>('remote_runners.stalled_jobs.live')),
  348. VOD: parseDurationToMs(config.get<string>('remote_runners.stalled_jobs.vod'))
  349. }
  350. },
  351. THUMBNAILS: {
  352. GENERATION_FROM_VIDEO: {
  353. FRAMES_TO_ANALYZE: config.get<number>('thumbnails.generation_from_video.frames_to_analyze')
  354. }
  355. },
  356. ADMIN: {
  357. get EMAIL () { return config.get<string>('admin.email') }
  358. },
  359. CONTACT_FORM: {
  360. get ENABLED () { return config.get<boolean>('contact_form.enabled') }
  361. },
  362. SIGNUP: {
  363. get ENABLED () { return config.get<boolean>('signup.enabled') },
  364. get REQUIRES_APPROVAL () { return config.get<boolean>('signup.requires_approval') },
  365. get LIMIT () { return config.get<number>('signup.limit') },
  366. get REQUIRES_EMAIL_VERIFICATION () { return config.get<boolean>('signup.requires_email_verification') },
  367. get MINIMUM_AGE () { return config.get<number>('signup.minimum_age') },
  368. FILTERS: {
  369. CIDR: {
  370. get WHITELIST () { return config.get<string[]>('signup.filters.cidr.whitelist') },
  371. get BLACKLIST () { return config.get<string[]>('signup.filters.cidr.blacklist') }
  372. }
  373. }
  374. },
  375. USER: {
  376. HISTORY: {
  377. VIDEOS: {
  378. get ENABLED () { return config.get<boolean>('user.history.videos.enabled') }
  379. }
  380. },
  381. get VIDEO_QUOTA () { return parseBytes(config.get<number>('user.video_quota')) },
  382. get VIDEO_QUOTA_DAILY () { return parseBytes(config.get<number>('user.video_quota_daily')) },
  383. get DEFAULT_CHANNEL_NAME () { return config.get<string>('user.default_channel_name') }
  384. },
  385. VIDEO_CHANNELS: {
  386. get MAX_PER_USER () { return config.get<number>('video_channels.max_per_user') }
  387. },
  388. TRANSCODING: {
  389. get ENABLED () { return config.get<boolean>('transcoding.enabled') },
  390. get ALLOW_ADDITIONAL_EXTENSIONS () { return config.get<boolean>('transcoding.allow_additional_extensions') },
  391. get ALLOW_AUDIO_FILES () { return config.get<boolean>('transcoding.allow_audio_files') },
  392. get THREADS () { return config.get<number>('transcoding.threads') },
  393. get CONCURRENCY () { return config.get<number>('transcoding.concurrency') },
  394. get PROFILE () { return config.get<string>('transcoding.profile') },
  395. get ALWAYS_TRANSCODE_ORIGINAL_RESOLUTION () { return config.get<boolean>('transcoding.always_transcode_original_resolution') },
  396. RESOLUTIONS: {
  397. get '0p' () { return config.get<boolean>('transcoding.resolutions.0p') },
  398. get '144p' () { return config.get<boolean>('transcoding.resolutions.144p') },
  399. get '240p' () { return config.get<boolean>('transcoding.resolutions.240p') },
  400. get '360p' () { return config.get<boolean>('transcoding.resolutions.360p') },
  401. get '480p' () { return config.get<boolean>('transcoding.resolutions.480p') },
  402. get '720p' () { return config.get<boolean>('transcoding.resolutions.720p') },
  403. get '1080p' () { return config.get<boolean>('transcoding.resolutions.1080p') },
  404. get '1440p' () { return config.get<boolean>('transcoding.resolutions.1440p') },
  405. get '2160p' () { return config.get<boolean>('transcoding.resolutions.2160p') }
  406. },
  407. HLS: {
  408. get ENABLED () { return config.get<boolean>('transcoding.hls.enabled') }
  409. },
  410. WEB_VIDEOS: {
  411. get ENABLED () { return config.get<boolean>('transcoding.web_videos.enabled') }
  412. },
  413. REMOTE_RUNNERS: {
  414. get ENABLED () { return config.get<boolean>('transcoding.remote_runners.enabled') }
  415. }
  416. },
  417. LIVE: {
  418. get ENABLED () { return config.get<boolean>('live.enabled') },
  419. get MAX_DURATION () { return parseDurationToMs(config.get<string>('live.max_duration')) },
  420. get MAX_INSTANCE_LIVES () { return config.get<number>('live.max_instance_lives') },
  421. get MAX_USER_LIVES () { return config.get<number>('live.max_user_lives') },
  422. get ALLOW_REPLAY () { return config.get<boolean>('live.allow_replay') },
  423. LATENCY_SETTING: {
  424. get ENABLED () { return config.get<boolean>('live.latency_setting.enabled') }
  425. },
  426. RTMP: {
  427. get ENABLED () { return config.get<boolean>('live.rtmp.enabled') },
  428. get PORT () { return config.get<number>('live.rtmp.port') },
  429. get HOSTNAME () { return config.get<number>('live.rtmp.hostname') },
  430. get PUBLIC_HOSTNAME () { return config.get<number>('live.rtmp.public_hostname') }
  431. },
  432. RTMPS: {
  433. get ENABLED () { return config.get<boolean>('live.rtmps.enabled') },
  434. get PORT () { return config.get<number>('live.rtmps.port') },
  435. get HOSTNAME () { return config.get<number>('live.rtmps.hostname') },
  436. get PUBLIC_HOSTNAME () { return config.get<number>('live.rtmps.public_hostname') },
  437. get KEY_FILE () { return config.get<string>('live.rtmps.key_file') },
  438. get CERT_FILE () { return config.get<string>('live.rtmps.cert_file') }
  439. },
  440. TRANSCODING: {
  441. get ENABLED () { return config.get<boolean>('live.transcoding.enabled') },
  442. get THREADS () { return config.get<number>('live.transcoding.threads') },
  443. get PROFILE () { return config.get<string>('live.transcoding.profile') },
  444. get ALWAYS_TRANSCODE_ORIGINAL_RESOLUTION () { return config.get<boolean>('live.transcoding.always_transcode_original_resolution') },
  445. RESOLUTIONS: {
  446. get '144p' () { return config.get<boolean>('live.transcoding.resolutions.144p') },
  447. get '240p' () { return config.get<boolean>('live.transcoding.resolutions.240p') },
  448. get '360p' () { return config.get<boolean>('live.transcoding.resolutions.360p') },
  449. get '480p' () { return config.get<boolean>('live.transcoding.resolutions.480p') },
  450. get '720p' () { return config.get<boolean>('live.transcoding.resolutions.720p') },
  451. get '1080p' () { return config.get<boolean>('live.transcoding.resolutions.1080p') },
  452. get '1440p' () { return config.get<boolean>('live.transcoding.resolutions.1440p') },
  453. get '2160p' () { return config.get<boolean>('live.transcoding.resolutions.2160p') }
  454. },
  455. REMOTE_RUNNERS: {
  456. get ENABLED () { return config.get<boolean>('live.transcoding.remote_runners.enabled') }
  457. }
  458. }
  459. },
  460. VIDEO_STUDIO: {
  461. get ENABLED () { return config.get<boolean>('video_studio.enabled') },
  462. REMOTE_RUNNERS: {
  463. get ENABLED () { return config.get<boolean>('video_studio.remote_runners.enabled') }
  464. }
  465. },
  466. VIDEO_FILE: {
  467. UPDATE: {
  468. get ENABLED () { return config.get<boolean>('video_file.update.enabled') }
  469. }
  470. },
  471. IMPORT: {
  472. VIDEOS: {
  473. get CONCURRENCY () { return config.get<number>('import.videos.concurrency') },
  474. get TIMEOUT () { return parseDurationToMs(config.get<string>('import.videos.timeout')) },
  475. HTTP: {
  476. get ENABLED () { return config.get<boolean>('import.videos.http.enabled') },
  477. YOUTUBE_DL_RELEASE: {
  478. get URL () { return config.get<string>('import.videos.http.youtube_dl_release.url') },
  479. get NAME () { return config.get<string>('import.videos.http.youtube_dl_release.name') },
  480. get PYTHON_PATH () { return config.get<string>('import.videos.http.youtube_dl_release.python_path') }
  481. },
  482. get FORCE_IPV4 () { return config.get<boolean>('import.videos.http.force_ipv4') }
  483. },
  484. TORRENT: {
  485. get ENABLED () { return config.get<boolean>('import.videos.torrent.enabled') }
  486. }
  487. },
  488. VIDEO_CHANNEL_SYNCHRONIZATION: {
  489. get ENABLED () { return config.get<boolean>('import.video_channel_synchronization.enabled') },
  490. get MAX_PER_USER () { return config.get<number>('import.video_channel_synchronization.max_per_user') },
  491. get CHECK_INTERVAL () { return parseDurationToMs(config.get<string>('import.video_channel_synchronization.check_interval')) },
  492. get VIDEOS_LIMIT_PER_SYNCHRONIZATION () {
  493. return config.get<number>('import.video_channel_synchronization.videos_limit_per_synchronization')
  494. },
  495. get FULL_SYNC_VIDEOS_LIMIT () {
  496. return config.get<number>('import.video_channel_synchronization.full_sync_videos_limit')
  497. }
  498. },
  499. USERS: {
  500. get ENABLED () { return config.get<boolean>('import.users.enabled') }
  501. }
  502. },
  503. EXPORT: {
  504. USERS: {
  505. get ENABLED () { return config.get<boolean>('export.users.enabled') },
  506. get MAX_USER_VIDEO_QUOTA () { return parseBytes(config.get<string>('export.users.max_user_video_quota')) },
  507. get EXPORT_EXPIRATION () { return parseDurationToMs(config.get<string>('export.users.export_expiration')) }
  508. }
  509. },
  510. AUTO_BLACKLIST: {
  511. VIDEOS: {
  512. OF_USERS: {
  513. get ENABLED () { return config.get<boolean>('auto_blacklist.videos.of_users.enabled') }
  514. }
  515. }
  516. },
  517. CACHE: {
  518. PREVIEWS: {
  519. get SIZE () { return config.get<number>('cache.previews.size') }
  520. },
  521. VIDEO_CAPTIONS: {
  522. get SIZE () { return config.get<number>('cache.captions.size') }
  523. },
  524. TORRENTS: {
  525. get SIZE () { return config.get<number>('cache.torrents.size') }
  526. },
  527. STORYBOARDS: {
  528. get SIZE () { return config.get<number>('cache.storyboards.size') }
  529. }
  530. },
  531. INSTANCE: {
  532. get NAME () { return config.get<string>('instance.name') },
  533. get SHORT_DESCRIPTION () { return config.get<string>('instance.short_description') },
  534. get DESCRIPTION () { return config.get<string>('instance.description') },
  535. get TERMS () { return config.get<string>('instance.terms') },
  536. get CODE_OF_CONDUCT () { return config.get<string>('instance.code_of_conduct') },
  537. get CREATION_REASON () { return config.get<string>('instance.creation_reason') },
  538. get MODERATION_INFORMATION () { return config.get<string>('instance.moderation_information') },
  539. get ADMINISTRATOR () { return config.get<string>('instance.administrator') },
  540. get MAINTENANCE_LIFETIME () { return config.get<string>('instance.maintenance_lifetime') },
  541. get BUSINESS_MODEL () { return config.get<string>('instance.business_model') },
  542. get HARDWARE_INFORMATION () { return config.get<string>('instance.hardware_information') },
  543. get LANGUAGES () { return config.get<string[]>('instance.languages') || [] },
  544. get CATEGORIES () { return config.get<number[]>('instance.categories') || [] },
  545. get IS_NSFW () { return config.get<boolean>('instance.is_nsfw') },
  546. get DEFAULT_NSFW_POLICY () { return config.get<NSFWPolicyType>('instance.default_nsfw_policy') },
  547. get DEFAULT_CLIENT_ROUTE () { return config.get<string>('instance.default_client_route') },
  548. CUSTOMIZATIONS: {
  549. get JAVASCRIPT () { return config.get<string>('instance.customizations.javascript') },
  550. get CSS () { return config.get<string>('instance.customizations.css') }
  551. },
  552. get ROBOTS () { return config.get<string>('instance.robots') },
  553. get SECURITYTXT () { return config.get<string>('instance.securitytxt') }
  554. },
  555. SERVICES: {
  556. TWITTER: {
  557. get USERNAME () { return config.get<string>('services.twitter.username') },
  558. get WHITELISTED () { return config.get<boolean>('services.twitter.whitelisted') }
  559. }
  560. },
  561. FOLLOWERS: {
  562. INSTANCE: {
  563. get ENABLED () { return config.get<boolean>('followers.instance.enabled') },
  564. get MANUAL_APPROVAL () { return config.get<boolean>('followers.instance.manual_approval') }
  565. }
  566. },
  567. FOLLOWINGS: {
  568. INSTANCE: {
  569. AUTO_FOLLOW_BACK: {
  570. get ENABLED () {
  571. return config.get<boolean>('followings.instance.auto_follow_back.enabled')
  572. }
  573. },
  574. AUTO_FOLLOW_INDEX: {
  575. get ENABLED () {
  576. return config.get<boolean>('followings.instance.auto_follow_index.enabled')
  577. },
  578. get INDEX_URL () {
  579. return config.get<string>('followings.instance.auto_follow_index.index_url')
  580. }
  581. }
  582. }
  583. },
  584. THEME: {
  585. get DEFAULT () { return config.get<string>('theme.default') }
  586. },
  587. BROADCAST_MESSAGE: {
  588. get ENABLED () { return config.get<boolean>('broadcast_message.enabled') },
  589. get MESSAGE () { return config.get<string>('broadcast_message.message') },
  590. get LEVEL () { return config.get<BroadcastMessageLevel>('broadcast_message.level') },
  591. get DISMISSABLE () { return config.get<boolean>('broadcast_message.dismissable') }
  592. },
  593. SEARCH: {
  594. REMOTE_URI: {
  595. get USERS () { return config.get<boolean>('search.remote_uri.users') },
  596. get ANONYMOUS () { return config.get<boolean>('search.remote_uri.anonymous') }
  597. },
  598. SEARCH_INDEX: {
  599. get ENABLED () { return config.get<boolean>('search.search_index.enabled') },
  600. get URL () { return config.get<string>('search.search_index.url') },
  601. get DISABLE_LOCAL_SEARCH () { return config.get<boolean>('search.search_index.disable_local_search') },
  602. get IS_DEFAULT_SEARCH () { return config.get<boolean>('search.search_index.is_default_search') }
  603. }
  604. },
  605. STORYBOARDS: {
  606. get ENABLED () { return config.get<boolean>('storyboards.enabled') }
  607. }
  608. }
  609. function registerConfigChangedHandler (fun: Function) {
  610. configChangedHandlers.push(fun)
  611. }
  612. function isEmailEnabled () {
  613. if (CONFIG.SMTP.TRANSPORT === 'sendmail' && CONFIG.SMTP.SENDMAIL) return true
  614. if (CONFIG.SMTP.TRANSPORT === 'smtp' && CONFIG.SMTP.HOSTNAME && CONFIG.SMTP.PORT) return true
  615. return false
  616. }
  617. function getLocalConfigFilePath () {
  618. const localConfigDir = getLocalConfigDir()
  619. let filename = 'local'
  620. if (process.env.NODE_ENV) filename += `-${process.env.NODE_ENV}`
  621. if (process.env.NODE_APP_INSTANCE) filename += `-${process.env.NODE_APP_INSTANCE}`
  622. return join(localConfigDir, filename + '.json')
  623. }
  624. function getConfigModule () {
  625. return config
  626. }
  627. // ---------------------------------------------------------------------------
  628. export {
  629. CONFIG,
  630. getConfigModule,
  631. getLocalConfigFilePath,
  632. registerConfigChangedHandler,
  633. isEmailEnabled
  634. }
  635. // ---------------------------------------------------------------------------
  636. function getLocalConfigDir () {
  637. if (process.env.PEERTUBE_LOCAL_CONFIG) return process.env.PEERTUBE_LOCAL_CONFIG
  638. const configSources = config.util.getConfigSources()
  639. if (configSources.length === 0) throw new Error('Invalid config source.')
  640. return dirname(configSources[0].name)
  641. }
  642. function buildVideosRedundancy (objs: any[]): VideosRedundancyStrategy[] {
  643. if (!objs) return []
  644. if (!Array.isArray(objs)) return objs
  645. return objs.map(obj => {
  646. return Object.assign({}, obj, {
  647. minLifetime: parseDurationToMs(obj.min_lifetime),
  648. size: bytes.parse(obj.size),
  649. minViews: obj.min_views
  650. })
  651. })
  652. }
  653. export function reloadConfig () {
  654. function getConfigDirectories () {
  655. if (process.env.NODE_CONFIG_DIR) {
  656. return process.env.NODE_CONFIG_DIR.split(':')
  657. }
  658. return [ join(root(), 'config') ]
  659. }
  660. function purge () {
  661. const directories = getConfigDirectories()
  662. for (const fileName in require.cache) {
  663. if (directories.some((dir) => fileName.includes(dir)) === false) {
  664. continue
  665. }
  666. delete require.cache[fileName]
  667. }
  668. decacheModule(require, 'config')
  669. }
  670. purge()
  671. config = require('config')
  672. for (const configChangedHandler of configChangedHandlers) {
  673. configChangedHandler()
  674. }
  675. return Promise.resolve()
  676. }