]> git.immae.eu Git - github/Chocobozzz/PeerTube.git/blobdiff - client/src/app/+videos/+video-edit/shared/video-edit.component.ts
Rename input toggle hidden to input text
[github/Chocobozzz/PeerTube.git] / client / src / app / +videos / +video-edit / shared / video-edit.component.ts
index 8ce36121d0b65408a67cd57975308afa9de080ee..16b964482a7d72360995dd88a57b1df25fe9d1a2 100644 (file)
@@ -1,8 +1,8 @@
 import { forkJoin } from 'rxjs'
 import { map } from 'rxjs/operators'
-import { SelectChannelItem } from 'src/types/select-options-item.model'
+import { SelectChannelItem, SelectOptionsItem } from 'src/types/select-options-item.model'
 import { ChangeDetectorRef, Component, EventEmitter, Input, NgZone, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'
-import { AbstractControl, FormArray, FormControl, FormGroup, ValidationErrors, Validators } from '@angular/forms'
+import { AbstractControl, FormArray, FormControl, FormGroup, Validators } from '@angular/forms'
 import { HooksService, PluginService, ServerService } from '@app/core'
 import { removeElementFromArray } from '@app/helpers'
 import { BuildFormValidator } from '@app/shared/form-validators'
@@ -21,11 +21,12 @@ import {
 } from '@app/shared/form-validators/video-validators'
 import { FormReactiveValidationMessages, FormValidatorService } from '@app/shared/shared-forms'
 import { InstanceService } from '@app/shared/shared-instance'
-import { VideoCaptionEdit, VideoEdit, VideoService } from '@app/shared/shared-main'
+import { VideoCaptionEdit, VideoCaptionWithPathEdit, VideoEdit, VideoService } from '@app/shared/shared-main'
 import { PluginInfo } from '@root-helpers/plugins-manager'
 import {
   HTMLServerConfig,
   LiveVideo,
+  LiveVideoLatencyMode,
   RegisterClientFormFieldOptions,
   RegisterClientVideoFieldOptions,
   VideoConstant,
@@ -34,6 +35,7 @@ import {
 } from '@shared/models'
 import { I18nPrimengCalendarService } from './i18n-primeng-calendar.service'
 import { VideoCaptionAddModalComponent } from './video-caption-add-modal.component'
+import { VideoCaptionEditModalComponent } from './video-caption-edit-modal/video-caption-edit-modal.component'
 import { VideoEditType } from './video-edit.type'
 
 type VideoLanguages = VideoConstant<string> & { group?: string }
@@ -56,15 +58,16 @@ export class VideoEditComponent implements OnInit, OnDestroy {
   @Input() videoToUpdate: VideoDetails
 
   @Input() userVideoChannels: SelectChannelItem[] = []
-  @Input() schedulePublicationPossible = true
+  @Input() forbidScheduledPublication = true
 
-  @Input() videoCaptions: (VideoCaptionEdit & { captionPath?: string })[] = []
+  @Input() videoCaptions: VideoCaptionWithPathEdit[] = []
 
   @Input() waitTranscodingEnabled = true
   @Input() type: VideoEditType
   @Input() liveVideo: LiveVideo
 
   @ViewChild('videoCaptionAddModal', { static: true }) videoCaptionAddModal: VideoCaptionAddModalComponent
+  @ViewChild('videoCaptionEditModal', { static: true }) editCaptionModal: VideoCaptionEditModalComponent
 
   @Output() formBuilt = new EventEmitter<void>()
   @Output() pluginFieldsAdded = new EventEmitter<void>()
@@ -76,6 +79,23 @@ export class VideoEditComponent implements OnInit, OnDestroy {
   videoCategories: VideoConstant<number>[] = []
   videoLicences: VideoConstant<number>[] = []
   videoLanguages: VideoLanguages[] = []
+  latencyModes: SelectOptionsItem[] = [
+    {
+      id: LiveVideoLatencyMode.SMALL_LATENCY,
+      label: $localize`Small latency`,
+      description: $localize`Reduce latency to ~15s disabling P2P`
+    },
+    {
+      id: LiveVideoLatencyMode.DEFAULT,
+      label: $localize`Default`,
+      description: $localize`Average latency of 30s`
+    },
+    {
+      id: LiveVideoLatencyMode.HIGH_LATENCY,
+      label: $localize`High latency`,
+      description: $localize`Average latency of 60s increasing P2P ratio`
+    }
+  ]
 
   pluginDataFormGroup: FormGroup
 
@@ -139,6 +159,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
       originallyPublishedAt: VIDEO_ORIGINALLY_PUBLISHED_AT_VALIDATOR,
       liveStreamKey: null,
       permanentLive: null,
+      latencyMode: null,
       saveReplay: null
     }
 
@@ -159,7 +180,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
 
     this.trackChannelChange()
     this.trackPrivacyChange()
-    this.trackLivePermanentFieldChange()
 
     this.formBuilt.emit()
   }
@@ -198,13 +218,15 @@ export class VideoEditComponent implements OnInit, OnDestroy {
       .subscribe(privacies => {
         this.videoPrivacies = this.videoService.explainedPrivacyLabels(privacies).videoPrivacies
 
-        if (this.schedulePublicationPossible) {
-          this.videoPrivacies.push({
-            id: this.SPECIAL_SCHEDULED_PRIVACY,
-            label: $localize`Scheduled`,
-            description: $localize`Hide the video until a specific date`
-          })
-        }
+        // Can't schedule publication if private privacy is not available (could be deleted by a plugin)
+        const hasPrivatePrivacy = this.videoPrivacies.some(p => p.id === VideoPrivacy.PRIVATE)
+        if (this.forbidScheduledPublication || !hasPrivatePrivacy) return
+
+        this.videoPrivacies.push({
+          id: this.SPECIAL_SCHEDULED_PRIVACY,
+          label: $localize`Scheduled`,
+          description: $localize`Hide the video until a specific date`
+        })
       })
 
     this.initialVideoCaptions = this.videoCaptions.map(c => c.language.id)
@@ -226,12 +248,12 @@ export class VideoEditComponent implements OnInit, OnDestroy {
                .map(c => c.language.id)
   }
 
-  onCaptionAdded (caption: VideoCaptionEdit) {
+  onCaptionEdited (caption: VideoCaptionEdit) {
     const existingCaption = this.videoCaptions.find(c => c.language.id === caption.language.id)
 
     // Replace existing caption?
     if (existingCaption) {
-      Object.assign(existingCaption, caption, { action: 'CREATE' as 'CREATE' })
+      Object.assign(existingCaption, caption)
     } else {
       this.videoCaptions.push(
         Object.assign(caption, { action: 'CREATE' as 'CREATE' })
@@ -249,7 +271,7 @@ export class VideoEditComponent implements OnInit, OnDestroy {
     }
 
     // This caption is not on the server, just remove it from our array
-    if (caption.action === 'CREATE') {
+    if (caption.action === 'CREATE' || caption.action === 'UPDATE') {
       removeElementFromArray(this.videoCaptions, caption)
       return
     }
@@ -269,6 +291,10 @@ export class VideoEditComponent implements OnInit, OnDestroy {
     return this.form.value['permanentLive'] === true
   }
 
+  isLatencyModeEnabled () {
+    return this.serverConfig.live.latencySetting.enabled
+  }
+
   isPluginFieldHidden (pluginField: PluginField) {
     if (typeof pluginField.commonOptions.hidden !== 'function') return false
 
@@ -309,10 +335,10 @@ export class VideoEditComponent implements OnInit, OnDestroy {
     for (const setting of this.pluginFields) {
       await this.pluginService.translateSetting(setting.pluginInfo.plugin.npmName, setting.commonOptions)
 
-      const validator = (control: AbstractControl): ValidationErrors | null => {
+      const validator = async (control: AbstractControl) => {
         if (!setting.commonOptions.error) return null
 
-        const error = setting.commonOptions.error({ formValues: this.form.value, value: control.value })
+        const error = await setting.commonOptions.error({ formValues: this.form.value, value: control.value })
 
         return error?.error ? { [setting.commonOptions.name]: error.text } : null
       }
@@ -320,7 +346,8 @@ export class VideoEditComponent implements OnInit, OnDestroy {
       const name = setting.commonOptions.name
 
       pluginObj[name] = {
-        VALIDATORS: [ validator ],
+        ASYNC_VALIDATORS: [ validator ],
+        VALIDATORS: [],
         MESSAGES: {}
       }
 
@@ -342,6 +369,9 @@ export class VideoEditComponent implements OnInit, OnDestroy {
 
     this.cd.detectChanges()
     this.pluginFieldsAdded.emit()
+
+    // Plugins may need other control values to calculate potential errors
+    this.form.valueChanges.subscribe(() => this.formValidatorService.updateTreeValidity(this.pluginDataFormGroup))
   }
 
   private trackPrivacyChange () {
@@ -426,24 +456,6 @@ export class VideoEditComponent implements OnInit, OnDestroy {
       )
   }
 
-  private trackLivePermanentFieldChange () {
-    // We will update the "support" field depending on the channel
-    this.form.controls['permanentLive']
-      .valueChanges
-      .subscribe(
-        permanentLive => {
-          const saveReplayControl = this.form.controls['saveReplay']
-
-          if (permanentLive === true) {
-            saveReplayControl.setValue(false)
-            saveReplayControl.disable()
-          } else {
-            saveReplayControl.enable()
-          }
-        }
-      )
-  }
-
   private updateSupportField (support: string) {
     return this.form.patchValue({ support: support || '' })
   }