aboutsummaryrefslogtreecommitdiffhomepage
path: root/server/lib
diff options
context:
space:
mode:
authorChocobozzz <chocobozzz@cpy.re>2021-05-27 15:59:55 +0200
committerGitHub <noreply@github.com>2021-05-27 15:59:55 +0200
commit2539932e16129992a2c0889b4ff527c265a8e2c7 (patch)
treefb5048e63e02a2485eb96d27455f43e4b22e8ae0 /server/lib
parenteb34ec30e0b57286fc6f85160490d2e973a3b0b1 (diff)
downloadPeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.tar.gz
PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.tar.zst
PeerTube-2539932e16129992a2c0889b4ff527c265a8e2c7.zip
Instance homepage support (#4007)
* Prepare homepage parsers * Add ability to update instance hompage * Add ability to set homepage as landing page * Add homepage preview in admin * Dynamically update left menu for homepage * Inject home content in homepage * Add videos list and channel miniature custom markup * Remove unused elements in markup service
Diffstat (limited to 'server/lib')
-rw-r--r--server/lib/client-html.ts6
-rw-r--r--server/lib/config.ts274
-rw-r--r--server/lib/job-queue/handlers/video-import.ts6
-rw-r--r--server/lib/plugins/plugin-helpers-builder.ts4
-rw-r--r--server/lib/server-config-manager.ts303
5 files changed, 311 insertions, 282 deletions
diff --git a/server/lib/client-html.ts b/server/lib/client-html.ts
index 85fdc8754..4b2968e8b 100644
--- a/server/lib/client-html.ts
+++ b/server/lib/client-html.ts
@@ -26,7 +26,7 @@ import { VideoChannelModel } from '../models/video/video-channel'
26import { getActivityStreamDuration } from '../models/video/video-format-utils' 26import { getActivityStreamDuration } from '../models/video/video-format-utils'
27import { VideoPlaylistModel } from '../models/video/video-playlist' 27import { VideoPlaylistModel } from '../models/video/video-playlist'
28import { MAccountActor, MChannelActor } from '../types/models' 28import { MAccountActor, MChannelActor } from '../types/models'
29import { getHTMLServerConfig } from './config' 29import { ServerConfigManager } from './server-config-manager'
30 30
31type Tags = { 31type Tags = {
32 ogType: string 32 ogType: string
@@ -211,7 +211,7 @@ class ClientHtml {
211 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] 211 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
212 212
213 const buffer = await readFile(path) 213 const buffer = await readFile(path)
214 const serverConfig = await getHTMLServerConfig() 214 const serverConfig = await ServerConfigManager.Instance.getHTMLServerConfig()
215 215
216 let html = buffer.toString() 216 let html = buffer.toString()
217 html = await ClientHtml.addAsyncPluginCSS(html) 217 html = await ClientHtml.addAsyncPluginCSS(html)
@@ -280,7 +280,7 @@ class ClientHtml {
280 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path] 280 if (!isTestInstance() && ClientHtml.htmlCache[path]) return ClientHtml.htmlCache[path]
281 281
282 const buffer = await readFile(path) 282 const buffer = await readFile(path)
283 const serverConfig = await getHTMLServerConfig() 283 const serverConfig = await ServerConfigManager.Instance.getHTMLServerConfig()
284 284
285 let html = buffer.toString() 285 let html = buffer.toString()
286 286
diff --git a/server/lib/config.ts b/server/lib/config.ts
deleted file mode 100644
index 18d49f05a..000000000
--- a/server/lib/config.ts
+++ /dev/null
@@ -1,274 +0,0 @@
1import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/helpers/signup'
2import { getServerCommit } from '@server/helpers/utils'
3import { CONFIG, isEmailEnabled } from '@server/initializers/config'
4import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants'
5import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models'
6import { Hooks } from './plugins/hooks'
7import { PluginManager } from './plugins/plugin-manager'
8import { getThemeOrDefault } from './plugins/theme-utils'
9import { VideoTranscodingProfilesManager } from './transcoding/video-transcoding-profiles'
10
11async function getServerConfig (ip?: string): Promise<ServerConfig> {
12 const { allowed } = await Hooks.wrapPromiseFun(
13 isSignupAllowed,
14 {
15 ip
16 },
17 'filter:api.user.signup.allowed.result'
18 )
19
20 const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip)
21
22 const signup = {
23 allowed,
24 allowedForCurrentIP,
25 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
26 }
27
28 const htmlConfig = await getHTMLServerConfig()
29
30 return { ...htmlConfig, signup }
31}
32
33// Config injected in HTML
34let serverCommit: string
35async function getHTMLServerConfig (): Promise<HTMLServerConfig> {
36 if (serverCommit === undefined) serverCommit = await getServerCommit()
37
38 const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
39
40 return {
41 instance: {
42 name: CONFIG.INSTANCE.NAME,
43 shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
44 isNSFW: CONFIG.INSTANCE.IS_NSFW,
45 defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
46 defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
47 customizations: {
48 javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
49 css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
50 }
51 },
52 search: {
53 remoteUri: {
54 users: CONFIG.SEARCH.REMOTE_URI.USERS,
55 anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
56 },
57 searchIndex: {
58 enabled: CONFIG.SEARCH.SEARCH_INDEX.ENABLED,
59 url: CONFIG.SEARCH.SEARCH_INDEX.URL,
60 disableLocalSearch: CONFIG.SEARCH.SEARCH_INDEX.DISABLE_LOCAL_SEARCH,
61 isDefaultSearch: CONFIG.SEARCH.SEARCH_INDEX.IS_DEFAULT_SEARCH
62 }
63 },
64 plugin: {
65 registered: getRegisteredPlugins(),
66 registeredExternalAuths: getExternalAuthsPlugins(),
67 registeredIdAndPassAuths: getIdAndPassAuthPlugins()
68 },
69 theme: {
70 registered: getRegisteredThemes(),
71 default: defaultTheme
72 },
73 email: {
74 enabled: isEmailEnabled()
75 },
76 contactForm: {
77 enabled: CONFIG.CONTACT_FORM.ENABLED
78 },
79 serverVersion: PEERTUBE_VERSION,
80 serverCommit,
81 transcoding: {
82 hls: {
83 enabled: CONFIG.TRANSCODING.HLS.ENABLED
84 },
85 webtorrent: {
86 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
87 },
88 enabledResolutions: getEnabledResolutions('vod'),
89 profile: CONFIG.TRANSCODING.PROFILE,
90 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('vod')
91 },
92 live: {
93 enabled: CONFIG.LIVE.ENABLED,
94
95 allowReplay: CONFIG.LIVE.ALLOW_REPLAY,
96 maxDuration: CONFIG.LIVE.MAX_DURATION,
97 maxInstanceLives: CONFIG.LIVE.MAX_INSTANCE_LIVES,
98 maxUserLives: CONFIG.LIVE.MAX_USER_LIVES,
99
100 transcoding: {
101 enabled: CONFIG.LIVE.TRANSCODING.ENABLED,
102 enabledResolutions: getEnabledResolutions('live'),
103 profile: CONFIG.LIVE.TRANSCODING.PROFILE,
104 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('live')
105 },
106
107 rtmp: {
108 port: CONFIG.LIVE.RTMP.PORT
109 }
110 },
111 import: {
112 videos: {
113 http: {
114 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
115 },
116 torrent: {
117 enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
118 }
119 }
120 },
121 autoBlacklist: {
122 videos: {
123 ofUsers: {
124 enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED
125 }
126 }
127 },
128 avatar: {
129 file: {
130 size: {
131 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
132 },
133 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
134 }
135 },
136 banner: {
137 file: {
138 size: {
139 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
140 },
141 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
142 }
143 },
144 video: {
145 image: {
146 extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
147 size: {
148 max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
149 }
150 },
151 file: {
152 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
153 }
154 },
155 videoCaption: {
156 file: {
157 size: {
158 max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
159 },
160 extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
161 }
162 },
163 user: {
164 videoQuota: CONFIG.USER.VIDEO_QUOTA,
165 videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
166 },
167 trending: {
168 videos: {
169 intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
170 algorithms: {
171 enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED,
172 default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT
173 }
174 }
175 },
176 tracker: {
177 enabled: CONFIG.TRACKER.ENABLED
178 },
179
180 followings: {
181 instance: {
182 autoFollowIndex: {
183 indexUrl: CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_INDEX.INDEX_URL
184 }
185 }
186 },
187
188 broadcastMessage: {
189 enabled: CONFIG.BROADCAST_MESSAGE.ENABLED,
190 message: CONFIG.BROADCAST_MESSAGE.MESSAGE,
191 level: CONFIG.BROADCAST_MESSAGE.LEVEL,
192 dismissable: CONFIG.BROADCAST_MESSAGE.DISMISSABLE
193 }
194 }
195}
196
197function getRegisteredThemes () {
198 return PluginManager.Instance.getRegisteredThemes()
199 .map(t => ({
200 name: t.name,
201 version: t.version,
202 description: t.description,
203 css: t.css,
204 clientScripts: t.clientScripts
205 }))
206}
207
208function getRegisteredPlugins () {
209 return PluginManager.Instance.getRegisteredPlugins()
210 .map(p => ({
211 name: p.name,
212 version: p.version,
213 description: p.description,
214 clientScripts: p.clientScripts
215 }))
216}
217
218function getEnabledResolutions (type: 'vod' | 'live') {
219 const transcoding = type === 'vod'
220 ? CONFIG.TRANSCODING
221 : CONFIG.LIVE.TRANSCODING
222
223 return Object.keys(transcoding.RESOLUTIONS)
224 .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true)
225 .map(r => parseInt(r, 10))
226}
227
228// ---------------------------------------------------------------------------
229
230export {
231 getServerConfig,
232 getRegisteredThemes,
233 getEnabledResolutions,
234 getRegisteredPlugins,
235 getHTMLServerConfig
236}
237
238// ---------------------------------------------------------------------------
239
240function getIdAndPassAuthPlugins () {
241 const result: RegisteredIdAndPassAuthConfig[] = []
242
243 for (const p of PluginManager.Instance.getIdAndPassAuths()) {
244 for (const auth of p.idAndPassAuths) {
245 result.push({
246 npmName: p.npmName,
247 name: p.name,
248 version: p.version,
249 authName: auth.authName,
250 weight: auth.getWeight()
251 })
252 }
253 }
254
255 return result
256}
257
258function getExternalAuthsPlugins () {
259 const result: RegisteredExternalAuthConfig[] = []
260
261 for (const p of PluginManager.Instance.getExternalAuths()) {
262 for (const auth of p.externalAuths) {
263 result.push({
264 npmName: p.npmName,
265 name: p.name,
266 version: p.version,
267 authName: auth.authName,
268 authDisplayName: auth.authDisplayName()
269 })
270 }
271 }
272
273 return result
274}
diff --git a/server/lib/job-queue/handlers/video-import.ts b/server/lib/job-queue/handlers/video-import.ts
index 3067ce214..d71053e87 100644
--- a/server/lib/job-queue/handlers/video-import.ts
+++ b/server/lib/job-queue/handlers/video-import.ts
@@ -2,8 +2,10 @@ import * as Bull from 'bull'
2import { move, remove, stat } from 'fs-extra' 2import { move, remove, stat } from 'fs-extra'
3import { extname } from 'path' 3import { extname } from 'path'
4import { retryTransactionWrapper } from '@server/helpers/database-utils' 4import { retryTransactionWrapper } from '@server/helpers/database-utils'
5import { YoutubeDL } from '@server/helpers/youtube-dl'
5import { isPostImportVideoAccepted } from '@server/lib/moderation' 6import { isPostImportVideoAccepted } from '@server/lib/moderation'
6import { Hooks } from '@server/lib/plugins/hooks' 7import { Hooks } from '@server/lib/plugins/hooks'
8import { ServerConfigManager } from '@server/lib/server-config-manager'
7import { isAbleToUploadVideo } from '@server/lib/user' 9import { isAbleToUploadVideo } from '@server/lib/user'
8import { addOptimizeOrMergeAudioJob } from '@server/lib/video' 10import { addOptimizeOrMergeAudioJob } from '@server/lib/video'
9import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths' 11import { generateVideoFilename, getVideoFilePath } from '@server/lib/video-paths'
@@ -33,8 +35,6 @@ import { MThumbnail } from '../../../types/models/video/thumbnail'
33import { federateVideoIfNeeded } from '../../activitypub/videos' 35import { federateVideoIfNeeded } from '../../activitypub/videos'
34import { Notifier } from '../../notifier' 36import { Notifier } from '../../notifier'
35import { generateVideoMiniature } from '../../thumbnail' 37import { generateVideoMiniature } from '../../thumbnail'
36import { YoutubeDL } from '@server/helpers/youtube-dl'
37import { getEnabledResolutions } from '@server/lib/config'
38 38
39async function processVideoImport (job: Bull.Job) { 39async function processVideoImport (job: Bull.Job) {
40 const payload = job.data as VideoImportPayload 40 const payload = job.data as VideoImportPayload
@@ -76,7 +76,7 @@ async function processYoutubeDLImport (job: Bull.Job, payload: VideoImportYoutub
76 videoImportId: videoImport.id 76 videoImportId: videoImport.id
77 } 77 }
78 78
79 const youtubeDL = new YoutubeDL(videoImport.targetUrl, getEnabledResolutions('vod')) 79 const youtubeDL = new YoutubeDL(videoImport.targetUrl, ServerConfigManager.Instance.getEnabledResolutions('vod'))
80 80
81 return processFile( 81 return processFile(
82 () => youtubeDL.downloadYoutubeDLVideo(payload.fileExt, VIDEO_IMPORT_TIMEOUT), 82 () => youtubeDL.downloadYoutubeDLVideo(payload.fileExt, VIDEO_IMPORT_TIMEOUT),
diff --git a/server/lib/plugins/plugin-helpers-builder.ts b/server/lib/plugins/plugin-helpers-builder.ts
index cb1cd4d9a..8487672ba 100644
--- a/server/lib/plugins/plugin-helpers-builder.ts
+++ b/server/lib/plugins/plugin-helpers-builder.ts
@@ -15,7 +15,7 @@ import { MPlugin } from '@server/types/models'
15import { PeerTubeHelpers } from '@server/types/plugins' 15import { PeerTubeHelpers } from '@server/types/plugins'
16import { VideoBlacklistCreate } from '@shared/models' 16import { VideoBlacklistCreate } from '@shared/models'
17import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist' 17import { addAccountInBlocklist, addServerInBlocklist, removeAccountFromBlocklist, removeServerFromBlocklist } from '../blocklist'
18import { getServerConfig } from '../config' 18import { ServerConfigManager } from '../server-config-manager'
19import { blacklistVideo, unblacklistVideo } from '../video-blacklist' 19import { blacklistVideo, unblacklistVideo } from '../video-blacklist'
20import { UserModel } from '@server/models/user/user' 20import { UserModel } from '@server/models/user/user'
21 21
@@ -147,7 +147,7 @@ function buildConfigHelpers () {
147 }, 147 },
148 148
149 getServerConfig () { 149 getServerConfig () {
150 return getServerConfig() 150 return ServerConfigManager.Instance.getServerConfig()
151 } 151 }
152 } 152 }
153} 153}
diff --git a/server/lib/server-config-manager.ts b/server/lib/server-config-manager.ts
new file mode 100644
index 000000000..1aff6f446
--- /dev/null
+++ b/server/lib/server-config-manager.ts
@@ -0,0 +1,303 @@
1import { isSignupAllowed, isSignupAllowedForCurrentIP } from '@server/helpers/signup'
2import { getServerCommit } from '@server/helpers/utils'
3import { CONFIG, isEmailEnabled } from '@server/initializers/config'
4import { CONSTRAINTS_FIELDS, DEFAULT_THEME_NAME, PEERTUBE_VERSION } from '@server/initializers/constants'
5import { ActorCustomPageModel } from '@server/models/account/actor-custom-page'
6import { HTMLServerConfig, RegisteredExternalAuthConfig, RegisteredIdAndPassAuthConfig, ServerConfig } from '@shared/models'
7import { Hooks } from './plugins/hooks'
8import { PluginManager } from './plugins/plugin-manager'
9import { getThemeOrDefault } from './plugins/theme-utils'
10import { VideoTranscodingProfilesManager } from './transcoding/video-transcoding-profiles'
11
12/**
13 *
14 * Used to send the server config to clients (using REST/API or plugins API)
15 * We need a singleton class to manage config state depending on external events (to build menu entries etc)
16 *
17 */
18
19class ServerConfigManager {
20
21 private static instance: ServerConfigManager
22
23 private serverCommit: string
24
25 private homepageEnabled = false
26
27 private constructor () {}
28
29 async init () {
30 const instanceHomepage = await ActorCustomPageModel.loadInstanceHomepage()
31
32 this.updateHomepageState(instanceHomepage?.content)
33 }
34
35 updateHomepageState (content: string) {
36 this.homepageEnabled = !!content
37 }
38
39 async getHTMLServerConfig (): Promise<HTMLServerConfig> {
40 if (this.serverCommit === undefined) this.serverCommit = await getServerCommit()
41
42 const defaultTheme = getThemeOrDefault(CONFIG.THEME.DEFAULT, DEFAULT_THEME_NAME)
43
44 return {
45 instance: {
46 name: CONFIG.INSTANCE.NAME,
47 shortDescription: CONFIG.INSTANCE.SHORT_DESCRIPTION,
48 isNSFW: CONFIG.INSTANCE.IS_NSFW,
49 defaultNSFWPolicy: CONFIG.INSTANCE.DEFAULT_NSFW_POLICY,
50 defaultClientRoute: CONFIG.INSTANCE.DEFAULT_CLIENT_ROUTE,
51 customizations: {
52 javascript: CONFIG.INSTANCE.CUSTOMIZATIONS.JAVASCRIPT,
53 css: CONFIG.INSTANCE.CUSTOMIZATIONS.CSS
54 }
55 },
56 search: {
57 remoteUri: {
58 users: CONFIG.SEARCH.REMOTE_URI.USERS,
59 anonymous: CONFIG.SEARCH.REMOTE_URI.ANONYMOUS
60 },
61 searchIndex: {
62 enabled: CONFIG.SEARCH.SEARCH_INDEX.ENABLED,
63 url: CONFIG.SEARCH.SEARCH_INDEX.URL,
64 disableLocalSearch: CONFIG.SEARCH.SEARCH_INDEX.DISABLE_LOCAL_SEARCH,
65 isDefaultSearch: CONFIG.SEARCH.SEARCH_INDEX.IS_DEFAULT_SEARCH
66 }
67 },
68 plugin: {
69 registered: this.getRegisteredPlugins(),
70 registeredExternalAuths: this.getExternalAuthsPlugins(),
71 registeredIdAndPassAuths: this.getIdAndPassAuthPlugins()
72 },
73 theme: {
74 registered: this.getRegisteredThemes(),
75 default: defaultTheme
76 },
77 email: {
78 enabled: isEmailEnabled()
79 },
80 contactForm: {
81 enabled: CONFIG.CONTACT_FORM.ENABLED
82 },
83 serverVersion: PEERTUBE_VERSION,
84 serverCommit: this.serverCommit,
85 transcoding: {
86 hls: {
87 enabled: CONFIG.TRANSCODING.HLS.ENABLED
88 },
89 webtorrent: {
90 enabled: CONFIG.TRANSCODING.WEBTORRENT.ENABLED
91 },
92 enabledResolutions: this.getEnabledResolutions('vod'),
93 profile: CONFIG.TRANSCODING.PROFILE,
94 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('vod')
95 },
96 live: {
97 enabled: CONFIG.LIVE.ENABLED,
98
99 allowReplay: CONFIG.LIVE.ALLOW_REPLAY,
100 maxDuration: CONFIG.LIVE.MAX_DURATION,
101 maxInstanceLives: CONFIG.LIVE.MAX_INSTANCE_LIVES,
102 maxUserLives: CONFIG.LIVE.MAX_USER_LIVES,
103
104 transcoding: {
105 enabled: CONFIG.LIVE.TRANSCODING.ENABLED,
106 enabledResolutions: this.getEnabledResolutions('live'),
107 profile: CONFIG.LIVE.TRANSCODING.PROFILE,
108 availableProfiles: VideoTranscodingProfilesManager.Instance.getAvailableProfiles('live')
109 },
110
111 rtmp: {
112 port: CONFIG.LIVE.RTMP.PORT
113 }
114 },
115 import: {
116 videos: {
117 http: {
118 enabled: CONFIG.IMPORT.VIDEOS.HTTP.ENABLED
119 },
120 torrent: {
121 enabled: CONFIG.IMPORT.VIDEOS.TORRENT.ENABLED
122 }
123 }
124 },
125 autoBlacklist: {
126 videos: {
127 ofUsers: {
128 enabled: CONFIG.AUTO_BLACKLIST.VIDEOS.OF_USERS.ENABLED
129 }
130 }
131 },
132 avatar: {
133 file: {
134 size: {
135 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
136 },
137 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
138 }
139 },
140 banner: {
141 file: {
142 size: {
143 max: CONSTRAINTS_FIELDS.ACTORS.IMAGE.FILE_SIZE.max
144 },
145 extensions: CONSTRAINTS_FIELDS.ACTORS.IMAGE.EXTNAME
146 }
147 },
148 video: {
149 image: {
150 extensions: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.EXTNAME,
151 size: {
152 max: CONSTRAINTS_FIELDS.VIDEOS.IMAGE.FILE_SIZE.max
153 }
154 },
155 file: {
156 extensions: CONSTRAINTS_FIELDS.VIDEOS.EXTNAME
157 }
158 },
159 videoCaption: {
160 file: {
161 size: {
162 max: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.FILE_SIZE.max
163 },
164 extensions: CONSTRAINTS_FIELDS.VIDEO_CAPTIONS.CAPTION_FILE.EXTNAME
165 }
166 },
167 user: {
168 videoQuota: CONFIG.USER.VIDEO_QUOTA,
169 videoQuotaDaily: CONFIG.USER.VIDEO_QUOTA_DAILY
170 },
171 trending: {
172 videos: {
173 intervalDays: CONFIG.TRENDING.VIDEOS.INTERVAL_DAYS,
174 algorithms: {
175 enabled: CONFIG.TRENDING.VIDEOS.ALGORITHMS.ENABLED,
176 default: CONFIG.TRENDING.VIDEOS.ALGORITHMS.DEFAULT
177 }
178 }
179 },
180 tracker: {
181 enabled: CONFIG.TRACKER.ENABLED
182 },
183
184 followings: {
185 instance: {
186 autoFollowIndex: {
187 indexUrl: CONFIG.FOLLOWINGS.INSTANCE.AUTO_FOLLOW_INDEX.INDEX_URL
188 }
189 }
190 },
191
192 broadcastMessage: {
193 enabled: CONFIG.BROADCAST_MESSAGE.ENABLED,
194 message: CONFIG.BROADCAST_MESSAGE.MESSAGE,
195 level: CONFIG.BROADCAST_MESSAGE.LEVEL,
196 dismissable: CONFIG.BROADCAST_MESSAGE.DISMISSABLE
197 },
198
199 homepage: {
200 enabled: this.homepageEnabled
201 }
202 }
203 }
204
205 async getServerConfig (ip?: string): Promise<ServerConfig> {
206 const { allowed } = await Hooks.wrapPromiseFun(
207 isSignupAllowed,
208 {
209 ip
210 },
211 'filter:api.user.signup.allowed.result'
212 )
213
214 const allowedForCurrentIP = isSignupAllowedForCurrentIP(ip)
215
216 const signup = {
217 allowed,
218 allowedForCurrentIP,
219 requiresEmailVerification: CONFIG.SIGNUP.REQUIRES_EMAIL_VERIFICATION
220 }
221
222 const htmlConfig = await this.getHTMLServerConfig()
223
224 return { ...htmlConfig, signup }
225 }
226
227 getRegisteredThemes () {
228 return PluginManager.Instance.getRegisteredThemes()
229 .map(t => ({
230 name: t.name,
231 version: t.version,
232 description: t.description,
233 css: t.css,
234 clientScripts: t.clientScripts
235 }))
236 }
237
238 getRegisteredPlugins () {
239 return PluginManager.Instance.getRegisteredPlugins()
240 .map(p => ({
241 name: p.name,
242 version: p.version,
243 description: p.description,
244 clientScripts: p.clientScripts
245 }))
246 }
247
248 getEnabledResolutions (type: 'vod' | 'live') {
249 const transcoding = type === 'vod'
250 ? CONFIG.TRANSCODING
251 : CONFIG.LIVE.TRANSCODING
252
253 return Object.keys(transcoding.RESOLUTIONS)
254 .filter(key => transcoding.ENABLED && transcoding.RESOLUTIONS[key] === true)
255 .map(r => parseInt(r, 10))
256 }
257
258 private getIdAndPassAuthPlugins () {
259 const result: RegisteredIdAndPassAuthConfig[] = []
260
261 for (const p of PluginManager.Instance.getIdAndPassAuths()) {
262 for (const auth of p.idAndPassAuths) {
263 result.push({
264 npmName: p.npmName,
265 name: p.name,
266 version: p.version,
267 authName: auth.authName,
268 weight: auth.getWeight()
269 })
270 }
271 }
272
273 return result
274 }
275
276 private getExternalAuthsPlugins () {
277 const result: RegisteredExternalAuthConfig[] = []
278
279 for (const p of PluginManager.Instance.getExternalAuths()) {
280 for (const auth of p.externalAuths) {
281 result.push({
282 npmName: p.npmName,
283 name: p.name,
284 version: p.version,
285 authName: auth.authName,
286 authDisplayName: auth.authDisplayName()
287 })
288 }
289 }
290
291 return result
292 }
293
294 static get Instance () {
295 return this.instance || (this.instance = new this())
296 }
297}
298
299// ---------------------------------------------------------------------------
300
301export {
302 ServerConfigManager
303}