aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app/videos
diff options
context:
space:
mode:
authorChocobozzz <florian.bigard@gmail.com>2016-10-02 15:39:09 +0200
committerChocobozzz <florian.bigard@gmail.com>2016-10-02 15:39:09 +0200
commita6375e69668ea42e19531c6bc68dcd37f3f7cbd7 (patch)
tree03204a408d56311692c3528bedcf95d2455e94f2 /client/src/app/videos
parent052937db8a8d282eccdbdf38d487ed8d85d3c0a7 (diff)
parentc4403b29ad4db097af528a7f04eea07e0ed320d0 (diff)
downloadPeerTube-a6375e69668ea42e19531c6bc68dcd37f3f7cbd7.tar.gz
PeerTube-a6375e69668ea42e19531c6bc68dcd37f3f7cbd7.tar.zst
PeerTube-a6375e69668ea42e19531c6bc68dcd37f3f7cbd7.zip
Merge branch 'master' into webseed-merged
Diffstat (limited to 'client/src/app/videos')
-rw-r--r--client/src/app/videos/shared/index.ts1
-rw-r--r--client/src/app/videos/shared/loader/loader.component.ts4
-rw-r--r--client/src/app/videos/shared/pagination.model.ts5
-rw-r--r--client/src/app/videos/shared/video.service.ts62
-rw-r--r--client/src/app/videos/video-add/video-add.component.html30
-rw-r--r--client/src/app/videos/video-add/video-add.component.ts93
-rw-r--r--client/src/app/videos/video-list/video-list.component.ts35
-rw-r--r--client/src/app/videos/video-list/video-miniature.component.ts10
-rw-r--r--client/src/app/videos/video-list/video-sort.component.ts2
-rw-r--r--client/src/app/videos/video-watch/video-watch.component.ts34
-rw-r--r--client/src/app/videos/videos.component.ts4
-rw-r--r--client/src/app/videos/videos.routes.ts4
12 files changed, 134 insertions, 150 deletions
diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts
index a54120f5d..67d16ead1 100644
--- a/client/src/app/videos/shared/index.ts
+++ b/client/src/app/videos/shared/index.ts
@@ -1,5 +1,4 @@
1export * from './loader'; 1export * from './loader';
2export * from './pagination.model';
3export * from './sort-field.type'; 2export * from './sort-field.type';
4export * from './video.model'; 3export * from './video.model';
5export * from './video.service'; 4export * from './video.service';
diff --git a/client/src/app/videos/shared/loader/loader.component.ts b/client/src/app/videos/shared/loader/loader.component.ts
index cdd07d1b4..e72d2f3f3 100644
--- a/client/src/app/videos/shared/loader/loader.component.ts
+++ b/client/src/app/videos/shared/loader/loader.component.ts
@@ -2,8 +2,8 @@ import { Component, Input } from '@angular/core';
2 2
3@Component({ 3@Component({
4 selector: 'my-loader', 4 selector: 'my-loader',
5 styles: [ require('./loader.component.scss') ], 5 styleUrls: [ './loader.component.scss' ],
6 template: require('./loader.component.html') 6 templateUrl: './loader.component.html'
7}) 7})
8 8
9export class LoaderComponent { 9export class LoaderComponent {
diff --git a/client/src/app/videos/shared/pagination.model.ts b/client/src/app/videos/shared/pagination.model.ts
deleted file mode 100644
index eda44ebfb..000000000
--- a/client/src/app/videos/shared/pagination.model.ts
+++ /dev/null
@@ -1,5 +0,0 @@
1export interface Pagination {
2 currentPage: number;
3 itemsPerPage: number;
4 totalItems: number;
5}
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts
index b4396f767..ad8557533 100644
--- a/client/src/app/videos/shared/video.service.ts
+++ b/client/src/app/videos/shared/video.service.ts
@@ -1,11 +1,10 @@
1import { Injectable } from '@angular/core'; 1import { Injectable } from '@angular/core';
2import { Http, Response, URLSearchParams } from '@angular/http'; 2import { Http } from '@angular/http';
3import { Observable } from 'rxjs/Observable'; 3import { Observable } from 'rxjs/Observable';
4 4
5import { Pagination } from './pagination.model';
6import { Search } from '../../shared'; 5import { Search } from '../../shared';
7import { SortField } from './sort-field.type'; 6import { SortField } from './sort-field.type';
8import { AuthHttp, AuthService } from '../../shared'; 7import { AuthHttp, AuthService, RestExtractor, RestPagination, RestService, ResultList } from '../../shared';
9import { Video } from './video.model'; 8import { Video } from './video.model';
10 9
11@Injectable() 10@Injectable()
@@ -15,68 +14,51 @@ export class VideoService {
15 constructor( 14 constructor(
16 private authService: AuthService, 15 private authService: AuthService,
17 private authHttp: AuthHttp, 16 private authHttp: AuthHttp,
18 private http: Http 17 private http: Http,
18 private restExtractor: RestExtractor,
19 private restService: RestService
19 ) {} 20 ) {}
20 21
21 getVideo(id: string) { 22 getVideo(id: string): Observable<Video> {
22 return this.http.get(VideoService.BASE_VIDEO_URL + id) 23 return this.http.get(VideoService.BASE_VIDEO_URL + id)
23 .map(res => <Video> res.json()) 24 .map(this.restExtractor.extractDataGet)
24 .catch(this.handleError); 25 .catch((res) => this.restExtractor.handleError(res));
25 } 26 }
26 27
27 getVideos(pagination: Pagination, sort: SortField) { 28 getVideos(pagination: RestPagination, sort: SortField) {
28 const params = this.createPaginationParams(pagination); 29 const params = this.restService.buildRestGetParams(pagination, sort);
29
30 if (sort) params.set('sort', sort);
31 30
32 return this.http.get(VideoService.BASE_VIDEO_URL, { search: params }) 31 return this.http.get(VideoService.BASE_VIDEO_URL, { search: params })
33 .map(res => res.json()) 32 .map(res => res.json())
34 .map(this.extractVideos) 33 .map(this.extractVideos)
35 .catch(this.handleError); 34 .catch((res) => this.restExtractor.handleError(res));
36 } 35 }
37 36
38 removeVideo(id: string) { 37 removeVideo(id: string) {
39 return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) 38 return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id)
40 .map(res => <number> res.status) 39 .map(this.restExtractor.extractDataBool)
41 .catch(this.handleError); 40 .catch((res) => this.restExtractor.handleError(res));
42 } 41 }
43 42
44 searchVideos(search: Search, pagination: Pagination, sort: SortField) { 43 searchVideos(search: Search, pagination: RestPagination, sort: SortField) {
45 const params = this.createPaginationParams(pagination); 44 const params = this.restService.buildRestGetParams(pagination, sort);
46 45
47 if (search.field) params.set('field', search.field); 46 if (search.field) params.set('field', search.field);
48 if (sort) params.set('sort', sort);
49 47
50 return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params }) 48 return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params })
51 .map(res => res.json()) 49 .map(this.restExtractor.extractDataList)
52 .map(this.extractVideos) 50 .map(this.extractVideos)
53 .catch(this.handleError); 51 .catch((res) => this.restExtractor.handleError(res));
54 }
55
56 private createPaginationParams(pagination: Pagination) {
57 const params = new URLSearchParams();
58 const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage;
59 const count: number = pagination.itemsPerPage;
60
61 params.set('start', start.toString());
62 params.set('count', count.toString());
63
64 return params;
65 } 52 }
66 53
67 private extractVideos(body: any) { 54 private extractVideos(result: ResultList) {
68 const videos_json = body.data; 55 const videosJson = result.data;
69 const totalVideos = body.total; 56 const totalVideos = result.total;
70 const videos = []; 57 const videos = [];
71 for (const video_json of videos_json) { 58 for (const videoJson of videosJson) {
72 videos.push(new Video(video_json)); 59 videos.push(new Video(videoJson));
73 } 60 }
74 61
75 return { videos, totalVideos }; 62 return { videos, totalVideos };
76 } 63 }
77
78 private handleError(error: Response) {
79 console.error(error);
80 return Observable.throw(error.json().error || 'Server error');
81 }
82} 64}
diff --git a/client/src/app/videos/video-add/video-add.component.html b/client/src/app/videos/video-add/video-add.component.html
index bcd78c7cb..64320cae7 100644
--- a/client/src/app/videos/video-add/video-add.component.html
+++ b/client/src/app/videos/video-add/video-add.component.html
@@ -2,31 +2,31 @@
2 2
3<div *ngIf="error" class="alert alert-danger">{{ error }}</div> 3<div *ngIf="error" class="alert alert-danger">{{ error }}</div>
4 4
5<form novalidate (ngSubmit)="upload()" [ngFormModel]="videoForm"> 5<form novalidate (ngSubmit)="upload()" [formGroup]="form">
6 <div class="form-group"> 6 <div class="form-group">
7 <label for="name">Name</label> 7 <label for="name">Name</label>
8 <input 8 <input
9 type="text" class="form-control" name="name" id="name" 9 type="text" class="form-control" id="name"
10 ngControl="name" #name="ngForm" [(ngModel)]="video.name" 10 formControlName="name"
11 > 11 >
12 <div [hidden]="name.valid || name.pristine" class="alert alert-warning"> 12 <div *ngIf="formErrors.name" class="alert alert-danger">
13 A name is required and should be between 3 and 50 characters long 13 {{ formErrors.name }}
14 </div> 14 </div>
15 </div> 15 </div>
16 16
17 <div class="form-group"> 17 <div class="form-group">
18 <label for="tags">Tags</label> 18 <label for="tags">Tags</label>
19 <input 19 <input
20 type="text" class="form-control" name="tags" id="tags" 20 type="text" class="form-control" id="currentTag"
21 ngControl="tags" #tags="ngForm" [disabled]="isTagsInputDisabled" (keyup)="onTagKeyPress($event)" [(ngModel)]="currentTag" 21 formControlName="currentTag" (keyup)="onTagKeyPress($event)"
22 > 22 >
23 <div [hidden]="tags.valid || tags.pristine" class="alert alert-warning"> 23 <div *ngIf="formErrors.currentTag" class="alert alert-danger">
24 A tag should be between 2 and 10 characters (alphanumeric) long 24 {{ formErrors.currentTag }}
25 </div> 25 </div>
26 </div> 26 </div>
27 27
28 <div class="tags"> 28 <div class="tags">
29 <div class="label label-primary tag" *ngFor="let tag of video.tags"> 29 <div class="label label-primary tag" *ngFor="let tag of tags">
30 {{ tag }} 30 {{ tag }}
31 <span class="remove" (click)="removeTag(tag)">x</span> 31 <span class="remove" (click)="removeTag(tag)">x</span>
32 </div> 32 </div>
@@ -53,12 +53,12 @@
53 <div class="form-group"> 53 <div class="form-group">
54 <label for="description">Description</label> 54 <label for="description">Description</label>
55 <textarea 55 <textarea
56 name="description" id="description" class="form-control" placeholder="Description..." 56 id="description" class="form-control" placeholder="Description..."
57 ngControl="description" #description="ngForm" [(ngModel)]="video.description" 57 formControlName="description"
58 > 58 >
59 </textarea> 59 </textarea>
60 <div [hidden]="description.valid || description.pristine" class="alert alert-warning"> 60 <div *ngIf="formErrors.description" class="alert alert-danger">
61 A description is required and should be between 3 and 250 characters long 61 {{ formErrors.description }}
62 </div> 62 </div>
63 </div> 63 </div>
64 64
@@ -69,7 +69,7 @@
69 <div class="form-group"> 69 <div class="form-group">
70 <input 70 <input
71 type="submit" value="Upload" class="btn btn-default form-control" [title]="getInvalidFieldsTitle()" 71 type="submit" value="Upload" class="btn btn-default form-control" [title]="getInvalidFieldsTitle()"
72 [disabled]="!videoForm.valid || video.tags.length === 0 || filename === null" 72 [disabled]="!form.valid || tags.length === 0 || filename === null"
73 > 73 >
74 </div> 74 </div>
75</form> 75</form>
diff --git a/client/src/app/videos/video-add/video-add.component.ts b/client/src/app/videos/video-add/video-add.component.ts
index c0f8cb9c4..d12a7d572 100644
--- a/client/src/app/videos/video-add/video-add.component.ts
+++ b/client/src/app/videos/video-add/video-add.component.ts
@@ -1,37 +1,42 @@
1import { Control, ControlGroup, Validators } from '@angular/common';
2import { Component, ElementRef, OnInit } from '@angular/core'; 1import { Component, ElementRef, OnInit } from '@angular/core';
2import { FormBuilder, FormGroup } from '@angular/forms';
3import { Router } from '@angular/router'; 3import { Router } from '@angular/router';
4 4
5import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; 5import { FileUploader } from 'ng2-file-upload/ng2-file-upload';
6import { PROGRESSBAR_DIRECTIVES } from 'ng2-bootstrap/components/progressbar';
7import { FileSelectDirective, FileUploader } from 'ng2-file-upload/ng2-file-upload';
8 6
9import { AuthService } from '../../shared'; 7import { AuthService, FormReactive, VIDEO_NAME, VIDEO_DESCRIPTION, VIDEO_TAGS } from '../../shared';
10 8
11@Component({ 9@Component({
12 selector: 'my-videos-add', 10 selector: 'my-videos-add',
13 styles: [ require('./video-add.component.scss') ], 11 styleUrls: [ './video-add.component.scss' ],
14 template: require('./video-add.component.html'), 12 templateUrl: './video-add.component.html'
15 directives: [ FileSelectDirective, PROGRESSBAR_DIRECTIVES ],
16 pipes: [ BytesPipe ]
17}) 13})
18 14
19export class VideoAddComponent implements OnInit { 15export class VideoAddComponent extends FormReactive implements OnInit {
20 currentTag: string; // Tag the user is writing in the input 16 tags: string[] = [];
21 error: string = null;
22 videoForm: ControlGroup;
23 uploader: FileUploader; 17 uploader: FileUploader;
24 video = { 18
19 error: string = null;
20 form: FormGroup;
21 formErrors = {
25 name: '', 22 name: '',
26 tags: [], 23 description: '',
27 description: '' 24 currentTag: ''
25 };
26 validationMessages = {
27 name: VIDEO_NAME.MESSAGES,
28 description: VIDEO_DESCRIPTION.MESSAGES,
29 currentTag: VIDEO_TAGS.MESSAGES
28 }; 30 };
29 31
30 constructor( 32 constructor(
31 private authService: AuthService, 33 private authService: AuthService,
32 private elementRef: ElementRef, 34 private elementRef: ElementRef,
35 private formBuilder: FormBuilder,
33 private router: Router 36 private router: Router
34 ) {} 37 ) {
38 super();
39 }
35 40
36 get filename() { 41 get filename() {
37 if (this.uploader.queue.length === 0) { 42 if (this.uploader.queue.length === 0) {
@@ -41,20 +46,26 @@ export class VideoAddComponent implements OnInit {
41 return this.uploader.queue[0].file.name; 46 return this.uploader.queue[0].file.name;
42 } 47 }
43 48
44 get isTagsInputDisabled () { 49 buildForm() {
45 return this.video.tags.length >= 3; 50 this.form = this.formBuilder.group({
51 name: [ '', VIDEO_NAME.VALIDATORS ],
52 description: [ '', VIDEO_DESCRIPTION.VALIDATORS ],
53 currentTag: [ '', VIDEO_TAGS.VALIDATORS ]
54 });
55
56 this.form.valueChanges.subscribe(data => this.onValueChanged(data));
46 } 57 }
47 58
48 getInvalidFieldsTitle() { 59 getInvalidFieldsTitle() {
49 let title = ''; 60 let title = '';
50 const nameControl = this.videoForm.controls['name']; 61 const nameControl = this.form.controls['name'];
51 const descriptionControl = this.videoForm.controls['description']; 62 const descriptionControl = this.form.controls['description'];
52 63
53 if (!nameControl.valid) { 64 if (!nameControl.valid) {
54 title += 'A name is required\n'; 65 title += 'A name is required\n';
55 } 66 }
56 67
57 if (this.video.tags.length === 0) { 68 if (this.tags.length === 0) {
58 title += 'At least one tag is required\n'; 69 title += 'At least one tag is required\n';
59 } 70 }
60 71
@@ -70,13 +81,6 @@ export class VideoAddComponent implements OnInit {
70 } 81 }
71 82
72 ngOnInit() { 83 ngOnInit() {
73 this.videoForm = new ControlGroup({
74 name: new Control('', Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(50) ])),
75 description: new Control('', Validators.compose([ Validators.required, Validators.minLength(3), Validators.maxLength(250) ])),
76 tags: new Control('', Validators.pattern('^[a-zA-Z0-9]{2,10}$'))
77 });
78
79
80 this.uploader = new FileUploader({ 84 this.uploader = new FileUploader({
81 authToken: this.authService.getRequestHeaderValue(), 85 authToken: this.authService.getRequestHeaderValue(),
82 queueLimit: 1, 86 queueLimit: 1,
@@ -85,26 +89,37 @@ export class VideoAddComponent implements OnInit {
85 }); 89 });
86 90
87 this.uploader.onBuildItemForm = (item, form) => { 91 this.uploader.onBuildItemForm = (item, form) => {
88 form.append('name', this.video.name); 92 const name = this.form.value['name'];
89 form.append('description', this.video.description); 93 const description = this.form.value['description'];
94
95 form.append('name', name);
96 form.append('description', description);
90 97
91 for (let i = 0; i < this.video.tags.length; i++) { 98 for (let i = 0; i < this.tags.length; i++) {
92 form.append(`tags[${i}]`, this.video.tags[i]); 99 form.append(`tags[${i}]`, this.tags[i]);
93 } 100 }
94 }; 101 };
102
103 this.buildForm();
95 } 104 }
96 105
97 onTagKeyPress(event: KeyboardEvent) { 106 onTagKeyPress(event: KeyboardEvent) {
107 const currentTag = this.form.value['currentTag'];
108
98 // Enter press 109 // Enter press
99 if (event.keyCode === 13) { 110 if (event.keyCode === 13) {
100 // Check if the tag is valid and does not already exist 111 // Check if the tag is valid and does not already exist
101 if ( 112 if (
102 this.currentTag !== '' && 113 currentTag !== '' &&
103 this.videoForm.controls['tags'].valid && 114 this.form.controls['currentTag'].valid &&
104 this.video.tags.indexOf(this.currentTag) === -1 115 this.tags.indexOf(currentTag) === -1
105 ) { 116 ) {
106 this.video.tags.push(this.currentTag); 117 this.tags.push(currentTag);
107 this.currentTag = ''; 118 this.form.patchValue({ currentTag: '' });
119
120 if (this.tags.length >= 3) {
121 this.form.get('currentTag').disable();
122 }
108 } 123 }
109 } 124 }
110 } 125 }
@@ -114,7 +129,7 @@ export class VideoAddComponent implements OnInit {
114 } 129 }
115 130
116 removeTag(tag: string) { 131 removeTag(tag: string) {
117 this.video.tags.splice(this.video.tags.indexOf(tag), 1); 132 this.tags.splice(this.tags.indexOf(tag), 1);
118 } 133 }
119 134
120 upload() { 135 upload() {
diff --git a/client/src/app/videos/video-list/video-list.component.ts b/client/src/app/videos/video-list/video-list.component.ts
index 5691d684e..6b086e938 100644
--- a/client/src/app/videos/video-list/video-list.component.ts
+++ b/client/src/app/videos/video-list/video-list.component.ts
@@ -1,39 +1,30 @@
1import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; 1import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
2import { AsyncPipe } from '@angular/common'; 2import { ActivatedRoute, Router } from '@angular/router';
3import { ActivatedRoute, Router, ROUTER_DIRECTIVES } from '@angular/router';
4import { BehaviorSubject } from 'rxjs/BehaviorSubject'; 3import { BehaviorSubject } from 'rxjs/BehaviorSubject';
5 4
6import { PAGINATION_DIRECTIVES } from 'ng2-bootstrap/components/pagination';
7
8import { 5import {
9 LoaderComponent,
10 Pagination,
11 SortField, 6 SortField,
12 Video, 7 Video,
13 VideoService 8 VideoService
14} from '../shared'; 9} from '../shared';
15import { AuthService, Search, SearchField, User } from '../../shared'; 10import { AuthService, AuthUser, RestPagination, Search, SearchField } from '../../shared';
16import { VideoMiniatureComponent } from './video-miniature.component';
17import { VideoSortComponent } from './video-sort.component';
18import { SearchService } from '../../shared'; 11import { SearchService } from '../../shared';
19 12
20@Component({ 13@Component({
21 selector: 'my-videos-list', 14 selector: 'my-videos-list',
22 styles: [ require('./video-list.component.scss') ], 15 styleUrls: [ './video-list.component.scss' ],
23 pipes: [ AsyncPipe ], 16 templateUrl: './video-list.component.html'
24 template: require('./video-list.component.html'),
25 directives: [ LoaderComponent, PAGINATION_DIRECTIVES, ROUTER_DIRECTIVES, VideoMiniatureComponent, VideoSortComponent ]
26}) 17})
27 18
28export class VideoListComponent implements OnInit, OnDestroy { 19export class VideoListComponent implements OnInit, OnDestroy {
29 loading: BehaviorSubject<boolean> = new BehaviorSubject(false); 20 loading: BehaviorSubject<boolean> = new BehaviorSubject(false);
30 pagination: Pagination = { 21 pagination: RestPagination = {
31 currentPage: 1, 22 currentPage: 1,
32 itemsPerPage: 9, 23 itemsPerPage: 9,
33 totalItems: null 24 totalItems: null
34 }; 25 };
35 sort: SortField; 26 sort: SortField;
36 user: User = null; 27 user: AuthUser = null;
37 videos: Video[] = []; 28 videos: Video[] = [];
38 29
39 private search: Search; 30 private search: Search;
@@ -51,7 +42,7 @@ export class VideoListComponent implements OnInit, OnDestroy {
51 42
52 ngOnInit() { 43 ngOnInit() {
53 if (this.authService.isLoggedIn()) { 44 if (this.authService.isLoggedIn()) {
54 this.user = User.load(); 45 this.user = AuthUser.load();
55 } 46 }
56 47
57 // Subscribe to route changes 48 // Subscribe to route changes
@@ -66,6 +57,8 @@ export class VideoListComponent implements OnInit, OnDestroy {
66 // Subscribe to search changes 57 // Subscribe to search changes
67 this.subSearch = this.searchService.searchUpdated.subscribe(search => { 58 this.subSearch = this.searchService.searchUpdated.subscribe(search => {
68 this.search = search; 59 this.search = search;
60 // Reset pagination
61 this.pagination.currentPage = 1;
69 62
70 this.navigateToNewParams(); 63 this.navigateToNewParams();
71 }); 64 });
@@ -76,7 +69,7 @@ export class VideoListComponent implements OnInit, OnDestroy {
76 this.subSearch.unsubscribe(); 69 this.subSearch.unsubscribe();
77 } 70 }
78 71
79 getVideos(detectChanges = true) { 72 getVideos() {
80 this.loading.next(true); 73 this.loading.next(true);
81 this.videos = []; 74 this.videos = [];
82 75
@@ -97,7 +90,7 @@ export class VideoListComponent implements OnInit, OnDestroy {
97 90
98 this.loading.next(false); 91 this.loading.next(false);
99 }, 92 },
100 error => alert(error) 93 error => alert(error.text)
101 ); 94 );
102 } 95 }
103 96
@@ -153,7 +146,11 @@ export class VideoListComponent implements OnInit, OnDestroy {
153 146
154 this.sort = <SortField>routeParams['sort'] || '-createdDate'; 147 this.sort = <SortField>routeParams['sort'] || '-createdDate';
155 148
156 this.pagination.currentPage = parseInt(routeParams['page']) || 1; 149 if (routeParams['page'] !== undefined) {
150 this.pagination.currentPage = parseInt(routeParams['page']);
151 } else {
152 this.pagination.currentPage = 1;
153 }
157 154
158 this.changeDetector.detectChanges(); 155 this.changeDetector.detectChanges();
159 } 156 }
diff --git a/client/src/app/videos/video-list/video-miniature.component.ts b/client/src/app/videos/video-list/video-miniature.component.ts
index 84bab950e..398d2db75 100644
--- a/client/src/app/videos/video-list/video-miniature.component.ts
+++ b/client/src/app/videos/video-list/video-miniature.component.ts
@@ -1,16 +1,12 @@
1import { DatePipe } from '@angular/common';
2import { Component, Input, Output, EventEmitter } from '@angular/core'; 1import { Component, Input, Output, EventEmitter } from '@angular/core';
3import { ROUTER_DIRECTIVES } from '@angular/router';
4 2
5import { SortField, Video, VideoService } from '../shared'; 3import { SortField, Video, VideoService } from '../shared';
6import { User } from '../../shared'; 4import { User } from '../../shared';
7 5
8@Component({ 6@Component({
9 selector: 'my-video-miniature', 7 selector: 'my-video-miniature',
10 styles: [ require('./video-miniature.component.scss') ], 8 styleUrls: [ './video-miniature.component.scss' ],
11 template: require('./video-miniature.component.html'), 9 templateUrl: './video-miniature.component.html'
12 directives: [ ROUTER_DIRECTIVES ],
13 pipes: [ DatePipe ]
14}) 10})
15 11
16export class VideoMiniatureComponent { 12export class VideoMiniatureComponent {
@@ -40,7 +36,7 @@ export class VideoMiniatureComponent {
40 if (confirm('Do you really want to remove this video?')) { 36 if (confirm('Do you really want to remove this video?')) {
41 this.videoService.removeVideo(id).subscribe( 37 this.videoService.removeVideo(id).subscribe(
42 status => this.removed.emit(true), 38 status => this.removed.emit(true),
43 error => alert(error) 39 error => alert(error.text)
44 ); 40 );
45 } 41 }
46 } 42 }
diff --git a/client/src/app/videos/video-list/video-sort.component.ts b/client/src/app/videos/video-list/video-sort.component.ts
index 0d76b54b7..ca94b07c2 100644
--- a/client/src/app/videos/video-list/video-sort.component.ts
+++ b/client/src/app/videos/video-list/video-sort.component.ts
@@ -4,7 +4,7 @@ import { SortField } from '../shared';
4 4
5@Component({ 5@Component({
6 selector: 'my-video-sort', 6 selector: 'my-video-sort',
7 template: require('./video-sort.component.html') 7 templateUrl: './video-sort.component.html'
8}) 8})
9 9
10export class VideoSortComponent { 10export class VideoSortComponent {
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 3aaed0487..239e24c99 100644
--- a/client/src/app/videos/video-watch/video-watch.component.ts
+++ b/client/src/app/videos/video-watch/video-watch.component.ts
@@ -1,18 +1,13 @@
1import { Component, ElementRef, OnDestroy, OnInit } from '@angular/core'; 1import { Component, ElementRef, NgZone, OnDestroy, OnInit } from '@angular/core';
2import { ActivatedRoute } from '@angular/router'; 2import { ActivatedRoute } from '@angular/router';
3 3
4import { BytesPipe } from 'angular-pipes/src/math/bytes.pipe'; 4import { Video, VideoService } from '../shared';
5
6import { LoaderComponent, Video, VideoService } from '../shared';
7import { WebTorrentService } from './webtorrent.service'; 5import { WebTorrentService } from './webtorrent.service';
8 6
9@Component({ 7@Component({
10 selector: 'my-video-watch', 8 selector: 'my-video-watch',
11 template: require('./video-watch.component.html'), 9 templateUrl: './video-watch.component.html',
12 styles: [ require('./video-watch.component.scss') ], 10 styleUrls: [ './video-watch.component.scss' ]
13 providers: [ WebTorrentService ],
14 directives: [ LoaderComponent ],
15 pipes: [ BytesPipe ]
16}) 11})
17 12
18export class VideoWatchComponent implements OnInit, OnDestroy { 13export class VideoWatchComponent implements OnInit, OnDestroy {
@@ -31,6 +26,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
31 26
32 constructor( 27 constructor(
33 private elementRef: ElementRef, 28 private elementRef: ElementRef,
29 private ngZone: NgZone,
34 private route: ActivatedRoute, 30 private route: ActivatedRoute,
35 private videoService: VideoService, 31 private videoService: VideoService,
36 private webTorrentService: WebTorrentService 32 private webTorrentService: WebTorrentService
@@ -65,12 +61,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
65 } 61 }
66 }); 62 });
67 63
68 // Refresh each second 64 this.runInProgress(torrent);
69 this.torrentInfosInterval = setInterval(() => {
70 this.downloadSpeed = torrent.downloadSpeed;
71 this.numPeers = torrent.numPeers;
72 this.uploadSpeed = torrent.uploadSpeed;
73 }, 1000);
74 }); 65 });
75 } 66 }
76 67
@@ -91,7 +82,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
91 this.video = video; 82 this.video = video;
92 this.loadVideo(); 83 this.loadVideo();
93 }, 84 },
94 error => alert(error) 85 error => alert(error.text)
95 ); 86 );
96 }); 87 });
97 } 88 }
@@ -100,4 +91,15 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
100 this.error = true; 91 this.error = true;
101 console.error('The video load seems to be abnormally long.'); 92 console.error('The video load seems to be abnormally long.');
102 } 93 }
94
95 private runInProgress(torrent: any) {
96 // Refresh each second
97 this.torrentInfosInterval = setInterval(() => {
98 this.ngZone.run(() => {
99 this.downloadSpeed = torrent.downloadSpeed;
100 this.numPeers = torrent.numPeers;
101 this.uploadSpeed = torrent.uploadSpeed;
102 });
103 }, 1000);
104 }
103} 105}
diff --git a/client/src/app/videos/videos.component.ts b/client/src/app/videos/videos.component.ts
index 76252afbb..591e7523d 100644
--- a/client/src/app/videos/videos.component.ts
+++ b/client/src/app/videos/videos.component.ts
@@ -1,9 +1,7 @@
1import { Component } from '@angular/core'; 1import { Component } from '@angular/core';
2import { ROUTER_DIRECTIVES } from '@angular/router';
3 2
4@Component({ 3@Component({
5 template: '<router-outlet></router-outlet>', 4 template: '<router-outlet></router-outlet>'
6 directives: [ ROUTER_DIRECTIVES ]
7}) 5})
8 6
9export class VideosComponent { 7export class VideosComponent {
diff --git a/client/src/app/videos/videos.routes.ts b/client/src/app/videos/videos.routes.ts
index 1f088b376..074f96596 100644
--- a/client/src/app/videos/videos.routes.ts
+++ b/client/src/app/videos/videos.routes.ts
@@ -1,11 +1,11 @@
1import { RouterConfig } from '@angular/router'; 1import { Routes } from '@angular/router';
2 2
3import { VideoAddComponent } from './video-add'; 3import { VideoAddComponent } from './video-add';
4import { VideoListComponent } from './video-list'; 4import { VideoListComponent } from './video-list';
5import { VideosComponent } from './videos.component'; 5import { VideosComponent } from './videos.component';
6import { VideoWatchComponent } from './video-watch'; 6import { VideoWatchComponent } from './video-watch';
7 7
8export const VideosRoutes: RouterConfig = [ 8export const VideosRoutes: Routes = [
9 { 9 {
10 path: 'videos', 10 path: 'videos',
11 component: VideosComponent, 11 component: VideosComponent,