]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blob - client/src/app/+admin/config/edit-custom-config/edit-custom-config.component.ts
3a60b144f7f738bdf78e30b449973da2f4a56875
[github/Chocobozzz/PeerTube.git] / client / src / app / +admin / config / edit-custom-config / edit-custom-config.component.ts
1 import { forkJoin } from 'rxjs'
2 import { ViewportScroller } from '@angular/common'
3 import { AfterViewChecked, Component, OnInit, ViewChild } from '@angular/core'
4 import { ConfigService } from '@app/+admin/config/shared/config.service'
5 import { Notifier } from '@app/core'
6 import { ServerService } from '@app/core/server/server.service'
7 import {
8 CustomConfigValidatorsService,
9 FormReactive,
10 FormValidatorService,
11 SelectOptionsItem,
12 UserValidatorsService
13 } from '@app/shared/shared-forms'
14 import { NgbNav } from '@ng-bootstrap/ng-bootstrap'
15 import { CustomConfig, ServerConfig } from '@shared/models'
16
17 @Component({
18 selector: 'my-edit-custom-config',
19 templateUrl: './edit-custom-config.component.html',
20 styleUrls: [ './edit-custom-config.component.scss' ]
21 })
22 export class EditCustomConfigComponent extends FormReactive implements OnInit, AfterViewChecked {
23 // FIXME: use built-in router
24 @ViewChild('nav') nav: NgbNav
25
26 initDone = false
27 customConfig: CustomConfig
28
29 resolutions: { id: string, label: string, description?: string }[] = []
30 transcodingThreadOptions: { label: string, value: number }[] = []
31
32 languageItems: SelectOptionsItem[] = []
33 categoryItems: SelectOptionsItem[] = []
34
35 private serverConfig: ServerConfig
36
37 constructor (
38 private viewportScroller: ViewportScroller,
39 protected formValidatorService: FormValidatorService,
40 private customConfigValidatorsService: CustomConfigValidatorsService,
41 private userValidatorsService: UserValidatorsService,
42 private notifier: Notifier,
43 private configService: ConfigService,
44 private serverService: ServerService
45 ) {
46 super()
47
48 this.resolutions = [
49 {
50 id: '0p',
51 label: $localize`Audio-only`,
52 description: $localize`A <code>.mp4</code> that keeps the original audio track, with no video`
53 },
54 {
55 id: '240p',
56 label: $localize`240p`
57 },
58 {
59 id: '360p',
60 label: $localize`360p`
61 },
62 {
63 id: '480p',
64 label: $localize`480p`
65 },
66 {
67 id: '720p',
68 label: $localize`720p`
69 },
70 {
71 id: '1080p',
72 label: $localize`1080p`
73 },
74 {
75 id: '2160p',
76 label: $localize`2160p`
77 }
78 ]
79
80 this.transcodingThreadOptions = [
81 { value: 0, label: $localize`Auto (via ffmpeg)` },
82 { value: 1, label: '1' },
83 { value: 2, label: '2' },
84 { value: 4, label: '4' },
85 { value: 8, label: '8' }
86 ]
87 }
88
89 get videoQuotaOptions () {
90 return this.configService.videoQuotaOptions
91 }
92
93 get videoQuotaDailyOptions () {
94 return this.configService.videoQuotaDailyOptions
95 }
96
97 get availableThemes () {
98 return this.serverConfig.theme.registered
99 .map(t => t.name)
100 }
101
102 getResolutionKey (resolution: string) {
103 return 'transcoding.resolutions.' + resolution
104 }
105
106 ngOnInit () {
107 this.serverConfig = this.serverService.getTmpConfig()
108 this.serverService.getConfig()
109 .subscribe(config => this.serverConfig = config)
110
111 const formGroupData: { [key in keyof CustomConfig ]: any } = {
112 instance: {
113 name: this.customConfigValidatorsService.INSTANCE_NAME,
114 shortDescription: this.customConfigValidatorsService.INSTANCE_SHORT_DESCRIPTION,
115 description: null,
116
117 isNSFW: false,
118 defaultNSFWPolicy: null,
119
120 terms: null,
121 codeOfConduct: null,
122
123 creationReason: null,
124 moderationInformation: null,
125 administrator: null,
126 maintenanceLifetime: null,
127 businessModel: null,
128
129 hardwareInformation: null,
130
131 categories: null,
132 languages: null,
133
134 defaultClientRoute: null,
135
136 customizations: {
137 javascript: null,
138 css: null
139 }
140 },
141 theme: {
142 default: null
143 },
144 services: {
145 twitter: {
146 username: this.customConfigValidatorsService.SERVICES_TWITTER_USERNAME,
147 whitelisted: null
148 }
149 },
150 cache: {
151 previews: {
152 size: this.customConfigValidatorsService.CACHE_PREVIEWS_SIZE
153 },
154 captions: {
155 size: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE
156 }
157 },
158 signup: {
159 enabled: null,
160 limit: this.customConfigValidatorsService.SIGNUP_LIMIT,
161 requiresEmailVerification: null
162 },
163 import: {
164 videos: {
165 http: {
166 enabled: null
167 },
168 torrent: {
169 enabled: null
170 }
171 }
172 },
173 admin: {
174 email: this.customConfigValidatorsService.ADMIN_EMAIL
175 },
176 contactForm: {
177 enabled: null
178 },
179 user: {
180 videoQuota: this.userValidatorsService.USER_VIDEO_QUOTA,
181 videoQuotaDaily: this.userValidatorsService.USER_VIDEO_QUOTA_DAILY
182 },
183 transcoding: {
184 enabled: null,
185 threads: this.customConfigValidatorsService.TRANSCODING_THREADS,
186 allowAdditionalExtensions: null,
187 allowAudioFiles: null,
188 resolutions: {},
189 hls: {
190 enabled: null
191 },
192 webtorrent: {
193 enabled: null
194 }
195 },
196 autoBlacklist: {
197 videos: {
198 ofUsers: {
199 enabled: null
200 }
201 }
202 },
203 followers: {
204 instance: {
205 enabled: null,
206 manualApproval: null
207 }
208 },
209 followings: {
210 instance: {
211 autoFollowBack: {
212 enabled: null
213 },
214 autoFollowIndex: {
215 enabled: null,
216 indexUrl: this.customConfigValidatorsService.INDEX_URL
217 }
218 }
219 },
220 broadcastMessage: {
221 enabled: null,
222 level: null,
223 dismissable: null,
224 message: null
225 },
226 search: {
227 remoteUri: {
228 users: null,
229 anonymous: null
230 },
231 searchIndex: {
232 enabled: null,
233 url: this.customConfigValidatorsService.SEARCH_INDEX_URL,
234 disableLocalSearch: null,
235 isDefaultSearch: null
236 }
237 }
238 }
239
240 const defaultValues = {
241 transcoding: {
242 resolutions: {}
243 }
244 }
245 for (const resolution of this.resolutions) {
246 defaultValues.transcoding.resolutions[resolution.id] = 'false'
247 formGroupData.transcoding.resolutions[resolution.id] = null
248 }
249
250 this.buildForm(formGroupData)
251 this.loadForm()
252 this.checkTranscodingFields()
253 }
254
255 ngAfterViewChecked () {
256 if (!this.initDone) {
257 this.initDone = true
258 this.gotoAnchor()
259 }
260 }
261
262 isTranscodingEnabled () {
263 return this.form.value['transcoding']['enabled'] === true
264 }
265
266 isSignupEnabled () {
267 return this.form.value['signup']['enabled'] === true
268 }
269
270 isSearchIndexEnabled () {
271 return this.form.value['search']['searchIndex']['enabled'] === true
272 }
273
274 isAutoFollowIndexEnabled () {
275 return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true
276 }
277
278 async formValidated () {
279 this.configService.updateCustomConfig(this.form.getRawValue())
280 .subscribe(
281 res => {
282 this.customConfig = res
283
284 // Reload general configuration
285 this.serverService.resetConfig()
286
287 this.updateForm()
288
289 this.notifier.success($localize`Configuration updated.`)
290 },
291
292 err => this.notifier.error(err.message)
293 )
294 }
295
296 gotoAnchor () {
297 const hashToNav = {
298 'customizations': 'advanced-configuration'
299 }
300 const hash = window.location.hash.replace('#', '')
301
302 if (hash && Object.keys(hashToNav).includes(hash)) {
303 this.nav.select(hashToNav[hash])
304 setTimeout(() => this.viewportScroller.scrollToAnchor(hash), 100)
305 }
306 }
307
308 private updateForm () {
309 this.form.patchValue(this.customConfig)
310 }
311
312 private loadForm () {
313 forkJoin([
314 this.configService.getCustomConfig(),
315 this.serverService.getVideoLanguages(),
316 this.serverService.getVideoCategories()
317 ]).subscribe(
318 ([ config, languages, categories ]) => {
319 this.customConfig = config
320
321 this.languageItems = languages.map(l => ({ label: l.label, id: l.id }))
322 this.categoryItems = categories.map(l => ({ label: l.label, id: l.id + '' }))
323
324 this.updateForm()
325 // Force form validation
326 this.forceCheck()
327 },
328
329 err => this.notifier.error(err.message)
330 )
331 }
332
333 private checkTranscodingFields () {
334 const hlsControl = this.form.get('transcoding.hls.enabled')
335 const webtorrentControl = this.form.get('transcoding.webtorrent.enabled')
336
337 webtorrentControl.valueChanges
338 .subscribe(newValue => {
339 if (newValue === false && !hlsControl.disabled) {
340 hlsControl.disable()
341 }
342
343 if (newValue === true && !hlsControl.enabled) {
344 hlsControl.enable()
345 }
346 })
347
348 hlsControl.valueChanges
349 .subscribe(newValue => {
350 if (newValue === false && !webtorrentControl.disabled) {
351 webtorrentControl.disable()
352 }
353
354 if (newValue === true && !webtorrentControl.enabled) {
355 webtorrentControl.enable()
356 }
357 })
358 }
359 }