Lazy description and previews to video form
[oweals/peertube.git] / client / src / app / videos / +video-edit / video-add.component.ts
1 import { Component, OnInit, ViewChild } from '@angular/core'
2 import { FormBuilder, FormGroup } from '@angular/forms'
3 import { Router } from '@angular/router'
4
5 import { NotificationsService } from 'angular2-notifications'
6
7 import {
8   FormReactive,
9   VIDEO_NAME,
10   VIDEO_CATEGORY,
11   VIDEO_LICENCE,
12   VIDEO_LANGUAGE,
13   VIDEO_DESCRIPTION,
14   VIDEO_TAGS,
15   VIDEO_CHANNEL,
16   VIDEO_FILE
17 } from '../../shared'
18 import { AuthService, ServerService } from '../../core'
19 import { VideoService } from '../shared'
20 import { VideoCreate } from '../../../../../shared'
21 import { HttpEventType, HttpResponse } from '@angular/common/http'
22
23 @Component({
24   selector: 'my-videos-add',
25   styleUrls: [ './video-edit.component.scss' ],
26   templateUrl: './video-add.component.html'
27 })
28
29 export class VideoAddComponent extends FormReactive implements OnInit {
30   @ViewChild('videofileInput') videofileInput
31
32   progressPercent = 0
33   tags: string[] = []
34   videoCategories = []
35   videoLicences = []
36   videoLanguages = []
37   userVideoChannels = []
38
39   tagValidators = VIDEO_TAGS.VALIDATORS
40   tagValidatorsMessages = VIDEO_TAGS.MESSAGES
41
42   error: string
43   form: FormGroup
44   formErrors = {
45     name: '',
46     category: '',
47     licence: '',
48     language: '',
49     channelId: '',
50     description: '',
51     videofile: ''
52   }
53   validationMessages = {
54     name: VIDEO_NAME.MESSAGES,
55     category: VIDEO_CATEGORY.MESSAGES,
56     licence: VIDEO_LICENCE.MESSAGES,
57     language: VIDEO_LANGUAGE.MESSAGES,
58     channelId: VIDEO_CHANNEL.MESSAGES,
59     description: VIDEO_DESCRIPTION.MESSAGES,
60     videofile: VIDEO_FILE.MESSAGES
61   }
62
63   constructor (
64     private formBuilder: FormBuilder,
65     private router: Router,
66     private notificationsService: NotificationsService,
67     private authService: AuthService,
68     private serverService: ServerService,
69     private videoService: VideoService
70   ) {
71     super()
72   }
73
74   get filename () {
75     return this.form.value['videofile']
76   }
77
78   buildForm () {
79     this.form = this.formBuilder.group({
80       name: [ '', VIDEO_NAME.VALIDATORS ],
81       nsfw: [ false ],
82       category: [ '', VIDEO_CATEGORY.VALIDATORS ],
83       licence: [ '', VIDEO_LICENCE.VALIDATORS ],
84       language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
85       channelId: [ '', VIDEO_CHANNEL.VALIDATORS ],
86       description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
87       videofile: [ '', VIDEO_FILE.VALIDATORS ],
88       tags: [ '' ]
89     })
90
91     this.form.valueChanges.subscribe(data => this.onValueChanged(data))
92   }
93
94   ngOnInit () {
95     this.videoCategories = this.serverService.getVideoCategories()
96     this.videoLicences = this.serverService.getVideoLicences()
97     this.videoLanguages = this.serverService.getVideoLanguages()
98
99     this.buildForm()
100
101     this.authService.userInformationLoaded
102       .subscribe(
103         () => {
104           const user = this.authService.getUser()
105           if (!user) return
106
107           const videoChannels = user.videoChannels
108           if (Array.isArray(videoChannels) === false) return
109
110           this.userVideoChannels = videoChannels.map(v => ({ id: v.id, label: v.name }))
111
112           this.form.patchValue({ channelId: this.userVideoChannels[0].id })
113         }
114       )
115   }
116
117   // The goal is to keep reactive form validation (required field)
118   // https://stackoverflow.com/a/44238894
119   fileChange ($event) {
120     this.form.controls['videofile'].setValue($event.target.files[0].name)
121   }
122
123   removeFile () {
124     this.videofileInput.nativeElement.value = ''
125     this.form.controls['videofile'].setValue('')
126   }
127
128   checkForm () {
129     this.forceCheck()
130
131     return this.form.valid
132   }
133
134   upload () {
135     if (this.checkForm() === false) {
136       return
137     }
138
139     const formValue: VideoCreate = this.form.value
140
141     const name = formValue.name
142     const nsfw = formValue.nsfw
143     const category = formValue.category
144     const licence = formValue.licence
145     const language = formValue.language
146     const channelId = formValue.channelId
147     const description = formValue.description
148     const tags = formValue.tags
149     const videofile = this.videofileInput.nativeElement.files[0]
150
151     const formData = new FormData()
152     formData.append('name', name)
153     formData.append('category', '' + category)
154     formData.append('nsfw', '' + nsfw)
155     formData.append('licence', '' + licence)
156     formData.append('channelId', '' + channelId)
157     formData.append('videofile', videofile)
158
159     // Language is optional
160     if (language) {
161       formData.append('language', '' + language)
162     }
163
164     formData.append('description', description)
165
166     for (let i = 0; i < tags.length; i++) {
167       formData.append(`tags[${i}]`, tags[i])
168     }
169
170     this.videoService.uploadVideo(formData).subscribe(
171       event => {
172         if (event.type === HttpEventType.UploadProgress) {
173           this.progressPercent = Math.round(100 * event.loaded / event.total)
174         } else if (event instanceof HttpResponse) {
175           console.log('Video uploaded.')
176           this.notificationsService.success('Success', 'Video uploaded.')
177
178           // Display all the videos once it's finished
179           this.router.navigate([ '/videos/list' ])
180         }
181       },
182
183       err => {
184         // Reset progress
185         this.progressPercent = 0
186         this.error = err.message
187       }
188     )
189   }
190 }