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'
8 CustomConfigValidatorsService,
13 } from '@app/shared/shared-forms'
14 import { NgbNav } from '@ng-bootstrap/ng-bootstrap'
15 import { CustomConfig, ServerConfig } from '@shared/models'
18 selector: 'my-edit-custom-config',
19 templateUrl: './edit-custom-config.component.html',
20 styleUrls: [ './edit-custom-config.component.scss' ]
22 export class EditCustomConfigComponent extends FormReactive implements OnInit, AfterViewChecked {
23 // FIXME: use built-in router
24 @ViewChild('nav') nav: NgbNav
27 customConfig: CustomConfig
29 resolutions: { id: string, label: string, description?: string }[] = []
30 transcodingThreadOptions: { label: string, value: number }[] = []
32 languageItems: SelectOptionsItem[] = []
33 categoryItems: SelectOptionsItem[] = []
35 private serverConfig: ServerConfig
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
51 label: $localize`Audio-only`,
52 description: $localize`A <code>.mp4</code> that keeps the original audio track, with no video`
56 label: $localize`240p`
60 label: $localize`360p`
64 label: $localize`480p`
68 label: $localize`720p`
72 label: $localize`1080p`
76 label: $localize`2160p`
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' }
89 get videoQuotaOptions () {
90 return this.configService.videoQuotaOptions
93 get videoQuotaDailyOptions () {
94 return this.configService.videoQuotaDailyOptions
97 get availableThemes () {
98 return this.serverConfig.theme.registered
102 getResolutionKey (resolution: string) {
103 return 'transcoding.resolutions.' + resolution
107 this.serverConfig = this.serverService.getTmpConfig()
108 this.serverService.getConfig()
109 .subscribe(config => this.serverConfig = config)
111 const formGroupData: { [key in keyof CustomConfig ]: any } = {
113 name: this.customConfigValidatorsService.INSTANCE_NAME,
114 shortDescription: this.customConfigValidatorsService.INSTANCE_SHORT_DESCRIPTION,
118 defaultNSFWPolicy: null,
123 creationReason: null,
124 moderationInformation: null,
126 maintenanceLifetime: null,
129 hardwareInformation: null,
134 defaultClientRoute: null,
146 username: this.customConfigValidatorsService.SERVICES_TWITTER_USERNAME,
152 size: this.customConfigValidatorsService.CACHE_PREVIEWS_SIZE
155 size: this.customConfigValidatorsService.CACHE_CAPTIONS_SIZE
160 limit: this.customConfigValidatorsService.SIGNUP_LIMIT,
161 requiresEmailVerification: null
174 email: this.customConfigValidatorsService.ADMIN_EMAIL
180 videoQuota: this.userValidatorsService.USER_VIDEO_QUOTA,
181 videoQuotaDaily: this.userValidatorsService.USER_VIDEO_QUOTA_DAILY
185 threads: this.customConfigValidatorsService.TRANSCODING_THREADS,
186 allowAdditionalExtensions: null,
187 allowAudioFiles: null,
216 indexUrl: this.customConfigValidatorsService.INDEX_URL
233 url: this.customConfigValidatorsService.SEARCH_INDEX_URL,
234 disableLocalSearch: null,
235 isDefaultSearch: null
240 const defaultValues = {
245 for (const resolution of this.resolutions) {
246 defaultValues.transcoding.resolutions[resolution.id] = 'false'
247 formGroupData.transcoding.resolutions[resolution.id] = null
250 this.buildForm(formGroupData)
252 this.checkTranscodingFields()
255 ngAfterViewChecked () {
256 if (!this.initDone) {
262 isTranscodingEnabled () {
263 return this.form.value['transcoding']['enabled'] === true
267 return this.form.value['signup']['enabled'] === true
270 isSearchIndexEnabled () {
271 return this.form.value['search']['searchIndex']['enabled'] === true
274 isAutoFollowIndexEnabled () {
275 return this.form.value['followings']['instance']['autoFollowIndex']['enabled'] === true
278 async formValidated () {
279 this.configService.updateCustomConfig(this.form.getRawValue())
282 this.customConfig = res
284 // Reload general configuration
285 this.serverService.resetConfig()
289 this.notifier.success($localize`Configuration updated.`)
292 err => this.notifier.error(err.message)
298 'customizations': 'advanced-configuration'
300 const hash = window.location.hash.replace('#', '')
302 if (hash && Object.keys(hashToNav).includes(hash)) {
303 this.nav.select(hashToNav[hash])
304 setTimeout(() => this.viewportScroller.scrollToAnchor(hash), 100)
308 private updateForm () {
309 this.form.patchValue(this.customConfig)
312 private loadForm () {
314 this.configService.getCustomConfig(),
315 this.serverService.getVideoLanguages(),
316 this.serverService.getVideoCategories()
318 ([ config, languages, categories ]) => {
319 this.customConfig = config
321 this.languageItems = languages.map(l => ({ label: l.label, id: l.id }))
322 this.categoryItems = categories.map(l => ({ label: l.label, id: l.id + '' }))
325 // Force form validation
329 err => this.notifier.error(err.message)
333 private checkTranscodingFields () {
334 const hlsControl = this.form.get('transcoding.hls.enabled')
335 const webtorrentControl = this.form.get('transcoding.webtorrent.enabled')
337 webtorrentControl.valueChanges
338 .subscribe(newValue => {
339 if (newValue === false && !hlsControl.disabled) {
343 if (newValue === true && !hlsControl.enabled) {
348 hlsControl.valueChanges
349 .subscribe(newValue => {
350 if (newValue === false && !webtorrentControl.disabled) {
351 webtorrentControl.disable()
354 if (newValue === true && !webtorrentControl.enabled) {
355 webtorrentControl.enable()