aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--client/app/app.component.ts16
-rw-r--r--client/app/shared/search.component.ts16
-rw-r--r--client/app/users/login/login.component.ts5
-rw-r--r--client/app/users/shared/auth.service.ts60
-rw-r--r--client/app/videos/shared/video.model.ts59
-rw-r--r--client/app/videos/shared/video.service.ts39
-rw-r--r--client/app/videos/video-add/video-add.component.ts21
-rw-r--r--client/app/videos/video-list/video-list.component.ts13
-rw-r--r--client/app/videos/video-list/video-miniature.component.ts10
-rw-r--r--client/app/videos/video-watch/video-watch.component.ts30
10 files changed, 138 insertions, 131 deletions
diff --git a/client/app/app.component.ts b/client/app/app.component.ts
index 20c8c8724..965848105 100644
--- a/client/app/app.component.ts
+++ b/client/app/app.component.ts
@@ -49,13 +49,13 @@ import {
49}) 49})
50 50
51export class AppComponent { 51export class AppComponent {
52 isLoggedIn: boolean;
53 search_field: string = name;
54 choices = []; 52 choices = [];
53 isLoggedIn: boolean;
55 54
56 constructor(private friendService: FriendService, 55 constructor(
57 private authService: AuthService, 56 private authService: AuthService,
58 private router: Router 57 private friendService: FriendService,
58 private router: Router
59 ) { 59 ) {
60 this.isLoggedIn = this.authService.isLoggedIn(); 60 this.isLoggedIn = this.authService.isLoggedIn();
61 61
@@ -71,8 +71,8 @@ export class AppComponent {
71 onSearch(search: Search) { 71 onSearch(search: Search) {
72 if (search.value !== '') { 72 if (search.value !== '') {
73 const params = { 73 const params = {
74 search: search.value, 74 field: search.field,
75 field: search.field 75 search: search.value
76 }; 76 };
77 this.router.navigate(['VideosList', params]); 77 this.router.navigate(['VideosList', params]);
78 } else { 78 } else {
@@ -100,7 +100,7 @@ export class AppComponent {
100 quitFriends() { 100 quitFriends() {
101 this.friendService.quitFriends().subscribe( 101 this.friendService.quitFriends().subscribe(
102 status => { 102 status => {
103 alert('Quit friends!'); 103 alert('Quit friends!');
104 }, 104 },
105 error => alert(error) 105 error => alert(error)
106 ); 106 );
diff --git a/client/app/shared/search.component.ts b/client/app/shared/search.component.ts
index 674518aba..e1e30b9af 100644
--- a/client/app/shared/search.component.ts
+++ b/client/app/shared/search.component.ts
@@ -14,26 +14,21 @@ import { SearchField } from './search-field.type';
14export class SearchComponent { 14export class SearchComponent {
15 @Output() search = new EventEmitter<Search>(); 15 @Output() search = new EventEmitter<Search>();
16 16
17 searchCriterias: Search = {
18 field: 'name',
19 value: ''
20 };
21
22 fieldChoices = { 17 fieldChoices = {
23 name: 'Name', 18 name: 'Name',
24 author: 'Author', 19 author: 'Author',
25 podUrl: 'Pod Url', 20 podUrl: 'Pod Url',
26 magnetUri: 'Magnet Uri' 21 magnetUri: 'Magnet Uri'
27 }; 22 };
23 searchCriterias: Search = {
24 field: 'name',
25 value: ''
26 };
28 27
29 get choiceKeys() { 28 get choiceKeys() {
30 return Object.keys(this.fieldChoices); 29 return Object.keys(this.fieldChoices);
31 } 30 }
32 31
33 getStringChoice(choiceKey: SearchField) {
34 return this.fieldChoices[choiceKey];
35 }
36
37 choose($event: MouseEvent, choice: SearchField) { 32 choose($event: MouseEvent, choice: SearchField) {
38 $event.preventDefault(); 33 $event.preventDefault();
39 $event.stopPropagation(); 34 $event.stopPropagation();
@@ -45,4 +40,7 @@ export class SearchComponent {
45 this.search.emit(this.searchCriterias); 40 this.search.emit(this.searchCriterias);
46 } 41 }
47 42
43 getStringChoice(choiceKey: SearchField) {
44 return this.fieldChoices[choiceKey];
45 }
48} 46}
diff --git a/client/app/users/login/login.component.ts b/client/app/users/login/login.component.ts
index 8e369541d..09c5f1af7 100644
--- a/client/app/users/login/login.component.ts
+++ b/client/app/users/login/login.component.ts
@@ -10,7 +10,10 @@ import { AuthService, AuthStatus, User } from '../shared/index';
10}) 10})
11 11
12export class UserLoginComponent { 12export class UserLoginComponent {
13 constructor(private authService: AuthService, private router: Router) {} 13 constructor(
14 private authService: AuthService,
15 private router: Router
16 ) {}
14 17
15 login(username: string, password: string) { 18 login(username: string, password: string) {
16 this.authService.login(username, password).subscribe( 19 this.authService.login(username, password).subscribe(
diff --git a/client/app/users/shared/auth.service.ts b/client/app/users/shared/auth.service.ts
index b1da94436..d63fe38f3 100644
--- a/client/app/users/shared/auth.service.ts
+++ b/client/app/users/shared/auth.service.ts
@@ -7,14 +7,14 @@ import { User } from './user.model';
7 7
8@Injectable() 8@Injectable()
9export class AuthService { 9export class AuthService {
10 private static BASE_LOGIN_URL = '/api/v1/users/token';
11 private static BASE_CLIENT_URL = '/api/v1/users/client'; 10 private static BASE_CLIENT_URL = '/api/v1/users/client';
11 private static BASE_LOGIN_URL = '/api/v1/users/token';
12 12
13 loginChangedSource: Observable<AuthStatus>; 13 loginChangedSource: Observable<AuthStatus>;
14 14
15 private loginChanged: Subject<AuthStatus>;
16 private clientId: string; 15 private clientId: string;
17 private clientSecret: string; 16 private clientSecret: string;
17 private loginChanged: Subject<AuthStatus>;
18 18
19 constructor(private http: Http) { 19 constructor(private http: Http) {
20 this.loginChanged = new Subject<AuthStatus>(); 20 this.loginChanged = new Subject<AuthStatus>();
@@ -37,40 +37,14 @@ export class AuthService {
37 ); 37 );
38 } 38 }
39 39
40 login(username: string, password: string) { 40 getAuthRequestOptions(): RequestOptions {
41 let body = new URLSearchParams(); 41 return new RequestOptions({ headers: this.getRequestHeader() });
42 body.set('client_id', this.clientId);
43 body.set('client_secret', this.clientSecret);
44 body.set('response_type', 'code');
45 body.set('grant_type', 'password');
46 body.set('scope', 'upload');
47 body.set('username', username);
48 body.set('password', password);
49
50 let headers = new Headers();
51 headers.append('Content-Type', 'application/x-www-form-urlencoded');
52
53 let options = {
54 headers: headers
55 };
56
57 return this.http.post(AuthService.BASE_LOGIN_URL, body.toString(), options)
58 .map(res => res.json())
59 .catch(this.handleError);
60 }
61
62 logout() {
63 // TODO make HTTP request
64 } 42 }
65 43
66 getRequestHeader() { 44 getRequestHeader() {
67 return new Headers({ 'Authorization': `${this.getTokenType()} ${this.getToken()}` }); 45 return new Headers({ 'Authorization': `${this.getTokenType()} ${this.getToken()}` });
68 } 46 }
69 47
70 getAuthRequestOptions(): RequestOptions {
71 return new RequestOptions({ headers: this.getRequestHeader() });
72 }
73
74 getToken() { 48 getToken() {
75 return localStorage.getItem('access_token'); 49 return localStorage.getItem('access_token');
76 } 50 }
@@ -97,6 +71,32 @@ export class AuthService {
97 } 71 }
98 } 72 }
99 73
74 login(username: string, password: string) {
75 let body = new URLSearchParams();
76 body.set('client_id', this.clientId);
77 body.set('client_secret', this.clientSecret);
78 body.set('response_type', 'code');
79 body.set('grant_type', 'password');
80 body.set('scope', 'upload');
81 body.set('username', username);
82 body.set('password', password);
83
84 let headers = new Headers();
85 headers.append('Content-Type', 'application/x-www-form-urlencoded');
86
87 let options = {
88 headers: headers
89 };
90
91 return this.http.post(AuthService.BASE_LOGIN_URL, body.toString(), options)
92 .map(res => res.json())
93 .catch(this.handleError);
94 }
95
96 logout() {
97 // TODO make HTTP request
98 }
99
100 setStatus(status: AuthStatus) { 100 setStatus(status: AuthStatus) {
101 this.loginChanged.next(status); 101 this.loginChanged.next(status);
102 } 102 }
diff --git a/client/app/videos/shared/video.model.ts b/client/app/videos/shared/video.model.ts
index 2b018ad86..614403d79 100644
--- a/client/app/videos/shared/video.model.ts
+++ b/client/app/videos/shared/video.model.ts
@@ -1,24 +1,15 @@
1export class Video { 1export class Video {
2 id: string; 2 author: string;
3 name: string; 3 by: string;
4 createdDate: Date;
4 description: string; 5 description: string;
6 duration: string;
7 id: string;
8 isLocal: boolean;
5 magnetUri: string; 9 magnetUri: string;
10 name: string;
6 podUrl: string; 11 podUrl: string;
7 isLocal: boolean;
8 thumbnailPath: string; 12 thumbnailPath: string;
9 author: string;
10 createdDate: Date;
11 by: string;
12 duration: string;
13
14 private static createDurationString(duration: number) {
15 const minutes = Math.floor(duration / 60);
16 const seconds = duration % 60;
17 const minutes_padding = minutes >= 10 ? '' : '0';
18 const seconds_padding = seconds >= 10 ? '' : '0';
19
20 return minutes_padding + minutes.toString() + ':' + seconds_padding + seconds.toString();
21 }
22 13
23 private static createByString(author: string, podUrl: string) { 14 private static createByString(author: string, podUrl: string) {
24 let [ host, port ] = podUrl.replace(/^https?:\/\//, '').split(':'); 15 let [ host, port ] = podUrl.replace(/^https?:\/\//, '').split(':');
@@ -32,28 +23,38 @@ export class Video {
32 return author + '@' + host + port; 23 return author + '@' + host + port;
33 } 24 }
34 25
26 private static createDurationString(duration: number) {
27 const minutes = Math.floor(duration / 60);
28 const seconds = duration % 60;
29 const minutes_padding = minutes >= 10 ? '' : '0';
30 const seconds_padding = seconds >= 10 ? '' : '0';
31
32 return minutes_padding + minutes.toString() + ':' + seconds_padding + seconds.toString();
33 }
34
35 constructor(hash: { 35 constructor(hash: {
36 id: string,
37 name: string,
38 description: string,
39 magnetUri: string,
40 podUrl: string,
41 isLocal: boolean,
42 thumbnailPath: string,
43 author: string, 36 author: string,
44 createdDate: string, 37 createdDate: string,
38 description: string,
45 duration: number; 39 duration: number;
40 id: string,
41 isLocal: boolean,
42 magnetUri: string,
43 name: string,
44 podUrl: string,
45 thumbnailPath: string
46 }) { 46 }) {
47 this.id = hash.id; 47 this.author = hash.author;
48 this.name = hash.name; 48 this.createdDate = new Date(hash.createdDate);
49 this.description = hash.description; 49 this.description = hash.description;
50 this.duration = Video.createDurationString(hash.duration);
51 this.id = hash.id;
52 this.isLocal = hash.isLocal;
50 this.magnetUri = hash.magnetUri; 53 this.magnetUri = hash.magnetUri;
54 this.name = hash.name;
51 this.podUrl = hash.podUrl; 55 this.podUrl = hash.podUrl;
52 this.isLocal = hash.isLocal;
53 this.thumbnailPath = hash.thumbnailPath; 56 this.thumbnailPath = hash.thumbnailPath;
54 this.author = hash.author; 57
55 this.createdDate = new Date(hash.createdDate);
56 this.duration = Video.createDurationString(hash.duration);
57 this.by = Video.createByString(hash.author, hash.podUrl); 58 this.by = Video.createByString(hash.author, hash.podUrl);
58 } 59 }
59 60
diff --git a/client/app/videos/shared/video.service.ts b/client/app/videos/shared/video.service.ts
index b6e0800a0..7b6519f00 100644
--- a/client/app/videos/shared/video.service.ts
+++ b/client/app/videos/shared/video.service.ts
@@ -12,7 +12,16 @@ import { Video } from './video.model';
12export class VideoService { 12export class VideoService {
13 private static BASE_VIDEO_URL = '/api/v1/videos/'; 13 private static BASE_VIDEO_URL = '/api/v1/videos/';
14 14
15 constructor(private http: Http, private authService: AuthService) {} 15 constructor(
16 private authService: AuthService,
17 private http: Http
18 ) {}
19
20 getVideo(id: string) {
21 return this.http.get(VideoService.BASE_VIDEO_URL + id)
22 .map(res => <Video> res.json())
23 .catch(this.handleError);
24 }
16 25
17 getVideos(pagination: Pagination, sort: SortField) { 26 getVideos(pagination: Pagination, sort: SortField) {
18 const params = this.createPaginationParams(pagination); 27 const params = this.createPaginationParams(pagination);
@@ -25,12 +34,6 @@ export class VideoService {
25 .catch(this.handleError); 34 .catch(this.handleError);
26 } 35 }
27 36
28 getVideo(id: string) {
29 return this.http.get(VideoService.BASE_VIDEO_URL + id)
30 .map(res => <Video> res.json())
31 .catch(this.handleError);
32 }
33
34 removeVideo(id: string) { 37 removeVideo(id: string) {
35 const options = this.authService.getAuthRequestOptions(); 38 const options = this.authService.getAuthRequestOptions();
36 return this.http.delete(VideoService.BASE_VIDEO_URL + id, options) 39 return this.http.delete(VideoService.BASE_VIDEO_URL + id, options)
@@ -50,6 +53,17 @@ export class VideoService {
50 .catch(this.handleError); 53 .catch(this.handleError);
51 } 54 }
52 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 }
66
53 private extractVideos(body: any) { 67 private extractVideos(body: any) {
54 const videos_json = body.data; 68 const videos_json = body.data;
55 const totalVideos = body.total; 69 const totalVideos = body.total;
@@ -65,15 +79,4 @@ export class VideoService {
65 console.error(error); 79 console.error(error);
66 return Observable.throw(error.json().error || 'Server error'); 80 return Observable.throw(error.json().error || 'Server error');
67 } 81 }
68
69 private createPaginationParams(pagination: Pagination) {
70 const params = new URLSearchParams();
71 const start: number = (pagination.currentPage - 1) * pagination.itemsPerPage;
72 const count: number = pagination.itemsPerPage;
73
74 params.set('start', start.toString());
75 params.set('count', count.toString());
76
77 return params;
78 }
79} 82}
diff --git a/client/app/videos/video-add/video-add.component.ts b/client/app/videos/video-add/video-add.component.ts
index 67a04a2b4..b11475ae9 100644
--- a/client/app/videos/video-add/video-add.component.ts
+++ b/client/app/videos/video-add/video-add.component.ts
@@ -18,20 +18,21 @@ declare var jQuery: any;
18}) 18})
19 19
20export class VideoAddComponent implements OnInit { 20export class VideoAddComponent implements OnInit {
21 user: User;
22 fileToUpload: any; 21 fileToUpload: any;
23 progressBar: { value: number; max: number; } = { value: 0, max: 0 }; 22 progressBar: { value: number; max: number; } = { value: 0, max: 0 };
23 user: User;
24 24
25 private _form: any; 25 private form: any;
26 26
27 constructor( 27 constructor(
28 private _router: Router, private _elementRef: ElementRef, 28 private router: Router,
29 private _authService: AuthService 29 private elementRef: ElementRef,
30 private authService: AuthService
30 ) {} 31 ) {}
31 32
32 ngOnInit() { 33 ngOnInit() {
33 this.user = User.load(); 34 this.user = User.load();
34 jQuery(this._elementRef.nativeElement).find('#videofile').fileupload({ 35 jQuery(this.elementRef.nativeElement).find('#videofile').fileupload({
35 url: '/api/v1/videos', 36 url: '/api/v1/videos',
36 dataType: 'json', 37 dataType: 'json',
37 singleFileUploads: true, 38 singleFileUploads: true,
@@ -39,7 +40,7 @@ export class VideoAddComponent implements OnInit {
39 autoupload: false, 40 autoupload: false,
40 41
41 add: (e, data) => { 42 add: (e, data) => {
42 this._form = data; 43 this.form = data;
43 this.fileToUpload = data['files'][0]; 44 this.fileToUpload = data['files'][0];
44 }, 45 },
45 46
@@ -55,14 +56,14 @@ export class VideoAddComponent implements OnInit {
55 console.log('Video uploaded.'); 56 console.log('Video uploaded.');
56 57
57 // Print all the videos once it's finished 58 // Print all the videos once it's finished
58 this._router.navigate(['VideosList']); 59 this.router.navigate(['VideosList']);
59 } 60 }
60 }); 61 });
61 } 62 }
62 63
63 uploadFile() { 64 uploadFile() {
64 this._form.headers = this._authService.getRequestHeader().toJSON(); 65 this.form.headers = this.authService.getRequestHeader().toJSON();
65 this._form.formData = jQuery(this._elementRef.nativeElement).find('form').serializeArray(); 66 this.form.formData = jQuery(this.elementRef.nativeElement).find('form').serializeArray();
66 this._form.submit(); 67 this.form.submit();
67 } 68 }
68} 69}
diff --git a/client/app/videos/video-list/video-list.component.ts b/client/app/videos/video-list/video-list.component.ts
index 3f54c98ce..23b97df32 100644
--- a/client/app/videos/video-list/video-list.component.ts
+++ b/client/app/videos/video-list/video-list.component.ts
@@ -23,23 +23,23 @@ import { VideoSortComponent } from './video-sort.component';
23}) 23})
24 24
25export class VideoListComponent implements OnInit { 25export class VideoListComponent implements OnInit {
26 user: User = null; 26 loading = false;
27 videos: Video[] = [];
28 pagination: Pagination = { 27 pagination: Pagination = {
29 currentPage: 1, 28 currentPage: 1,
30 itemsPerPage: 9, 29 itemsPerPage: 9,
31 total: 0 30 total: 0
32 }; 31 };
33 sort: SortField; 32 sort: SortField;
34 loading = false; 33 user: User = null;
34 videos: Video[] = [];
35 35
36 private search: Search; 36 private search: Search;
37 37
38 constructor( 38 constructor(
39 private authService: AuthService, 39 private authService: AuthService,
40 private videoService: VideoService, 40 private router: Router,
41 private routeParams: RouteParams, 41 private routeParams: RouteParams,
42 private router: Router 42 private videoService: VideoService
43 ) { 43 ) {
44 this.search = { 44 this.search = {
45 value: this.routeParams.get('search'), 45 value: this.routeParams.get('search'),
@@ -73,6 +73,7 @@ export class VideoListComponent implements OnInit {
73 ({ videos, totalVideos }) => { 73 ({ videos, totalVideos }) => {
74 this.videos = videos; 74 this.videos = videos;
75 this.pagination.total = totalVideos; 75 this.pagination.total = totalVideos;
76
76 this.loading = false; 77 this.loading = false;
77 }, 78 },
78 error => alert(error) 79 error => alert(error)
@@ -91,8 +92,8 @@ export class VideoListComponent implements OnInit {
91 }; 92 };
92 93
93 if (this.search.value) { 94 if (this.search.value) {
94 params.search = this.search.value;
95 params.field = this.search.field; 95 params.field = this.search.field;
96 params.search = this.search.value;
96 } 97 }
97 98
98 this.router.navigate(['VideosList', params]); 99 this.router.navigate(['VideosList', params]);
diff --git a/client/app/videos/video-list/video-miniature.component.ts b/client/app/videos/video-list/video-miniature.component.ts
index 73416607a..3baa1ddd6 100644
--- a/client/app/videos/video-list/video-miniature.component.ts
+++ b/client/app/videos/video-list/video-miniature.component.ts
@@ -16,23 +16,23 @@ import { User } from '../../users/index';
16export class VideoMiniatureComponent { 16export class VideoMiniatureComponent {
17 @Output() removed = new EventEmitter<any>(); 17 @Output() removed = new EventEmitter<any>();
18 18
19 @Input() video: Video;
20 @Input() user: User; 19 @Input() user: User;
20 @Input() video: Video;
21 21
22 hovering = false; 22 hovering = false;
23 23
24 constructor(private videoService: VideoService) {} 24 constructor(private videoService: VideoService) {}
25 25
26 onHover() { 26 displayRemoveIcon() {
27 this.hovering = true; 27 return this.hovering && this.video.isRemovableBy(this.user);
28 } 28 }
29 29
30 onBlur() { 30 onBlur() {
31 this.hovering = false; 31 this.hovering = false;
32 } 32 }
33 33
34 displayRemoveIcon() { 34 onHover() {
35 return this.hovering && this.video.isRemovableBy(this.user); 35 this.hovering = true;
36 } 36 }
37 37
38 removeVideo(id: string) { 38 removeVideo(id: string) {
diff --git a/client/app/videos/video-watch/video-watch.component.ts b/client/app/videos/video-watch/video-watch.component.ts
index c159b4004..137db8f0b 100644
--- a/client/app/videos/video-watch/video-watch.component.ts
+++ b/client/app/videos/video-watch/video-watch.component.ts
@@ -17,32 +17,24 @@ declare var WebTorrent: any;
17}) 17})
18 18
19export class VideoWatchComponent implements OnInit, CanDeactivate { 19export class VideoWatchComponent implements OnInit, CanDeactivate {
20 video: Video;
21 downloadSpeed: number; 20 downloadSpeed: number;
22 uploadSpeed: number;
23 numPeers: number;
24 loading: boolean = false; 21 loading: boolean = false;
22 numPeers: number;
23 uploadSpeed: number;
24 video: Video;
25 25
26 private interval: NodeJS.Timer;
27 private client: any; 26 private client: any;
27 private interval: NodeJS.Timer;
28 28
29 constructor( 29 constructor(
30 private videoService: VideoService, 30 private elementRef: ElementRef,
31 private routeParams: RouteParams, 31 private routeParams: RouteParams,
32 private elementRef: ElementRef 32 private videoService: VideoService
33 ) { 33 ) {
34 // TODO: use a service 34 // TODO: use a service
35 this.client = new WebTorrent({ dht: false }); 35 this.client = new WebTorrent({ dht: false });
36 } 36 }
37 37
38 ngOnInit() {
39 let id = this.routeParams.get('id');
40 this.videoService.getVideo(id).subscribe(
41 video => this.loadVideo(video),
42 error => alert(error)
43 );
44 }
45
46 loadVideo(video: Video) { 38 loadVideo(video: Video) {
47 this.loading = true; 39 this.loading = true;
48 this.video = video; 40 this.video = video;
@@ -60,12 +52,20 @@ export class VideoWatchComponent implements OnInit, CanDeactivate {
60 // Refresh each second 52 // Refresh each second
61 this.interval = setInterval(() => { 53 this.interval = setInterval(() => {
62 this.downloadSpeed = torrent.downloadSpeed; 54 this.downloadSpeed = torrent.downloadSpeed;
63 this.uploadSpeed = torrent.uploadSpeed;
64 this.numPeers = torrent.numPeers; 55 this.numPeers = torrent.numPeers;
56 this.uploadSpeed = torrent.uploadSpeed;
65 }, 1000); 57 }, 1000);
66 }); 58 });
67 } 59 }
68 60
61 ngOnInit() {
62 let id = this.routeParams.get('id');
63 this.videoService.getVideo(id).subscribe(
64 video => this.loadVideo(video),
65 error => alert(error)
66 );
67 }
68
69 routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) { 69 routerCanDeactivate(next: ComponentInstruction, prev: ComponentInstruction) {
70 console.log('Removing video from webtorrent.'); 70 console.log('Removing video from webtorrent.');
71 clearInterval(this.interval); 71 clearInterval(this.interval);