diff options
Diffstat (limited to 'client/app/videos/shared')
-rw-r--r-- | client/app/videos/shared/index.ts | 5 | ||||
-rw-r--r-- | client/app/videos/shared/loader/index.ts | 1 | ||||
-rw-r--r-- | client/app/videos/shared/loader/loader.component.html | 3 | ||||
-rw-r--r-- | client/app/videos/shared/loader/loader.component.scss | 26 | ||||
-rw-r--r-- | client/app/videos/shared/loader/loader.component.ts | 11 | ||||
-rw-r--r-- | client/app/videos/shared/pagination.model.ts | 5 | ||||
-rw-r--r-- | client/app/videos/shared/sort-field.type.ts | 3 | ||||
-rw-r--r-- | client/app/videos/shared/video.model.ts | 63 | ||||
-rw-r--r-- | client/app/videos/shared/video.service.ts | 79 |
9 files changed, 196 insertions, 0 deletions
diff --git a/client/app/videos/shared/index.ts b/client/app/videos/shared/index.ts new file mode 100644 index 000000000..c535c46fc --- /dev/null +++ b/client/app/videos/shared/index.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | export * from './loader/index'; | ||
2 | export * from './pagination.model'; | ||
3 | export * from './sort-field.type'; | ||
4 | export * from './video.model'; | ||
5 | export * from './video.service'; | ||
diff --git a/client/app/videos/shared/loader/index.ts b/client/app/videos/shared/loader/index.ts new file mode 100644 index 000000000..ab22584e4 --- /dev/null +++ b/client/app/videos/shared/loader/index.ts | |||
@@ -0,0 +1 @@ | |||
export * from './loader.component'; | |||
diff --git a/client/app/videos/shared/loader/loader.component.html b/client/app/videos/shared/loader/loader.component.html new file mode 100644 index 000000000..d02296a2d --- /dev/null +++ b/client/app/videos/shared/loader/loader.component.html | |||
@@ -0,0 +1,3 @@ | |||
1 | <div id="video-loading" class="col-md-12 text-center" *ngIf="loading"> | ||
2 | <div class="glyphicon glyphicon-refresh glyphicon-refresh-animate"></div> | ||
3 | </div> | ||
diff --git a/client/app/videos/shared/loader/loader.component.scss b/client/app/videos/shared/loader/loader.component.scss new file mode 100644 index 000000000..454195811 --- /dev/null +++ b/client/app/videos/shared/loader/loader.component.scss | |||
@@ -0,0 +1,26 @@ | |||
1 | div { | ||
2 | margin-top: 150px; | ||
3 | } | ||
4 | |||
5 | // Thanks https://gist.github.com/alexandrevicenzi/680147013e902a4eaa5d | ||
6 | .glyphicon-refresh-animate { | ||
7 | -animation: spin .7s infinite linear; | ||
8 | -ms-animation: spin .7s infinite linear; | ||
9 | -webkit-animation: spinw .7s infinite linear; | ||
10 | -moz-animation: spinm .7s infinite linear; | ||
11 | } | ||
12 | |||
13 | @keyframes spin { | ||
14 | from { transform: scale(1) rotate(0deg);} | ||
15 | to { transform: scale(1) rotate(360deg);} | ||
16 | } | ||
17 | |||
18 | @-webkit-keyframes spinw { | ||
19 | from { -webkit-transform: rotate(0deg);} | ||
20 | to { -webkit-transform: rotate(360deg);} | ||
21 | } | ||
22 | |||
23 | @-moz-keyframes spinm { | ||
24 | from { -moz-transform: rotate(0deg);} | ||
25 | to { -moz-transform: rotate(360deg);} | ||
26 | } | ||
diff --git a/client/app/videos/shared/loader/loader.component.ts b/client/app/videos/shared/loader/loader.component.ts new file mode 100644 index 000000000..666d43bc3 --- /dev/null +++ b/client/app/videos/shared/loader/loader.component.ts | |||
@@ -0,0 +1,11 @@ | |||
1 | import { Component, Input } from '@angular/core'; | ||
2 | |||
3 | @Component({ | ||
4 | selector: 'my-loader', | ||
5 | styleUrls: [ 'client/app/videos/shared/loader/loader.component.css' ], | ||
6 | templateUrl: 'client/app/videos/shared/loader/loader.component.html' | ||
7 | }) | ||
8 | |||
9 | export class LoaderComponent { | ||
10 | @Input() loading: boolean; | ||
11 | } | ||
diff --git a/client/app/videos/shared/pagination.model.ts b/client/app/videos/shared/pagination.model.ts new file mode 100644 index 000000000..06f7a7875 --- /dev/null +++ b/client/app/videos/shared/pagination.model.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | export interface Pagination { | ||
2 | currentPage: number; | ||
3 | itemsPerPage: number; | ||
4 | total: number; | ||
5 | } | ||
diff --git a/client/app/videos/shared/sort-field.type.ts b/client/app/videos/shared/sort-field.type.ts new file mode 100644 index 000000000..6e8cc7936 --- /dev/null +++ b/client/app/videos/shared/sort-field.type.ts | |||
@@ -0,0 +1,3 @@ | |||
1 | export type SortField = "name" | "-name" | ||
2 | | "duration" | "-duration" | ||
3 | | "createdDate" | "-createdDate"; | ||
diff --git a/client/app/videos/shared/video.model.ts b/client/app/videos/shared/video.model.ts new file mode 100644 index 000000000..eec537c9e --- /dev/null +++ b/client/app/videos/shared/video.model.ts | |||
@@ -0,0 +1,63 @@ | |||
1 | export class Video { | ||
2 | id: string; | ||
3 | name: string; | ||
4 | description: string; | ||
5 | magnetUri: string; | ||
6 | podUrl: string; | ||
7 | isLocal: boolean; | ||
8 | thumbnailPath: string; | ||
9 | author: string; | ||
10 | createdDate: Date; | ||
11 | by: string; | ||
12 | duration: string; | ||
13 | |||
14 | private static createDurationString(duration: number): string { | ||
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 | |||
23 | private static createByString(author: string, podUrl: string): string { | ||
24 | let [ host, port ] = podUrl.replace(/^https?:\/\//, '').split(':'); | ||
25 | |||
26 | if (port === '80' || port === '443') { | ||
27 | port = ''; | ||
28 | } else { | ||
29 | port = ':' + port; | ||
30 | } | ||
31 | |||
32 | return author + '@' + host + port; | ||
33 | } | ||
34 | |||
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, | ||
44 | createdDate: string, | ||
45 | duration: number; | ||
46 | }) { | ||
47 | this.id = hash.id; | ||
48 | this.name = hash.name; | ||
49 | this.description = hash.description; | ||
50 | this.magnetUri = hash.magnetUri; | ||
51 | this.podUrl = hash.podUrl; | ||
52 | this.isLocal = hash.isLocal; | ||
53 | this.thumbnailPath = hash.thumbnailPath; | ||
54 | this.author = hash.author; | ||
55 | this.createdDate = new Date(hash.createdDate); | ||
56 | this.duration = Video.createDurationString(hash.duration); | ||
57 | this.by = Video.createByString(hash.author, hash.podUrl); | ||
58 | } | ||
59 | |||
60 | isRemovableBy(user): boolean { | ||
61 | return this.isLocal === true && user && this.author === user.username; | ||
62 | } | ||
63 | } | ||
diff --git a/client/app/videos/shared/video.service.ts b/client/app/videos/shared/video.service.ts new file mode 100644 index 000000000..78789c3cc --- /dev/null +++ b/client/app/videos/shared/video.service.ts | |||
@@ -0,0 +1,79 @@ | |||
1 | import { Injectable } from '@angular/core'; | ||
2 | import { Http, Response, URLSearchParams } from '@angular/http'; | ||
3 | import { Observable } from 'rxjs/Rx'; | ||
4 | |||
5 | import { Pagination } from './pagination.model'; | ||
6 | import { Search } from '../../shared/index'; | ||
7 | import { SortField } from './sort-field.type'; | ||
8 | import { AuthService } from '../../users/index'; | ||
9 | import { Video } from './video.model'; | ||
10 | |||
11 | @Injectable() | ||
12 | export class VideoService { | ||
13 | private _baseVideoUrl = '/api/v1/videos/'; | ||
14 | |||
15 | constructor (private http: Http, private _authService: AuthService) {} | ||
16 | |||
17 | getVideos(pagination: Pagination, sort: SortField) { | ||
18 | const params = this.createPaginationParams(pagination); | ||
19 | |||
20 | if (sort) params.set('sort', sort); | ||
21 | |||
22 | return this.http.get(this._baseVideoUrl, { search: params }) | ||
23 | .map(res => res.json()) | ||
24 | .map(this.extractVideos) | ||
25 | .catch(this.handleError); | ||
26 | } | ||
27 | |||
28 | getVideo(id: string) { | ||
29 | return this.http.get(this._baseVideoUrl + id) | ||
30 | .map(res => <Video> res.json()) | ||
31 | .catch(this.handleError); | ||
32 | } | ||
33 | |||
34 | removeVideo(id: string) { | ||
35 | const options = this._authService.getAuthRequestOptions(); | ||
36 | return this.http.delete(this._baseVideoUrl + id, options) | ||
37 | .map(res => <number> res.status) | ||
38 | .catch(this.handleError); | ||
39 | } | ||
40 | |||
41 | searchVideos(search: Search, pagination: Pagination, sort: SortField) { | ||
42 | const params = this.createPaginationParams(pagination); | ||
43 | |||
44 | if (search.field) params.set('field', search.field); | ||
45 | if (sort) params.set('sort', sort); | ||
46 | |||
47 | return this.http.get(this._baseVideoUrl + 'search/' + encodeURIComponent(search.value), { search: params }) | ||
48 | .map(res => res.json()) | ||
49 | .map(this.extractVideos) | ||
50 | .catch(this.handleError); | ||
51 | } | ||
52 | |||
53 | private extractVideos (body: any) { | ||
54 | const videos_json = body.data; | ||
55 | const totalVideos = body.total; | ||
56 | const videos = []; | ||
57 | for (const video_json of videos_json) { | ||
58 | videos.push(new Video(video_json)); | ||
59 | } | ||
60 | |||
61 | return { videos, totalVideos }; | ||
62 | } | ||
63 | |||
64 | private handleError (error: Response) { | ||
65 | console.error(error); | ||
66 | return Observable.throw(error.json().error || 'Server error'); | ||
67 | } | ||
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 | } | ||