123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425 |
- import {
- HTMLServerConfig,
- RegisteredExternalAuthConfig,
- RegisteredIdAndPassAuthConfig,
- ServerConfig,
- VideoResolutionType
- } from '@peertube/peertube-models'
- import { getServerCommit } from '@server/helpers/version.js'
- import { CONFIG, isEmailEnabled } from '@server/initializers/config.js'
- import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants.js'
- import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/lib/signup.js'
- import { ActorCustomPageModel } from '@server/models/account/actor-custom-page.js'
- import { getServerActor } from '@server/models/application/application.js'
- import { PluginModel } from '@server/models/server/plugin.js'
- import { Hooks } from './plugins/hooks.js'
- import { PluginManager } from './plugins/plugin-manager.js'
- import { getThemeOrDefault } from './plugins/theme-utils.js'
- import { VideoTranscodingProfilesManager } from './transcoding/default-transcoding-profiles.js'
- /**
- *
- * Used to send the server config to clients (using REST/API or plugins API)
- * We need a singleton class to manage config state depending on external events (to build menu entries etc)
- *
- */
- class ServerConfigManager {
- private static instance: ServerConfigManager
- private serverCommit: string
- private homepageEnabled = false
- private constructor () {}
- async init () {
- const instanceHomepage = await ActorCustomPageModel.loadInstanceHomepage()
- this.updateHomepageState(instanceHomepage?.content)
- }
- updateHomepageState (content: string) {
- this.homepageEnabled = !!content
- }
- async getHTMLServerConfig (): Promise<HTMLServerConfig> {
- if (this.serverCommit === undefined) this.serverCommit = await getServerCommit()
- const serverActor = await getServerActor()
- const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
- return {
- client: {
- videos: {
- miniature: {
- displayAuthorAvatar: CONFIG.CLIENT.VIDEOS.MINIATURE.DISPLAY_AUTHOR_AVATAR,
- preferAuthorDisplayName: CONFIG.CLIENT.VIDEOS.MINIATURE.PREFER_AUTHOR_DISPLAY_NAME
- },
- resumableUpload: {
- maxChunkSize: CONFIG.CLIENT.VIDEOS.RESUMABLE_UPLOAD.MAX_CHUNK_SIZE
- }
- },
- menu: {
- login: {
- redirectOnSingleExternalAuth: CONFIG.CLIENT.MENU.LOGIN.REDIRECT_ON_SINGLE_EXTERNAL_AUTH
- }
- }
- },
- defaults: {
- publish: {
- downloadEnabled: CONFIG.DEFAULTS.PUBLISH.DOWNLOAD_ENABLED,
- commentsEnabled: CONFIG.DEFAULTS.PUBLISH.COMMENTS_ENABLED,
- privacy: CONFIG.DEFAULTS.PUBLISH.PRIVACY,
- licence: CONFIG.DEFAULTS.PUBLISH.LICENCE
- },
- p2p: {
- webapp: {
- enabled: CONFIG.DEFAULTS.P2P.WEBAPP.ENABLED
- },
- embed: {
- enabled: CONFIG.DEFAULTS.P2P.EMBED.ENABLED
- }
- }
- },
- webadmin: {
- configuration: {
- edition: {
- allowed: CONFIG.WEBADMIN.CONFIGURATION.EDITION.ALLOWED
- }
- }
- },
- instance: {
- name: CONFIG.INSTANCE.NAME,
- shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
- isNSFW: CONFIG.INSTANCE.IS_NSFW,
- defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
- defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
- customizations: {
- javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
- css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
- },
- avatars: serverActor.Avatars.map(a => a.toFormattedJSON()),
- banners: serverActor.Banners.map(b => b.toFormattedJSON())
- },
- search: {
- remoteUri: {
- users: CONFIG.SEARCH.REMOTE_URI.USERS,
- anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
- },
- searchIndex: {
- enabled: CONFIG.SEARCH.SEARCH_INDEX.ENABLED,
- url: CONFIG.SEARCH.SEARCH_INDEX.URL,
- disableLocalSearch: CONFIG.SEARCH.SEARCH_INDEX.DISABLE_LOCAL_SEARCH,
- isDefaultSearch: CONFIG.SEARCH.SEARCH_INDEX.IS_DEFAULT_SEARCH
- }
- },
- plugin: {
- registered: this.getRegisteredPlugins(),
- registeredExternalAuths: this.getExternalAuthsPlugins(),
- registeredIdAndPassAuths: this.getIdAndPassAuthPlugins()
- },
- theme: {
- registered: this.getRegisteredThemes(),
- default: defaultTheme
- },
- email: {
- enabled: isEmailEnabled()
- },
- contactForm: {
- enabled: CONFIG.CONTACT_FORM.ENABLED
- },
- serverVersion: PEERTUBE_VERSION,
- serverCommit: this.serverCommit,
- transcoding: {
- remoteRunners: {
- enabled: CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.REMOTE_RUNNERS.ENABLED
- },
- hls: {
- enabled: CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.HLS.ENABLED
- },
- web_videos: {
- enabled: CONFIG.TRANSCODING.ENABLED && CONFIG.TRANSCODING.WEB_VIDEOS.ENABLED
- },
- enabledResolutions: this.getEnabledResolutions('vod'),
- profile: CONFIG.TRANSCODING.PROFILE,
- availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('vod')
- },
- live: {
- enabled: CONFIG.LIVE.ENABLED,
- allowReplay: CONFIG.LIVE.ALLOW_REPLAY,
- latencySetting: {
- enabled: CONFIG.LIVE.LATENCY_SETTING.ENABLED
- },
- maxDuration: CONFIG.LIVE.MAX_DURATION,
- maxInstanceLives: CONFIG.LIVE.MAX_INSTANCE_LIVES,
- maxUserLives: CONFIG.LIVE.MAX_USER_LIVES,
- transcoding: {
- enabled: CONFIG.LIVE.TRANSCODING.ENABLED,
- remoteRunners: {
- enabled: CONFIG.LIVE.TRANSCODING.ENABLED && CONFIG.LIVE.TRANSCODING.REMOTE_RUNNERS.ENABLED
- },
- enabledResolutions: this.getEnabledResolutions('live'),
- profile: CONFIG.LIVE.TRANSCODING.PROFILE,
- availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('live')
- },
- rtmp: {
- port: CONFIG.LIVE.RTMP.PORT
- }
- },
- videoStudio: {
- enabled: CONFIG.VIDEO_STUDIO.ENABLED,
- remoteRunners: {
- enabled: CONFIG.VIDEO_STUDIO.REMOTE_RUNNERS.ENABLED
- }
- },
- videoFile: {
- update: {
- enabled: CONFIG.VIDEO_FILE.UPDATE.ENABLED
- }
- },
- import: {
- videos: {
- http: {
- enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
- },
- torrent: {
- enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
- }
- },
- videoChannelSynchronization: {
- enabled: CONFIG.IMPORT.VIDEO_CHANNEL_SYNCHRONIZATION.ENABLED
- },
- users: {
- enabled: CONFIG.IMPORT.USERS.ENABLED
- }
- },
- export: {
- users: {
- enabled: CONFIG.EXPORT.USERS.ENABLED,
- exportExpiration: CONFIG.EXPORT.USERS.EXPORT_EXPIRATION,
- maxUserVideoQuota: CONFIG.EXPORT.USERS.MAX_USER_VIDEO_QUOTA
- }
- },
- autoBlacklist: {
- videos: {
- ofUsers: {
- enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED
- }
- }
- },
- avatar: {
- file: {
- size: {
- max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
- },
- extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
- }
- },
- banner: {
- file: {
- size: {
- max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
- },
- extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
- }
- },
- video: {
- image: {
- extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
- size: {
- max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
- }
- },
- file: {
- extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
- }
- },
- videoCaption: {
- file: {
- size: {
- max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
- },
- extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
- }
- },
- user: {
- videoQuota: CONFIG.USER.VIDEO_QUOTA,
- videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
- },
- videoChannels: {
- maxPerUser: CONFIG.VIDEO_CHANNELS.MAX_PER_USER
- },
- trending: {
- videos: {
- intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
- algorithms: {
- enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED,
- default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT
- }
- }
- },
- tracker: {
- enabled: CONFIG.TRACKER.ENABLED
- },
- followings: {
- instance: {
- autoFollowIndex: {
- indexUrl: CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_INDEX.INDEX_URL
- }
- }
- },
- broadcastMessage: {
- enabled: CONFIG.BROADCAST_MESSAGE.ENABLED,
- message: CONFIG.BROADCAST_MESSAGE.MESSAGE,
- level: CONFIG.BROADCAST_MESSAGE.LEVEL,
- dismissable: CONFIG.BROADCAST_MESSAGE.DISMISSABLE
- },
- homepage: {
- enabled: this.homepageEnabled
- },
- openTelemetry: {
- metrics: {
- enabled: CONFIG.OPEN_TELEMETRY.METRICS.ENABLED,
- playbackStatsInterval: CONFIG.OPEN_TELEMETRY.METRICS.PLAYBACK_STATS_INTERVAL
- }
- },
- views: {
- videos: {
- watchingInterval: {
- anonymous: CONFIG.VIEWS.VIDEOS.WATCHING_INTERVAL.ANONYMOUS,
- users: CONFIG.VIEWS.VIDEOS.WATCHING_INTERVAL.USERS
- }
- }
- },
- storyboards: {
- enabled: CONFIG.STORYBOARDS.ENABLED
- }
- }
- }
- async getServerConfig (ip?: string): Promise<ServerConfig> {
- const { allowed } = await Hooks.wrapPromiseFun(
- isSignupAllowed,
- {
- ip,
- signupMode: CONFIG.SIGNUP.REQUIRES_APPROVAL
- ? 'request-registration'
- : 'direct-registration'
- },
- CONFIG.SIGNUP.REQUIRES_APPROVAL
- ? 'filter:api.user.request-signup.allowed.result'
- : 'filter:api.user.signup.allowed.result'
- )
- const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip)
- const signup = {
- allowed,
- allowedForCurrentIP,
- minimumAge: CONFIG.SIGNUP.MINIMUM_AGE,
- requiresApproval: CONFIG.SIGNUP.REQUIRES_APPROVAL,
- requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
- }
- const htmlConfig = await this.getHTMLServerConfig()
- return { ...htmlConfig, signup }
- }
- getRegisteredThemes () {
- return PluginManager.Instance.getRegisteredThemes()
- .map(t => ({
- npmName: PluginModel.buildNpmName(t.name, t.type),
- name: t.name,
- version: t.version,
- description: t.description,
- css: t.css,
- clientScripts: t.clientScripts
- }))
- }
- getRegisteredPlugins () {
- return PluginManager.Instance.getRegisteredPlugins()
- .map(p => ({
- npmName: PluginModel.buildNpmName(p.name, p.type),
- name: p.name,
- version: p.version,
- description: p.description,
- clientScripts: p.clientScripts
- }))
- }
- getEnabledResolutions (type: 'vod' | 'live') {
- const transcoding = type === 'vod'
- ? CONFIG.TRANSCODING
- : CONFIG.LIVE.TRANSCODING
- return Object.keys(transcoding.RESOLUTIONS)
- .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true)
- .map(r => parseInt(r, 10) as VideoResolutionType)
- }
- private getIdAndPassAuthPlugins () {
- const result: RegisteredIdAndPassAuthConfig[] = []
- for (const p of PluginManager.Instance.getIdAndPassAuths()) {
- for (const auth of p.idAndPassAuths) {
- result.push({
- npmName: p.npmName,
- name: p.name,
- version: p.version,
- authName: auth.authName,
- weight: auth.getWeight()
- })
- }
- }
- return result
- }
- private getExternalAuthsPlugins () {
- const result: RegisteredExternalAuthConfig[] = []
- for (const p of PluginManager.Instance.getExternalAuths()) {
- for (const auth of p.externalAuths) {
- result.push({
- npmName: p.npmName,
- name: p.name,
- version: p.version,
- authName: auth.authName,
- authDisplayName: auth.authDisplayName()
- })
- }
- }
- return result
- }
- static get Instance () {
- return this.instance || (this.instance = new this())
- }
- }
- // ---------------------------------------------------------------------------
- export {
- ServerConfigManager
- }
|