ニジカ投稿局 https://tv.nizika.tv
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

771 lines
31 KiB

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