aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app/videos')
-rw-r--r--client/src/app/videos/shared/video.service.ts25
-rw-r--r--client/src/app/videos/video-edit/video-add.component.html21
-rw-r--r--client/src/app/videos/video-edit/video-add.component.ts160
-rw-r--r--client/src/app/videos/video-edit/video-update.component.ts1
-rw-r--r--client/src/app/videos/video-watch/video-report.component.ts2
-rw-r--r--client/src/app/videos/video-watch/video-watch.component.ts6
6 files changed, 95 insertions, 120 deletions
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts
index b6d2a0666..cfce4cb16 100644
--- a/client/src/app/videos/shared/video.service.ts
+++ b/client/src/app/videos/shared/video.service.ts
@@ -2,7 +2,7 @@ import { Injectable } from '@angular/core'
2import { Observable } from 'rxjs/Observable' 2import { Observable } from 'rxjs/Observable'
3import 'rxjs/add/operator/catch' 3import 'rxjs/add/operator/catch'
4import 'rxjs/add/operator/map' 4import 'rxjs/add/operator/map'
5import { HttpClient, HttpParams } from '@angular/common/http' 5import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
6 6
7import { Search } from '../../shared' 7import { Search } from '../../shared'
8import { SortField } from './sort-field.type' 8import { SortField } from './sort-field.type'
@@ -14,13 +14,14 @@ import {
14import { Video } from './video.model' 14import { Video } from './video.model'
15import { VideoPagination } from './video-pagination.model' 15import { VideoPagination } from './video-pagination.model'
16import { 16import {
17UserVideoRate, 17 VideoCreate,
18VideoRateType, 18 UserVideoRate,
19VideoUpdate, 19 VideoRateType,
20VideoAbuseCreate, 20 VideoUpdate,
21UserVideoRateUpdate, 21 VideoAbuseCreate,
22Video as VideoServerModel, 22 UserVideoRateUpdate,
23ResultList 23 Video as VideoServerModel,
24 ResultList
24} from '../../../../../shared' 25} from '../../../../../shared'
25 26
26@Injectable() 27@Injectable()
@@ -73,6 +74,14 @@ export class VideoService {
73 .catch(this.restExtractor.handleError) 74 .catch(this.restExtractor.handleError)
74 } 75 }
75 76
77 // uploadVideo (video: VideoCreate) {
78 uploadVideo (video: any) {
79 const req = new HttpRequest('POST', `${VideoService.BASE_VIDEO_URL}/upload`, video, { reportProgress: true })
80
81 return this.authHttp.request(req)
82 .catch(this.restExtractor.handleError)
83 }
84
76 getVideos (videoPagination: VideoPagination, sort: SortField) { 85 getVideos (videoPagination: VideoPagination, sort: SortField) {
77 const pagination = this.videoPaginationToRestPagination(videoPagination) 86 const pagination = this.videoPaginationToRestPagination(videoPagination)
78 87
diff --git a/client/src/app/videos/video-edit/video-add.component.html b/client/src/app/videos/video-edit/video-add.component.html
index 7ad671ae7..cf8fc2b80 100644
--- a/client/src/app/videos/video-edit/video-add.component.html
+++ b/client/src/app/videos/video-edit/video-add.component.html
@@ -3,7 +3,7 @@
3 3
4 <h3>Upload a video</h3> 4 <h3>Upload a video</h3>
5 5
6 <div *ngIf="error" class="alert alert-danger">{{ error }}</div> 6 <div *ngIf="error !== undefined" class="alert alert-danger">{{ error }}</div>
7 7
8 <form novalidate [formGroup]="form"> 8 <form novalidate [formGroup]="form">
9 <div class="form-group"> 9 <div class="form-group">
@@ -62,7 +62,7 @@
62 </div> 62 </div>
63 63
64 <div class="form-group"> 64 <div class="form-group">
65 <label for="tags" class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span> 65 <label class="label-tags">Tags</label> <span class="little-information">(press enter to add the tag)</span>
66 <tag-input 66 <tag-input
67 [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages" 67 [ngModel]="tags" [validators]="tagValidators" [errorMessages]="tagValidatorsMessages"
68 formControlName="tags" maxItems="3" modelAsStrings="true" 68 formControlName="tags" maxItems="3" modelAsStrings="true"
@@ -71,25 +71,22 @@
71 71
72 <div class="form-group"> 72 <div class="form-group">
73 <label for="videofile">File</label> 73 <label for="videofile">File</label>
74 <div class="btn btn-default btn-file" [ngClass]="{ 'disabled': filename !== null }" > 74 <div class="btn btn-default btn-file">
75 <span>Select the video...</span> 75 <span>Select the video...</span>
76 <input 76 <input #videofileInput type="file" name="videofile" id="videofile" (change)="fileChange($event)" />
77 type="file" name="videofile" id="videofile" 77 <input type="hidden" name="videofileHidden" formControlName="videofile"/>
78 ng2FileSelect [uploader]="uploader" [disabled]="filename !== null"
79 (change)="fileChanged()"
80 >
81 </div> 78 </div>
82 </div> 79 </div>
83 80
84 <div class="file-to-upload"> 81 <div class="file-to-upload">
85 <div class="file" *ngIf="uploader.queue.length > 0"> 82 <div class="file" *ngIf="filename">
86 <span class="filename">{{ filename }}</span> 83 <span class="filename">{{ filename }}</span>
87 <span class="glyphicon glyphicon-remove" (click)="removeFile()"></span> 84 <span class="glyphicon glyphicon-remove" (click)="removeFile()"></span>
88 </div> 85 </div>
89 </div> 86 </div>
90 87
91 <div *ngIf="fileError" class="alert alert-danger"> 88 <div *ngIf="formErrors.videofile" class="alert alert-danger">
92 {{ fileError }} 89 {{ formErrors.videofile }}
93 </div> 90 </div>
94 91
95 <div class="form-group"> 92 <div class="form-group">
@@ -105,7 +102,7 @@
105 </div> 102 </div>
106 103
107 <div class="progress"> 104 <div class="progress">
108 <progressbar [value]="uploader.progress" max="100"></progressbar> 105 <progressbar [value]="progressPercent" max="100"></progressbar>
109 </div> 106 </div>
110 107
111 <div class="form-group"> 108 <div class="form-group">
diff --git a/client/src/app/videos/video-edit/video-add.component.ts b/client/src/app/videos/video-edit/video-add.component.ts
index 42b11cd08..537ef9bc3 100644
--- a/client/src/app/videos/video-edit/video-add.component.ts
+++ b/client/src/app/videos/video-edit/video-add.component.ts
@@ -1,11 +1,9 @@
1import { Component, ElementRef, OnInit } from '@angular/core' 1import { Component, OnInit, ViewChild } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms' 2import { FormBuilder, FormGroup } from '@angular/forms'
3import { Router } from '@angular/router' 3import { Router } from '@angular/router'
4 4
5import { FileUploader } from 'ng2-file-upload/ng2-file-upload'
6import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
7 6
8import { AuthService } from '../../core'
9import { 7import {
10 FormReactive, 8 FormReactive,
11 VIDEO_NAME, 9 VIDEO_NAME,
@@ -17,6 +15,8 @@ import {
17} from '../../shared' 15} from '../../shared'
18import { VideoService } from '../shared' 16import { VideoService } from '../shared'
19import { VideoCreate } from '../../../../../shared' 17import { VideoCreate } from '../../../../../shared'
18import { HttpEventType, HttpResponse } from '@angular/common/http'
19import { VIDEO_FILE } from '../../shared/forms/form-validators/video'
20 20
21@Component({ 21@Component({
22 selector: 'my-videos-add', 22 selector: 'my-videos-add',
@@ -25,8 +25,10 @@ import { VideoCreate } from '../../../../../shared'
25}) 25})
26 26
27export class VideoAddComponent extends FormReactive implements OnInit { 27export class VideoAddComponent extends FormReactive implements OnInit {
28 @ViewChild('videofileInput') videofileInput
29
30 progressPercent = 0
28 tags: string[] = [] 31 tags: string[] = []
29 uploader: FileUploader
30 videoCategories = [] 32 videoCategories = []
31 videoLicences = [] 33 videoLicences = []
32 videoLanguages = [] 34 videoLanguages = []
@@ -34,29 +36,26 @@ export class VideoAddComponent extends FormReactive implements OnInit {
34 tagValidators = VIDEO_TAGS.VALIDATORS 36 tagValidators = VIDEO_TAGS.VALIDATORS
35 tagValidatorsMessages = VIDEO_TAGS.MESSAGES 37 tagValidatorsMessages = VIDEO_TAGS.MESSAGES
36 38
37 error: string = null 39 error: string
38 form: FormGroup 40 form: FormGroup
39 formErrors = { 41 formErrors = {
40 name: '', 42 name: '',
41 category: '', 43 category: '',
42 licence: '', 44 licence: '',
43 language: '', 45 language: '',
44 description: '' 46 description: '',
47 videofile: ''
45 } 48 }
46 validationMessages = { 49 validationMessages = {
47 name: VIDEO_NAME.MESSAGES, 50 name: VIDEO_NAME.MESSAGES,
48 category: VIDEO_CATEGORY.MESSAGES, 51 category: VIDEO_CATEGORY.MESSAGES,
49 licence: VIDEO_LICENCE.MESSAGES, 52 licence: VIDEO_LICENCE.MESSAGES,
50 language: VIDEO_LANGUAGE.MESSAGES, 53 language: VIDEO_LANGUAGE.MESSAGES,
51 description: VIDEO_DESCRIPTION.MESSAGES 54 description: VIDEO_DESCRIPTION.MESSAGES,
55 videofile: VIDEO_FILE.MESSAGES
52 } 56 }
53 57
54 // Special error messages
55 fileError = ''
56
57 constructor ( 58 constructor (
58 private authService: AuthService,
59 private elementRef: ElementRef,
60 private formBuilder: FormBuilder, 59 private formBuilder: FormBuilder,
61 private router: Router, 60 private router: Router,
62 private notificationsService: NotificationsService, 61 private notificationsService: NotificationsService,
@@ -66,11 +65,7 @@ export class VideoAddComponent extends FormReactive implements OnInit {
66 } 65 }
67 66
68 get filename () { 67 get filename () {
69 if (this.uploader.queue.length === 0) { 68 return this.form.value['videofile']
70 return null
71 }
72
73 return this.uploader.queue[0].file.name
74 } 69 }
75 70
76 buildForm () { 71 buildForm () {
@@ -81,7 +76,8 @@ export class VideoAddComponent extends FormReactive implements OnInit {
81 licence: [ '', VIDEO_LICENCE.VALIDATORS ], 76 licence: [ '', VIDEO_LICENCE.VALIDATORS ],
82 language: [ '', VIDEO_LANGUAGE.VALIDATORS ], 77 language: [ '', VIDEO_LANGUAGE.VALIDATORS ],
83 description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], 78 description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
84 tags: [ ''] 79 videofile: [ '', VIDEO_FILE.VALIDATORS ],
80 tags: [ '' ]
85 }) 81 })
86 82
87 this.form.valueChanges.subscribe(data => this.onValueChanged(data)) 83 this.form.valueChanges.subscribe(data => this.onValueChanged(data))
@@ -92,60 +88,24 @@ export class VideoAddComponent extends FormReactive implements OnInit {
92 this.videoLicences = this.videoService.videoLicences 88 this.videoLicences = this.videoService.videoLicences
93 this.videoLanguages = this.videoService.videoLanguages 89 this.videoLanguages = this.videoService.videoLanguages
94 90
95 this.uploader = new FileUploader({
96 authToken: this.authService.getRequestHeaderValue(),
97 queueLimit: 1,
98 url: API_URL + '/api/v1/videos/upload',
99 removeAfterUpload: true
100 })
101
102 this.uploader.onBuildItemForm = (item, form: FormData) => {
103 const formValue: VideoCreate = this.form.value
104
105 const name = formValue.name
106 const nsfw = formValue.nsfw
107 const category = formValue.category
108 const licence = formValue.licence
109 const language = formValue.language
110 const description = formValue.description
111 const tags = formValue.tags
112
113 form.append('name', name)
114 form.append('category', '' + category)
115 form.append('nsfw', '' + nsfw)
116 form.append('licence', '' + licence)
117
118 // Language is optional
119 if (language) {
120 form.append('language', '' + language)
121 }
122
123 form.append('description', description)
124
125 for (let i = 0; i < tags.length; i++) {
126 form.append(`tags[${i}]`, tags[i])
127 }
128 }
129
130 this.buildForm() 91 this.buildForm()
131 } 92 }
132 93
133 checkForm () { 94 // The goal is to keep reactive form validation (required field)
134 this.forceCheck() 95 // https://stackoverflow.com/a/44238894
135 96 fileChange ($event) {
136 if (this.filename === null) { 97 this.form.controls['videofile'].setValue($event.target.files[0].name)
137 this.fileError = 'You did not add a file.'
138 }
139
140 return this.form.valid === true && this.fileError === ''
141 } 98 }
142 99
143 fileChanged () { 100 removeFile () {
144 this.fileError = '' 101 this.videofileInput.nativeElement.value = ''
102 this.form.controls['videofile'].setValue('')
145 } 103 }
146 104
147 removeFile () { 105 checkForm () {
148 this.uploader.clearQueue() 106 this.forceCheck()
107
108 return this.form.valid
149 } 109 }
150 110
151 upload () { 111 upload () {
@@ -153,39 +113,49 @@ export class VideoAddComponent extends FormReactive implements OnInit {
153 return 113 return
154 } 114 }
155 115
156 const item = this.uploader.queue[0] 116 const formValue: VideoCreate = this.form.value
157 // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 117
158 item.alias = 'videofile' 118 const name = formValue.name
159 119 const nsfw = formValue.nsfw
160 item.onSuccess = () => { 120 const category = formValue.category
161 console.log('Video uploaded.') 121 const licence = formValue.licence
162 this.notificationsService.success('Success', 'Video uploaded.') 122 const language = formValue.language
163 123 const description = formValue.description
164 // Print all the videos once it's finished 124 const tags = formValue.tags
165 this.router.navigate(['/videos/list']) 125 const videofile = this.videofileInput.nativeElement.files[0]
126
127 const formData = new FormData()
128 formData.append('name', name)
129 formData.append('category', '' + category)
130 formData.append('nsfw', '' + nsfw)
131 formData.append('licence', '' + licence)
132 formData.append('videofile', videofile)
133
134 // Language is optional
135 if (language) {
136 formData.append('language', '' + language)
166 } 137 }
167 138
168 item.onError = (response: string, status: number) => { 139 formData.append('description', description)
169 // We need to handle manually these cases because we use the FileUpload component 140
170 if (status === 400) { 141 for (let i = 0; i < tags.length; i++) {
171 this.error = response 142 formData.append(`tags[${i}]`, tags[i])
172 } else if (status === 401) {
173 this.error = 'Access token was expired, refreshing token...'
174 this.authService.refreshAccessToken().subscribe(
175 () => {
176 // Update the uploader request header
177 this.uploader.authToken = this.authService.getRequestHeaderValue()
178 this.error += ' access token refreshed. Please retry your request.'
179 }
180 )
181 } else if (status === 403) {
182 this.error = 'Your video quota is reached, you can\'t upload this video.'
183 } else {
184 this.error = 'Unknown error'
185 console.error(this.error)
186 }
187 } 143 }
188 144
189 this.uploader.uploadAll() 145 this.videoService.uploadVideo(formData).subscribe(
146 event => {
147 if (event.type === HttpEventType.UploadProgress) {
148 this.progressPercent = Math.round(100 * event.loaded / event.total)
149 } else if (event instanceof HttpResponse) {
150 console.log('Video uploaded.')
151 this.notificationsService.success('Success', 'Video uploaded.')
152
153 // Display all the videos once it's finished
154 this.router.navigate([ '/videos/list '])
155 }
156 },
157
158 err => this.error = err.message
159 )
190 } 160 }
191} 161}
diff --git a/client/src/app/videos/video-edit/video-update.component.ts b/client/src/app/videos/video-edit/video-update.component.ts
index 6c57a23d8..141ed3522 100644
--- a/client/src/app/videos/video-edit/video-update.component.ts
+++ b/client/src/app/videos/video-edit/video-update.component.ts
@@ -2,7 +2,6 @@ import { Component, ElementRef, OnInit } from '@angular/core'
2import { FormBuilder, FormGroup } from '@angular/forms' 2import { FormBuilder, FormGroup } from '@angular/forms'
3import { ActivatedRoute, Router } from '@angular/router' 3import { ActivatedRoute, Router } from '@angular/router'
4 4
5import { FileUploader } from 'ng2-file-upload/ng2-file-upload'
6import { NotificationsService } from 'angular2-notifications' 5import { NotificationsService } from 'angular2-notifications'
7 6
8import { AuthService } from '../../core' 7import { AuthService } from '../../core'
diff --git a/client/src/app/videos/video-watch/video-report.component.ts b/client/src/app/videos/video-watch/video-report.component.ts
index a5758060d..d9c83a640 100644
--- a/client/src/app/videos/video-watch/video-report.component.ts
+++ b/client/src/app/videos/video-watch/video-report.component.ts
@@ -63,7 +63,7 @@ export class VideoReportComponent extends FormReactive implements OnInit {
63 this.hide() 63 this.hide()
64 }, 64 },
65 65
66 err => this.notificationsService.error('Error', err) 66 err => this.notificationsService.error('Error', err.message)
67 ) 67 )
68 } 68 }
69} 69}
diff --git a/client/src/app/videos/video-watch/video-watch.component.ts b/client/src/app/videos/video-watch/video-watch.component.ts
index 9cedc9c76..f5a47199d 100644
--- a/client/src/app/videos/video-watch/video-watch.component.ts
+++ b/client/src/app/videos/video-watch/video-watch.component.ts
@@ -158,7 +158,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
158 this.userRating = 'like' 158 this.userRating = 'like'
159 }, 159 },
160 160
161 err => this.notificationsService.error('Error', err) 161 err => this.notificationsService.error('Error', err.message)
162 ) 162 )
163 } 163 }
164 164
@@ -175,7 +175,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
175 this.userRating = 'dislike' 175 this.userRating = 'dislike'
176 }, 176 },
177 177
178 err => this.notificationsService.error('Error', err) 178 err => this.notificationsService.error('Error', err.message)
179 ) 179 )
180 } 180 }
181 181
@@ -275,7 +275,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
275 } 275 }
276 }, 276 },
277 277
278 err => this.notificationsService.error('Error', err) 278 err => this.notificationsService.error('Error', err.message)
279 ) 279 )
280 } 280 }
281 281