ニジカ投稿局 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.

server-config-manager.ts 13 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. import {
  2. HTMLServerConfig,
  3. RegisteredExternalAuthConfig,
  4. RegisteredIdAndPassAuthConfig,
  5. ServerConfig,
  6. VideoCommentPolicy,
  7. VideoResolutionType
  8. } from '@peertube/peertube-models'
  9. import { getServerCommit } from '@server/helpers/version.js'
  10. import { CONFIG, isEmailEnabled } from '@server/initializers/config.js'
  11. import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants.js'
  12. import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/lib/signup.js'
  13. import { ActorCustomPageModel } from '@server/models/account/actor-custom-page.js'
  14. import { getServerActor } from '@server/models/application/application.js'
  15. import { PluginModel } from '@server/models/server/plugin.js'
  16. import { Hooks } from './plugins/hooks.js'
  17. import { PluginManager } from './plugins/plugin-manager.js'
  18. import { getThemeOrDefault } from './plugins/theme-utils.js'
  19. import { VideoTranscodingProfilesManager } from './transcoding/default-transcoding-profiles.js'
  20. /**
  21. *
  22. * Used to send the server config to clients (using REST/API or plugins API)
  23. * We need a singleton class to manage config state depending on external events (to build menu entries etc)
  24. *
  25. */
  26. class ServerConfigManager {
  27. private static instance: ServerConfigManager
  28. private serverCommit: string
  29. private homepageEnabled = false
  30. private constructor () {}
  31. async init () {
  32. const instanceHomepage = await ActorCustomPageModel.loadInstanceHomepage()
  33. this.updateHomepageState(instanceHomepage?.content)
  34. }
  35. updateHomepageState (content: string) {
  36. this.homepageEnabled = !!content
  37. }
  38. async getHTMLServerConfig (): Promise<HTMLServerConfig> {
  39. if (this.serverCommit === undefined) this.serverCommit = await getServerCommit()
  40. const serverActor = await getServerActor()
  41. const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
  42. return {
  43. client: {
  44. videos: {
  45. miniature: {
  46. displayAuthorAvatar: CONFIG.CLIENT.VIDEOS.MINIATURE.DISPLAY_AUTHOR_AVATAR,
  47. preferAuthorDisplayName: CONFIG.CLIENT.VIDEOS.MINIATURE.PREFER_AUTHOR_DISPLAY_NAME
  48. },
  49. resumableUpload: {
  50. maxChunkSize: CONFIG.CLIENT.VIDEOS.RESUMABLE_UPLOAD.MAX_CHUNK_SIZE
  51. }
  52. },
  53. menu: {
  54. login: {
  55. redirectOnSingleExternalAuth: CONFIG.CLIENT.MENU.LOGIN.REDIRECT_ON_SINGLE_EXTERNAL_AUTH
  56. }
  57. }
  58. },
  59. defaults: {
  60. publish: {
  61. downloadEnabled: CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED,
  62. commentsPolicy: CONFIG.DEFAULTS.PUBLISH.COMMENTS_POLICY,
  63. // TODO: remove, deprecated in 6.2
  64. commentsEnabled: CONFIG.DEFAULTS.PUBLISH.COMMENTS_POLICY !== VideoCommentPolicy.DISABLED,
  65. privacy: CONFIG.DEFAULTS.PUBLISH.PRIVACY,
  66. licence: CONFIG.DEFAULTS.PUBLISH.LICENCE
  67. },
  68. p2p: {
  69. webapp: {
  70. enabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED
  71. },
  72. embed: {
  73. enabled: CONFIG.DEFAULTS.P2P.EMBED.ENABLED
  74. }
  75. }
  76. },
  77. webadmin: {
  78. configuration: {
  79. edition: {
  80. allowed: CONFIG.WEBADMIN.CONFIGURATION.EDITION.ALLOWED
  81. }
  82. }
  83. },
  84. instance: {
  85. name: CONFIG.INSTANCE.NAME,
  86. shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
  87. isNSFW: CONFIG.INSTANCE.IS_NSFW,
  88. defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
  89. defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
  90. customizations: {
  91. javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
  92. css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
  93. },
  94. avatars: serverActor.Avatars.map(a => a.toFormattedJSON()),
  95. banners: serverActor.Banners.map(b => b.toFormattedJSON())
  96. },
  97. search: {
  98. remoteUri: {
  99. users: CONFIG.SEARCH.REMOTE_URI.USERS,
  100. anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
  101. },
  102. searchIndex: {
  103. enabled: CONFIG.SEARCH.SEARCH_INDEX.ENABLED,
  104. url: CONFIG.SEARCH.SEARCH_INDEX.URL,
  105. disableLocalSearch: CONFIG.SEARCH.SEARCH_INDEX.DISABLE_LOCAL_SEARCH,
  106. isDefaultSearch: CONFIG.SEARCH.SEARCH_INDEX.IS_DEFAULT_SEARCH
  107. }
  108. },
  109. plugin: {
  110. registered: this.getRegisteredPlugins(),
  111. registeredExternalAuths: this.getExternalAuthsPlugins(),
  112. registeredIdAndPassAuths: this.getIdAndPassAuthPlugins()
  113. },
  114. theme: {
  115. registered: this.getRegisteredThemes(),
  116. default: defaultTheme
  117. },
  118. email: {
  119. enabled: isEmailEnabled()
  120. },
  121. contactForm: {
  122. enabled: CONFIG.CONTACT_FORM.ENABLED
  123. },
  124. serverVersion: PEERTUBE_VERSION,
  125. serverCommit: this.serverCommit,
  126. transcoding: {
  127. remoteRunners: {
  128. enabled: CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.REMOTE_RUNNERS.ENABLED
  129. },
  130. hls: {
  131. enabled: CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.HLS.ENABLED
  132. },
  133. web_videos: {
  134. enabled: CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.WEB_VIDEOS.ENABLED
  135. },
  136. enabledResolutions: this.getEnabledResolutions('vod'),
  137. profile: CONFIG.TRANSCODING.PROFILE,
  138. availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('vod')
  139. },
  140. live: {
  141. enabled: CONFIG.LIVE.ENABLED,
  142. allowReplay: CONFIG.LIVE.ALLOW_REPLAY,
  143. latencySetting: {
  144. enabled: CONFIG.LIVE.LATENCY_SETTING.ENABLED
  145. },
  146. maxDuration: CONFIG.LIVE.MAX_DURATION,
  147. maxInstanceLives: CONFIG.LIVE.MAX_INSTANCE_LIVES,
  148. maxUserLives: CONFIG.LIVE.MAX_USER_LIVES,
  149. transcoding: {
  150. enabled: CONFIG.LIVE.TRANSCODING.ENABLED,
  151. remoteRunners: {
  152. enabled: CONFIG.LIVE.TRANSCODING.ENABLED && CONFIG.LIVE.TRANSCODING.REMOTE_RUNNERS.ENABLED
  153. },
  154. enabledResolutions: this.getEnabledResolutions('live'),
  155. profile: CONFIG.LIVE.TRANSCODING.PROFILE,
  156. availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('live')
  157. },
  158. rtmp: {
  159. port: CONFIG.LIVE.RTMP.PORT
  160. }
  161. },
  162. videoStudio: {
  163. enabled: CONFIG.VIDEO_STUDIO.ENABLED,
  164. remoteRunners: {
  165. enabled: CONFIG.VIDEO_STUDIO.REMOTE_RUNNERS.ENABLED
  166. }
  167. },
  168. videoFile: {
  169. update: {
  170. enabled: CONFIG.VIDEO_FILE.UPDATE.ENABLED
  171. }
  172. },
  173. videoTranscription: {
  174. enabled: CONFIG.VIDEO_TRANSCRIPTION.ENABLED
  175. },
  176. import: {
  177. videos: {
  178. http: {
  179. enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
  180. },
  181. torrent: {
  182. enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
  183. }
  184. },
  185. videoChannelSynchronization: {
  186. enabled: CONFIG.IMPORT.VIDEO_CHANNEL_SYNCHRONIZATION.ENABLED
  187. },
  188. users: {
  189. enabled: CONFIG.IMPORT.USERS.ENABLED
  190. }
  191. },
  192. export: {
  193. users: {
  194. enabled: CONFIG.EXPORT.USERS.ENABLED,
  195. exportExpiration: CONFIG.EXPORT.USERS.EXPORT_EXPIRATION,
  196. maxUserVideoQuota: CONFIG.EXPORT.USERS.MAX_USER_VIDEO_QUOTA
  197. }
  198. },
  199. autoBlacklist: {
  200. videos: {
  201. ofUsers: {
  202. enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED
  203. }
  204. }
  205. },
  206. avatar: {
  207. file: {
  208. size: {
  209. max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
  210. },
  211. extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
  212. }
  213. },
  214. banner: {
  215. file: {
  216. size: {
  217. max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
  218. },
  219. extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
  220. }
  221. },
  222. video: {
  223. image: {
  224. extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
  225. size: {
  226. max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
  227. }
  228. },
  229. file: {
  230. extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
  231. }
  232. },
  233. videoCaption: {
  234. file: {
  235. size: {
  236. max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
  237. },
  238. extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
  239. }
  240. },
  241. user: {
  242. videoQuota: CONFIG.USER.VIDEO_QUOTA,
  243. videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
  244. },
  245. videoChannels: {
  246. maxPerUser: CONFIG.VIDEO_CHANNELS.MAX_PER_USER
  247. },
  248. trending: {
  249. videos: {
  250. intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
  251. algorithms: {
  252. enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED,
  253. default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT
  254. }
  255. }
  256. },
  257. tracker: {
  258. enabled: CONFIG.TRACKER.ENABLED
  259. },
  260. followings: {
  261. instance: {
  262. autoFollowIndex: {
  263. indexUrl: CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_INDEX.INDEX_URL
  264. }
  265. }
  266. },
  267. broadcastMessage: {
  268. enabled: CONFIG.BROADCAST_MESSAGE.ENABLED,
  269. message: CONFIG.BROADCAST_MESSAGE.MESSAGE,
  270. level: CONFIG.BROADCAST_MESSAGE.LEVEL,
  271. dismissable: CONFIG.BROADCAST_MESSAGE.DISMISSABLE
  272. },
  273. homepage: {
  274. enabled: this.homepageEnabled
  275. },
  276. openTelemetry: {
  277. metrics: {
  278. enabled: CONFIG.OPEN_TELEMETRY.METRICS.ENABLED,
  279. playbackStatsInterval: CONFIG.OPEN_TELEMETRY.METRICS.PLAYBACK_STATS_INTERVAL
  280. }
  281. },
  282. views: {
  283. videos: {
  284. watchingInterval: {
  285. anonymous: CONFIG.VIEWS.VIDEOS.WATCHING_INTERVAL.ANONYMOUS,
  286. users: CONFIG.VIEWS.VIDEOS.WATCHING_INTERVAL.USERS
  287. }
  288. }
  289. },
  290. storyboards: {
  291. enabled: CONFIG.STORYBOARDS.ENABLED
  292. }
  293. }
  294. }
  295. async getServerConfig (ip?: string): Promise<ServerConfig> {
  296. const { allowed } = await Hooks.wrapPromiseFun(
  297. isSignupAllowed,
  298. {
  299. ip,
  300. signupMode: CONFIG.SIGNUP.REQUIRES_APPROVAL
  301. ? 'request-registration'
  302. : 'direct-registration'
  303. },
  304. CONFIG.SIGNUP.REQUIRES_APPROVAL
  305. ? 'filter:api.user.request-signup.allowed.result'
  306. : 'filter:api.user.signup.allowed.result'
  307. )
  308. const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip)
  309. const signup = {
  310. allowed,
  311. allowedForCurrentIP,
  312. minimumAge: CONFIG.SIGNUP.MINIMUM_AGE,
  313. requiresApproval: CONFIG.SIGNUP.REQUIRES_APPROVAL,
  314. requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
  315. }
  316. const htmlConfig = await this.getHTMLServerConfig()
  317. return { ...htmlConfig, signup }
  318. }
  319. getRegisteredThemes () {
  320. return PluginManager.Instance.getRegisteredThemes()
  321. .map(t => ({
  322. npmName: PluginModel.buildNpmName(t.name, t.type),
  323. name: t.name,
  324. version: t.version,
  325. description: t.description,
  326. css: t.css,
  327. clientScripts: t.clientScripts
  328. }))
  329. }
  330. getRegisteredPlugins () {
  331. return PluginManager.Instance.getRegisteredPlugins()
  332. .map(p => ({
  333. npmName: PluginModel.buildNpmName(p.name, p.type),
  334. name: p.name,
  335. version: p.version,
  336. description: p.description,
  337. clientScripts: p.clientScripts
  338. }))
  339. }
  340. getEnabledResolutions (type: 'vod' | 'live') {
  341. const transcoding = type === 'vod'
  342. ? CONFIG.TRANSCODING
  343. : CONFIG.LIVE.TRANSCODING
  344. return Object.keys(transcoding.RESOLUTIONS)
  345. .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true)
  346. .map(r => parseInt(r, 10) as VideoResolutionType)
  347. }
  348. private getIdAndPassAuthPlugins () {
  349. const result: RegisteredIdAndPassAuthConfig[] = []
  350. for (const p of PluginManager.Instance.getIdAndPassAuths()) {
  351. for (const auth of p.idAndPassAuths) {
  352. result.push({
  353. npmName: p.npmName,
  354. name: p.name,
  355. version: p.version,
  356. authName: auth.authName,
  357. weight: auth.getWeight()
  358. })
  359. }
  360. }
  361. return result
  362. }
  363. private getExternalAuthsPlugins () {
  364. const result: RegisteredExternalAuthConfig[] = []
  365. for (const p of PluginManager.Instance.getExternalAuths()) {
  366. for (const auth of p.externalAuths) {
  367. result.push({
  368. npmName: p.npmName,
  369. name: p.name,
  370. version: p.version,
  371. authName: auth.authName,
  372. authDisplayName: auth.authDisplayName()
  373. })
  374. }
  375. }
  376. return result
  377. }
  378. static get Instance () {
  379. return this.instance || (this.instance = new this())
  380. }
  381. }
  382. // ---------------------------------------------------------------------------
  383. export {
  384. ServerConfigManager
  385. }