diff options
Diffstat (limited to 'client/src/app/videos')
24 files changed, 642 insertions, 645 deletions
diff --git a/client/src/app/videos/index.ts b/client/src/app/videos/index.ts index 5158a23f8..83edcc758 100644 --- a/client/src/app/videos/index.ts +++ b/client/src/app/videos/index.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | export * from './shared'; | 1 | export * from './shared' |
2 | export * from './video-edit'; | 2 | export * from './video-edit' |
3 | export * from './video-list'; | 3 | export * from './video-list' |
4 | export * from './video-watch'; | 4 | export * from './video-watch' |
5 | export * from './videos-routing.module'; | 5 | export * from './videos-routing.module' |
6 | export * from './videos.component'; | 6 | export * from './videos.component' |
7 | export * from './videos.module'; | 7 | export * from './videos.module' |
diff --git a/client/src/app/videos/shared/index.ts b/client/src/app/videos/shared/index.ts index a68491022..0fa14f641 100644 --- a/client/src/app/videos/shared/index.ts +++ b/client/src/app/videos/shared/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './sort-field.type'; | 1 | export * from './sort-field.type' |
2 | export * from './rate-type.type'; | 2 | export * from './rate-type.type' |
3 | export * from './video.model'; | 3 | export * from './video.model' |
4 | export * from './video.service'; | 4 | export * from './video.service' |
diff --git a/client/src/app/videos/shared/rate-type.type.ts b/client/src/app/videos/shared/rate-type.type.ts index 88034d1ff..20eea3ae5 100644 --- a/client/src/app/videos/shared/rate-type.type.ts +++ b/client/src/app/videos/shared/rate-type.type.ts | |||
@@ -1 +1 @@ | |||
export type RateType = 'like' | 'dislike'; | export type RateType = 'like' | 'dislike' | ||
diff --git a/client/src/app/videos/shared/sort-field.type.ts b/client/src/app/videos/shared/sort-field.type.ts index 6cc598d8b..776f360f8 100644 --- a/client/src/app/videos/shared/sort-field.type.ts +++ b/client/src/app/videos/shared/sort-field.type.ts | |||
@@ -2,5 +2,4 @@ export type SortField = 'name' | '-name' | |||
2 | | 'duration' | '-duration' | 2 | | 'duration' | '-duration' |
3 | | 'createdAt' | '-createdAt' | 3 | | 'createdAt' | '-createdAt' |
4 | | 'views' | '-views' | 4 | | 'views' | '-views' |
5 | | 'likes' | '-likes'; | 5 | | 'likes' | '-likes' |
6 | |||
diff --git a/client/src/app/videos/shared/video.model.ts b/client/src/app/videos/shared/video.model.ts index e897eb175..f5e16fc13 100644 --- a/client/src/app/videos/shared/video.model.ts +++ b/client/src/app/videos/shared/video.model.ts | |||
@@ -1,56 +1,56 @@ | |||
1 | import { Video as VideoServerModel } from '../../../../../shared'; | 1 | import { Video as VideoServerModel } from '../../../../../shared' |
2 | import { User } from '../../shared'; | 2 | import { User } from '../../shared' |
3 | 3 | ||
4 | export class Video implements VideoServerModel { | 4 | export class Video implements VideoServerModel { |
5 | author: string; | 5 | author: string |
6 | by: string; | 6 | by: string |
7 | createdAt: Date; | 7 | createdAt: Date |
8 | categoryLabel: string; | 8 | categoryLabel: string |
9 | category: number; | 9 | category: number |
10 | licenceLabel: string; | 10 | licenceLabel: string |
11 | licence: number; | 11 | licence: number |
12 | languageLabel: string; | 12 | languageLabel: string |
13 | language: number; | 13 | language: number |
14 | description: string; | 14 | description: string |
15 | duration: number; | 15 | duration: number |
16 | durationLabel: string; | 16 | durationLabel: string |
17 | id: string; | 17 | id: string |
18 | isLocal: boolean; | 18 | isLocal: boolean |
19 | magnetUri: string; | 19 | magnetUri: string |
20 | name: string; | 20 | name: string |
21 | podHost: string; | 21 | podHost: string |
22 | tags: string[]; | 22 | tags: string[] |
23 | thumbnailPath: string; | 23 | thumbnailPath: string |
24 | thumbnailUrl: string; | 24 | thumbnailUrl: string |
25 | views: number; | 25 | views: number |
26 | likes: number; | 26 | likes: number |
27 | dislikes: number; | 27 | dislikes: number |
28 | nsfw: boolean; | 28 | nsfw: boolean |
29 | 29 | ||
30 | private static createByString(author: string, podHost: string) { | 30 | private static createByString (author: string, podHost: string) { |
31 | return author + '@' + podHost; | 31 | return author + '@' + podHost |
32 | } | 32 | } |
33 | 33 | ||
34 | private static createDurationString(duration: number) { | 34 | private static createDurationString (duration: number) { |
35 | const minutes = Math.floor(duration / 60); | 35 | const minutes = Math.floor(duration / 60) |
36 | const seconds = duration % 60; | 36 | const seconds = duration % 60 |
37 | const minutes_padding = minutes >= 10 ? '' : '0'; | 37 | const minutesPadding = minutes >= 10 ? '' : '0' |
38 | const seconds_padding = seconds >= 10 ? '' : '0'; | 38 | const secondsPadding = seconds >= 10 ? '' : '0' |
39 | 39 | ||
40 | return minutes_padding + minutes.toString() + ':' + seconds_padding + seconds.toString(); | 40 | return minutesPadding + minutes.toString() + ':' + secondsPadding + seconds.toString() |
41 | } | 41 | } |
42 | 42 | ||
43 | constructor(hash: { | 43 | constructor (hash: { |
44 | author: string, | 44 | author: string, |
45 | createdAt: string, | 45 | createdAt: string, |
46 | categoryLabel: string, | 46 | categoryLabel: string, |
47 | category: number, | 47 | category: number, |
48 | licenceLabel: string, | 48 | licenceLabel: string, |
49 | licence: number, | 49 | licence: number, |
50 | languageLabel: string; | 50 | languageLabel: string |
51 | language: number; | 51 | language: number |
52 | description: string, | 52 | description: string, |
53 | duration: number; | 53 | duration: number |
54 | id: string, | 54 | id: string, |
55 | isLocal: boolean, | 55 | isLocal: boolean, |
56 | magnetUri: string, | 56 | magnetUri: string, |
@@ -63,57 +63,57 @@ export class Video implements VideoServerModel { | |||
63 | dislikes: number, | 63 | dislikes: number, |
64 | nsfw: boolean | 64 | nsfw: boolean |
65 | }) { | 65 | }) { |
66 | this.author = hash.author; | 66 | this.author = hash.author |
67 | this.createdAt = new Date(hash.createdAt); | 67 | this.createdAt = new Date(hash.createdAt) |
68 | this.categoryLabel = hash.categoryLabel; | 68 | this.categoryLabel = hash.categoryLabel |
69 | this.category = hash.category; | 69 | this.category = hash.category |
70 | this.licenceLabel = hash.licenceLabel; | 70 | this.licenceLabel = hash.licenceLabel |
71 | this.licence = hash.licence; | 71 | this.licence = hash.licence |
72 | this.languageLabel = hash.languageLabel; | 72 | this.languageLabel = hash.languageLabel |
73 | this.language = hash.language; | 73 | this.language = hash.language |
74 | this.description = hash.description; | 74 | this.description = hash.description |
75 | this.duration = hash.duration; | 75 | this.duration = hash.duration |
76 | this.durationLabel = Video.createDurationString(hash.duration); | 76 | this.durationLabel = Video.createDurationString(hash.duration) |
77 | this.id = hash.id; | 77 | this.id = hash.id |
78 | this.isLocal = hash.isLocal; | 78 | this.isLocal = hash.isLocal |
79 | this.magnetUri = hash.magnetUri; | 79 | this.magnetUri = hash.magnetUri |
80 | this.name = hash.name; | 80 | this.name = hash.name |
81 | this.podHost = hash.podHost; | 81 | this.podHost = hash.podHost |
82 | this.tags = hash.tags; | 82 | this.tags = hash.tags |
83 | this.thumbnailPath = hash.thumbnailPath; | 83 | this.thumbnailPath = hash.thumbnailPath |
84 | this.thumbnailUrl = API_URL + hash.thumbnailPath; | 84 | this.thumbnailUrl = API_URL + hash.thumbnailPath |
85 | this.views = hash.views; | 85 | this.views = hash.views |
86 | this.likes = hash.likes; | 86 | this.likes = hash.likes |
87 | this.dislikes = hash.dislikes; | 87 | this.dislikes = hash.dislikes |
88 | this.nsfw = hash.nsfw; | 88 | this.nsfw = hash.nsfw |
89 | 89 | ||
90 | this.by = Video.createByString(hash.author, hash.podHost); | 90 | this.by = Video.createByString(hash.author, hash.podHost) |
91 | } | 91 | } |
92 | 92 | ||
93 | isRemovableBy(user) { | 93 | isRemovableBy (user) { |
94 | return user && this.isLocal === true && (this.author === user.username || user.isAdmin() === true); | 94 | return user && this.isLocal === true && (this.author === user.username || user.isAdmin() === true) |
95 | } | 95 | } |
96 | 96 | ||
97 | isBlackistableBy(user) { | 97 | isBlackistableBy (user) { |
98 | return user && user.isAdmin() === true && this.isLocal === false; | 98 | return user && user.isAdmin() === true && this.isLocal === false |
99 | } | 99 | } |
100 | 100 | ||
101 | isUpdatableBy(user) { | 101 | isUpdatableBy (user) { |
102 | return user && this.isLocal === true && user.username === this.author; | 102 | return user && this.isLocal === true && user.username === this.author |
103 | } | 103 | } |
104 | 104 | ||
105 | isVideoNSFWForUser(user: User) { | 105 | isVideoNSFWForUser (user: User) { |
106 | // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos... | 106 | // If the video is NSFW and the user is not logged in, or the user does not want to display NSFW videos... |
107 | return (this.nsfw && (!user || user.displayNSFW === false)); | 107 | return (this.nsfw && (!user || user.displayNSFW === false)) |
108 | } | 108 | } |
109 | 109 | ||
110 | patch(values: Object) { | 110 | patch (values: Object) { |
111 | Object.keys(values).forEach((key) => { | 111 | Object.keys(values).forEach((key) => { |
112 | this[key] = values[key]; | 112 | this[key] = values[key] |
113 | }); | 113 | }) |
114 | } | 114 | } |
115 | 115 | ||
116 | toJSON() { | 116 | toJSON () { |
117 | return { | 117 | return { |
118 | author: this.author, | 118 | author: this.author, |
119 | createdAt: this.createdAt, | 119 | createdAt: this.createdAt, |
@@ -133,6 +133,6 @@ export class Video implements VideoServerModel { | |||
133 | likes: this.likes, | 133 | likes: this.likes, |
134 | dislikes: this.dislikes, | 134 | dislikes: this.dislikes, |
135 | nsfw: this.nsfw | 135 | nsfw: this.nsfw |
136 | }; | 136 | } |
137 | } | 137 | } |
138 | } | 138 | } |
diff --git a/client/src/app/videos/shared/video.service.ts b/client/src/app/videos/shared/video.service.ts index a53ea1064..a4e3d16df 100644 --- a/client/src/app/videos/shared/video.service.ts +++ b/client/src/app/videos/shared/video.service.ts | |||
@@ -1,13 +1,13 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Http, Headers, RequestOptions } from '@angular/http'; | 2 | import { Http, Headers, RequestOptions } from '@angular/http' |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Observable } from 'rxjs/Observable' |
4 | import 'rxjs/add/operator/catch'; | 4 | import 'rxjs/add/operator/catch' |
5 | import 'rxjs/add/operator/map'; | 5 | import 'rxjs/add/operator/map' |
6 | 6 | ||
7 | import { Search } from '../../shared'; | 7 | import { Search } from '../../shared' |
8 | import { SortField } from './sort-field.type'; | 8 | import { SortField } from './sort-field.type' |
9 | import { RateType } from './rate-type.type'; | 9 | import { RateType } from './rate-type.type' |
10 | import { AuthService } from '../../core'; | 10 | import { AuthService } from '../../core' |
11 | import { | 11 | import { |
12 | AuthHttp, | 12 | AuthHttp, |
13 | RestExtractor, | 13 | RestExtractor, |
@@ -15,18 +15,18 @@ import { | |||
15 | RestService, | 15 | RestService, |
16 | ResultList, | 16 | ResultList, |
17 | UserService | 17 | UserService |
18 | } from '../../shared'; | 18 | } from '../../shared' |
19 | import { Video } from './video.model'; | 19 | import { Video } from './video.model' |
20 | 20 | ||
21 | @Injectable() | 21 | @Injectable() |
22 | export class VideoService { | 22 | export class VideoService { |
23 | private static BASE_VIDEO_URL = API_URL + '/api/v1/videos/'; | 23 | private static BASE_VIDEO_URL = API_URL + '/api/v1/videos/' |
24 | 24 | ||
25 | videoCategories: Array<{ id: number, label: string }> = []; | 25 | videoCategories: Array<{ id: number, label: string }> = [] |
26 | videoLicences: Array<{ id: number, label: string }> = []; | 26 | videoLicences: Array<{ id: number, label: string }> = [] |
27 | videoLanguages: Array<{ id: number, label: string }> = []; | 27 | videoLanguages: Array<{ id: number, label: string }> = [] |
28 | 28 | ||
29 | constructor( | 29 | constructor ( |
30 | private authService: AuthService, | 30 | private authService: AuthService, |
31 | private authHttp: AuthHttp, | 31 | private authHttp: AuthHttp, |
32 | private http: Http, | 32 | private http: Http, |
@@ -34,54 +34,54 @@ export class VideoService { | |||
34 | private restService: RestService | 34 | private restService: RestService |
35 | ) {} | 35 | ) {} |
36 | 36 | ||
37 | loadVideoCategories() { | 37 | loadVideoCategories () { |
38 | return this.http.get(VideoService.BASE_VIDEO_URL + 'categories') | 38 | return this.http.get(VideoService.BASE_VIDEO_URL + 'categories') |
39 | .map(this.restExtractor.extractDataGet) | 39 | .map(this.restExtractor.extractDataGet) |
40 | .subscribe(data => { | 40 | .subscribe(data => { |
41 | Object.keys(data).forEach(categoryKey => { | 41 | Object.keys(data).forEach(categoryKey => { |
42 | this.videoCategories.push({ | 42 | this.videoCategories.push({ |
43 | id: parseInt(categoryKey), | 43 | id: parseInt(categoryKey, 10), |
44 | label: data[categoryKey] | 44 | label: data[categoryKey] |
45 | }); | 45 | }) |
46 | }); | 46 | }) |
47 | }); | 47 | }) |
48 | } | 48 | } |
49 | 49 | ||
50 | loadVideoLicences() { | 50 | loadVideoLicences () { |
51 | return this.http.get(VideoService.BASE_VIDEO_URL + 'licences') | 51 | return this.http.get(VideoService.BASE_VIDEO_URL + 'licences') |
52 | .map(this.restExtractor.extractDataGet) | 52 | .map(this.restExtractor.extractDataGet) |
53 | .subscribe(data => { | 53 | .subscribe(data => { |
54 | Object.keys(data).forEach(licenceKey => { | 54 | Object.keys(data).forEach(licenceKey => { |
55 | this.videoLicences.push({ | 55 | this.videoLicences.push({ |
56 | id: parseInt(licenceKey), | 56 | id: parseInt(licenceKey, 10), |
57 | label: data[licenceKey] | 57 | label: data[licenceKey] |
58 | }); | 58 | }) |
59 | }); | 59 | }) |
60 | }); | 60 | }) |
61 | } | 61 | } |
62 | 62 | ||
63 | loadVideoLanguages() { | 63 | loadVideoLanguages () { |
64 | return this.http.get(VideoService.BASE_VIDEO_URL + 'languages') | 64 | return this.http.get(VideoService.BASE_VIDEO_URL + 'languages') |
65 | .map(this.restExtractor.extractDataGet) | 65 | .map(this.restExtractor.extractDataGet) |
66 | .subscribe(data => { | 66 | .subscribe(data => { |
67 | Object.keys(data).forEach(languageKey => { | 67 | Object.keys(data).forEach(languageKey => { |
68 | this.videoLanguages.push({ | 68 | this.videoLanguages.push({ |
69 | id: parseInt(languageKey), | 69 | id: parseInt(languageKey, 10), |
70 | label: data[languageKey] | 70 | label: data[languageKey] |
71 | }); | 71 | }) |
72 | }); | 72 | }) |
73 | }); | 73 | }) |
74 | } | 74 | } |
75 | 75 | ||
76 | getVideo(id: string): Observable<Video> { | 76 | getVideo (id: string): Observable<Video> { |
77 | return this.http.get(VideoService.BASE_VIDEO_URL + id) | 77 | return this.http.get(VideoService.BASE_VIDEO_URL + id) |
78 | .map(this.restExtractor.extractDataGet) | 78 | .map(this.restExtractor.extractDataGet) |
79 | .map(video_hash => new Video(video_hash)) | 79 | .map(videoHash => new Video(videoHash)) |
80 | .catch((res) => this.restExtractor.handleError(res)); | 80 | .catch((res) => this.restExtractor.handleError(res)) |
81 | } | 81 | } |
82 | 82 | ||
83 | updateVideo(video: Video) { | 83 | updateVideo (video: Video) { |
84 | const language = video.language ? video.language : null; | 84 | const language = video.language ? video.language : null |
85 | 85 | ||
86 | const body = { | 86 | const body = { |
87 | name: video.name, | 87 | name: video.name, |
@@ -90,94 +90,94 @@ export class VideoService { | |||
90 | language, | 90 | language, |
91 | description: video.description, | 91 | description: video.description, |
92 | tags: video.tags | 92 | tags: video.tags |
93 | }; | 93 | } |
94 | 94 | ||
95 | const headers = new Headers({ 'Content-Type': 'application/json' }); | 95 | const headers = new Headers({ 'Content-Type': 'application/json' }) |
96 | const options = new RequestOptions({ headers: headers }); | 96 | const options = new RequestOptions({ headers: headers }) |
97 | 97 | ||
98 | return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options) | 98 | return this.authHttp.put(`${VideoService.BASE_VIDEO_URL}/${video.id}`, body, options) |
99 | .map(this.restExtractor.extractDataBool) | 99 | .map(this.restExtractor.extractDataBool) |
100 | .catch(this.restExtractor.handleError); | 100 | .catch(this.restExtractor.handleError) |
101 | } | 101 | } |
102 | 102 | ||
103 | getVideos(pagination: RestPagination, sort: SortField) { | 103 | getVideos (pagination: RestPagination, sort: SortField) { |
104 | const params = this.restService.buildRestGetParams(pagination, sort); | 104 | const params = this.restService.buildRestGetParams(pagination, sort) |
105 | 105 | ||
106 | return this.http.get(VideoService.BASE_VIDEO_URL, { search: params }) | 106 | return this.http.get(VideoService.BASE_VIDEO_URL, { search: params }) |
107 | .map(res => res.json()) | 107 | .map(res => res.json()) |
108 | .map(this.extractVideos) | 108 | .map(this.extractVideos) |
109 | .catch((res) => this.restExtractor.handleError(res)); | 109 | .catch((res) => this.restExtractor.handleError(res)) |
110 | } | 110 | } |
111 | 111 | ||
112 | removeVideo(id: string) { | 112 | removeVideo (id: string) { |
113 | return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) | 113 | return this.authHttp.delete(VideoService.BASE_VIDEO_URL + id) |
114 | .map(this.restExtractor.extractDataBool) | 114 | .map(this.restExtractor.extractDataBool) |
115 | .catch((res) => this.restExtractor.handleError(res)); | 115 | .catch((res) => this.restExtractor.handleError(res)) |
116 | } | 116 | } |
117 | 117 | ||
118 | searchVideos(search: Search, pagination: RestPagination, sort: SortField) { | 118 | searchVideos (search: Search, pagination: RestPagination, sort: SortField) { |
119 | const params = this.restService.buildRestGetParams(pagination, sort); | 119 | const params = this.restService.buildRestGetParams(pagination, sort) |
120 | 120 | ||
121 | if (search.field) params.set('field', search.field); | 121 | if (search.field) params.set('field', search.field) |
122 | 122 | ||
123 | return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params }) | 123 | return this.http.get(VideoService.BASE_VIDEO_URL + 'search/' + encodeURIComponent(search.value), { search: params }) |
124 | .map(this.restExtractor.extractDataList) | 124 | .map(this.restExtractor.extractDataList) |
125 | .map(this.extractVideos) | 125 | .map(this.extractVideos) |
126 | .catch((res) => this.restExtractor.handleError(res)); | 126 | .catch((res) => this.restExtractor.handleError(res)) |
127 | } | 127 | } |
128 | 128 | ||
129 | reportVideo(id: string, reason: string) { | 129 | reportVideo (id: string, reason: string) { |
130 | const url = VideoService.BASE_VIDEO_URL + id + '/abuse'; | 130 | const url = VideoService.BASE_VIDEO_URL + id + '/abuse' |
131 | const body = { | 131 | const body = { |
132 | reason | 132 | reason |
133 | }; | 133 | } |
134 | 134 | ||
135 | return this.authHttp.post(url, body) | 135 | return this.authHttp.post(url, body) |
136 | .map(this.restExtractor.extractDataBool) | 136 | .map(this.restExtractor.extractDataBool) |
137 | .catch((res) => this.restExtractor.handleError(res)); | 137 | .catch((res) => this.restExtractor.handleError(res)) |
138 | } | 138 | } |
139 | 139 | ||
140 | setVideoLike(id: string) { | 140 | setVideoLike (id: string) { |
141 | return this.setVideoRate(id, 'like'); | 141 | return this.setVideoRate(id, 'like') |
142 | } | 142 | } |
143 | 143 | ||
144 | setVideoDislike(id: string) { | 144 | setVideoDislike (id: string) { |
145 | return this.setVideoRate(id, 'dislike'); | 145 | return this.setVideoRate(id, 'dislike') |
146 | } | 146 | } |
147 | 147 | ||
148 | getUserVideoRating(id: string) { | 148 | getUserVideoRating (id: string) { |
149 | const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating'; | 149 | const url = UserService.BASE_USERS_URL + '/me/videos/' + id + '/rating' |
150 | 150 | ||
151 | return this.authHttp.get(url) | 151 | return this.authHttp.get(url) |
152 | .map(this.restExtractor.extractDataGet) | 152 | .map(this.restExtractor.extractDataGet) |
153 | .catch((res) => this.restExtractor.handleError(res)); | 153 | .catch((res) => this.restExtractor.handleError(res)) |
154 | } | 154 | } |
155 | 155 | ||
156 | blacklistVideo(id: string) { | 156 | blacklistVideo (id: string) { |
157 | return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {}) | 157 | return this.authHttp.post(VideoService.BASE_VIDEO_URL + id + '/blacklist', {}) |
158 | .map(this.restExtractor.extractDataBool) | 158 | .map(this.restExtractor.extractDataBool) |
159 | .catch((res) => this.restExtractor.handleError(res)); | 159 | .catch((res) => this.restExtractor.handleError(res)) |
160 | } | 160 | } |
161 | 161 | ||
162 | private setVideoRate(id: string, rateType: RateType) { | 162 | private setVideoRate (id: string, rateType: RateType) { |
163 | const url = VideoService.BASE_VIDEO_URL + id + '/rate'; | 163 | const url = VideoService.BASE_VIDEO_URL + id + '/rate' |
164 | const body = { | 164 | const body = { |
165 | rating: rateType | 165 | rating: rateType |
166 | }; | 166 | } |
167 | 167 | ||
168 | return this.authHttp.put(url, body) | 168 | return this.authHttp.put(url, body) |
169 | .map(this.restExtractor.extractDataBool) | 169 | .map(this.restExtractor.extractDataBool) |
170 | .catch((res) => this.restExtractor.handleError(res)); | 170 | .catch((res) => this.restExtractor.handleError(res)) |
171 | } | 171 | } |
172 | 172 | ||
173 | private extractVideos(result: ResultList) { | 173 | private extractVideos (result: ResultList) { |
174 | const videosJson = result.data; | 174 | const videosJson = result.data |
175 | const totalVideos = result.total; | 175 | const totalVideos = result.total |
176 | const videos = []; | 176 | const videos = [] |
177 | for (const videoJson of videosJson) { | 177 | for (const videoJson of videosJson) { |
178 | videos.push(new Video(videoJson)); | 178 | videos.push(new Video(videoJson)) |
179 | } | 179 | } |
180 | 180 | ||
181 | return { videos, totalVideos }; | 181 | return { videos, totalVideos } |
182 | } | 182 | } |
183 | } | 183 | } |
diff --git a/client/src/app/videos/video-edit/index.ts b/client/src/app/videos/video-edit/index.ts index 5ce4fb9b1..3b4a9cb87 100644 --- a/client/src/app/videos/video-edit/index.ts +++ b/client/src/app/videos/video-edit/index.ts | |||
@@ -1,2 +1,2 @@ | |||
1 | export * from './video-add.component'; | 1 | export * from './video-add.component' |
2 | export * from './video-update.component'; | 2 | export * from './video-update.component' |
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 e5eb9a9f4..0653f5ac4 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,11 @@ | |||
1 | import { Component, ElementRef, OnInit } from '@angular/core'; | 1 | import { Component, ElementRef, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { Router } from '@angular/router'; | 3 | import { Router } from '@angular/router' |
4 | 4 | ||
5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload'; | 5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload' |
6 | import { NotificationsService } from 'angular2-notifications'; | 6 | import { NotificationsService } from 'angular2-notifications' |
7 | 7 | ||
8 | import { AuthService } from '../../core'; | 8 | import { AuthService } from '../../core' |
9 | import { | 9 | import { |
10 | FormReactive, | 10 | FormReactive, |
11 | VIDEO_NAME, | 11 | VIDEO_NAME, |
@@ -14,8 +14,8 @@ import { | |||
14 | VIDEO_LANGUAGE, | 14 | VIDEO_LANGUAGE, |
15 | VIDEO_DESCRIPTION, | 15 | VIDEO_DESCRIPTION, |
16 | VIDEO_TAGS | 16 | VIDEO_TAGS |
17 | } from '../../shared'; | 17 | } from '../../shared' |
18 | import { VideoService } from '../shared'; | 18 | import { VideoService } from '../shared' |
19 | 19 | ||
20 | @Component({ | 20 | @Component({ |
21 | selector: 'my-videos-add', | 21 | selector: 'my-videos-add', |
@@ -24,36 +24,36 @@ import { VideoService } from '../shared'; | |||
24 | }) | 24 | }) |
25 | 25 | ||
26 | export class VideoAddComponent extends FormReactive implements OnInit { | 26 | export class VideoAddComponent extends FormReactive implements OnInit { |
27 | tags: string[] = []; | 27 | tags: string[] = [] |
28 | uploader: FileUploader; | 28 | uploader: FileUploader |
29 | videoCategories = []; | 29 | videoCategories = [] |
30 | videoLicences = []; | 30 | videoLicences = [] |
31 | videoLanguages = []; | 31 | videoLanguages = [] |
32 | 32 | ||
33 | tagValidators = VIDEO_TAGS.VALIDATORS; | 33 | tagValidators = VIDEO_TAGS.VALIDATORS |
34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES; | 34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES |
35 | 35 | ||
36 | error: string = null; | 36 | error: string = null |
37 | form: FormGroup; | 37 | form: FormGroup |
38 | formErrors = { | 38 | formErrors = { |
39 | name: '', | 39 | name: '', |
40 | category: '', | 40 | category: '', |
41 | licence: '', | 41 | licence: '', |
42 | language: '', | 42 | language: '', |
43 | description: '' | 43 | description: '' |
44 | }; | 44 | } |
45 | validationMessages = { | 45 | validationMessages = { |
46 | name: VIDEO_NAME.MESSAGES, | 46 | name: VIDEO_NAME.MESSAGES, |
47 | category: VIDEO_CATEGORY.MESSAGES, | 47 | category: VIDEO_CATEGORY.MESSAGES, |
48 | licence: VIDEO_LICENCE.MESSAGES, | 48 | licence: VIDEO_LICENCE.MESSAGES, |
49 | language: VIDEO_LANGUAGE.MESSAGES, | 49 | language: VIDEO_LANGUAGE.MESSAGES, |
50 | description: VIDEO_DESCRIPTION.MESSAGES | 50 | description: VIDEO_DESCRIPTION.MESSAGES |
51 | }; | 51 | } |
52 | 52 | ||
53 | // Special error messages | 53 | // Special error messages |
54 | fileError = ''; | 54 | fileError = '' |
55 | 55 | ||
56 | constructor( | 56 | constructor ( |
57 | private authService: AuthService, | 57 | private authService: AuthService, |
58 | private elementRef: ElementRef, | 58 | private elementRef: ElementRef, |
59 | private formBuilder: FormBuilder, | 59 | private formBuilder: FormBuilder, |
@@ -61,18 +61,18 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
61 | private notificationsService: NotificationsService, | 61 | private notificationsService: NotificationsService, |
62 | private videoService: VideoService | 62 | private videoService: VideoService |
63 | ) { | 63 | ) { |
64 | super(); | 64 | super() |
65 | } | 65 | } |
66 | 66 | ||
67 | get filename() { | 67 | get filename () { |
68 | if (this.uploader.queue.length === 0) { | 68 | if (this.uploader.queue.length === 0) { |
69 | return null; | 69 | return null |
70 | } | 70 | } |
71 | 71 | ||
72 | return this.uploader.queue[0].file.name; | 72 | return this.uploader.queue[0].file.name |
73 | } | 73 | } |
74 | 74 | ||
75 | buildForm() { | 75 | buildForm () { |
76 | this.form = this.formBuilder.group({ | 76 | this.form = this.formBuilder.group({ |
77 | name: [ '', VIDEO_NAME.VALIDATORS ], | 77 | name: [ '', VIDEO_NAME.VALIDATORS ], |
78 | nsfw: [ false ], | 78 | nsfw: [ false ], |
@@ -81,115 +81,106 @@ export class VideoAddComponent extends FormReactive implements OnInit { | |||
81 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], | 81 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], |
82 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], | 82 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], |
83 | tags: [ ''] | 83 | tags: [ ''] |
84 | }); | 84 | }) |
85 | 85 | ||
86 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 86 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
87 | } | 87 | } |
88 | 88 | ||
89 | ngOnInit() { | 89 | ngOnInit () { |
90 | this.videoCategories = this.videoService.videoCategories; | 90 | this.videoCategories = this.videoService.videoCategories |
91 | this.videoLicences = this.videoService.videoLicences; | 91 | this.videoLicences = this.videoService.videoLicences |
92 | this.videoLanguages = this.videoService.videoLanguages; | 92 | this.videoLanguages = this.videoService.videoLanguages |
93 | 93 | ||
94 | this.uploader = new FileUploader({ | 94 | this.uploader = new FileUploader({ |
95 | authToken: this.authService.getRequestHeaderValue(), | 95 | authToken: this.authService.getRequestHeaderValue(), |
96 | queueLimit: 1, | 96 | queueLimit: 1, |
97 | url: API_URL + '/api/v1/videos', | 97 | url: API_URL + '/api/v1/videos', |
98 | removeAfterUpload: true | 98 | removeAfterUpload: true |
99 | }); | 99 | }) |
100 | 100 | ||
101 | this.uploader.onBuildItemForm = (item, form) => { | 101 | this.uploader.onBuildItemForm = (item, form) => { |
102 | const name = this.form.value['name']; | 102 | const name = this.form.value['name'] |
103 | const nsfw = this.form.value['nsfw']; | 103 | const nsfw = this.form.value['nsfw'] |
104 | const category = this.form.value['category']; | 104 | const category = this.form.value['category'] |
105 | const licence = this.form.value['licence']; | 105 | const licence = this.form.value['licence'] |
106 | const language = this.form.value['language']; | 106 | const language = this.form.value['language'] |
107 | const description = this.form.value['description']; | 107 | const description = this.form.value['description'] |
108 | const tags = this.form.value['tags']; | 108 | const tags = this.form.value['tags'] |
109 | 109 | ||
110 | form.append('name', name); | 110 | form.append('name', name) |
111 | form.append('category', category); | 111 | form.append('category', category) |
112 | form.append('nsfw', nsfw); | 112 | form.append('nsfw', nsfw) |
113 | form.append('licence', licence); | 113 | form.append('licence', licence) |
114 | 114 | ||
115 | // Language is optional | 115 | // Language is optional |
116 | if (language) { | 116 | if (language) { |
117 | form.append('language', language); | 117 | form.append('language', language) |
118 | } | 118 | } |
119 | 119 | ||
120 | form.append('description', description); | 120 | form.append('description', description) |
121 | 121 | ||
122 | for (let i = 0; i < tags.length; i++) { | 122 | for (let i = 0; i < tags.length; i++) { |
123 | form.append(`tags[${i}]`, tags[i]); | 123 | form.append(`tags[${i}]`, tags[i]) |
124 | } | 124 | } |
125 | }; | 125 | } |
126 | 126 | ||
127 | this.buildForm(); | 127 | this.buildForm() |
128 | } | 128 | } |
129 | 129 | ||
130 | checkForm() { | 130 | checkForm () { |
131 | this.forceCheck(); | 131 | this.forceCheck() |
132 | 132 | ||
133 | if (this.filename === null) { | 133 | if (this.filename === null) { |
134 | this.fileError = 'You did not add a file.'; | 134 | this.fileError = 'You did not add a file.' |
135 | } | 135 | } |
136 | 136 | ||
137 | return this.form.valid === true && this.fileError === ''; | 137 | return this.form.valid === true && this.fileError === '' |
138 | } | 138 | } |
139 | 139 | ||
140 | fileChanged() { | 140 | fileChanged () { |
141 | this.fileError = ''; | 141 | this.fileError = '' |
142 | } | 142 | } |
143 | 143 | ||
144 | removeFile() { | 144 | removeFile () { |
145 | this.uploader.clearQueue(); | 145 | this.uploader.clearQueue() |
146 | } | 146 | } |
147 | 147 | ||
148 | upload() { | 148 | upload () { |
149 | if (this.checkForm() === false) { | 149 | if (this.checkForm() === false) { |
150 | return; | 150 | return |
151 | } | 151 | } |
152 | 152 | ||
153 | const item = this.uploader.queue[0]; | 153 | const item = this.uploader.queue[0] |
154 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 | 154 | // TODO: wait for https://github.com/valor-software/ng2-file-upload/pull/242 |
155 | item.alias = 'videofile'; | 155 | item.alias = 'videofile' |
156 | |||
157 | // FIXME: remove | ||
158 | // Run detection change for progress bar | ||
159 | const interval = setInterval(() => { ; }, 250); | ||
160 | 156 | ||
161 | item.onSuccess = () => { | 157 | item.onSuccess = () => { |
162 | clearInterval(interval); | 158 | console.log('Video uploaded.') |
163 | 159 | this.notificationsService.success('Success', 'Video uploaded.') | |
164 | console.log('Video uploaded.'); | ||
165 | this.notificationsService.success('Success', 'Video uploaded.'); | ||
166 | |||
167 | 160 | ||
168 | // Print all the videos once it's finished | 161 | // Print all the videos once it's finished |
169 | this.router.navigate(['/videos/list']); | 162 | this.router.navigate(['/videos/list']) |
170 | }; | 163 | } |
171 | 164 | ||
172 | item.onError = (response: string, status: number) => { | 165 | item.onError = (response: string, status: number) => { |
173 | clearInterval(interval); | ||
174 | |||
175 | // We need to handle manually these cases beceause we use the FileUpload component | 166 | // We need to handle manually these cases beceause we use the FileUpload component |
176 | if (status === 400) { | 167 | if (status === 400) { |
177 | this.error = response; | 168 | this.error = response |
178 | } else if (status === 401) { | 169 | } else if (status === 401) { |
179 | this.error = 'Access token was expired, refreshing token...'; | 170 | this.error = 'Access token was expired, refreshing token...' |
180 | this.authService.refreshAccessToken().subscribe( | 171 | this.authService.refreshAccessToken().subscribe( |
181 | () => { | 172 | () => { |
182 | // Update the uploader request header | 173 | // Update the uploader request header |
183 | this.uploader.authToken = this.authService.getRequestHeaderValue(); | 174 | this.uploader.authToken = this.authService.getRequestHeaderValue() |
184 | this.error += ' access token refreshed. Please retry your request.'; | 175 | this.error += ' access token refreshed. Please retry your request.' |
185 | } | 176 | } |
186 | ); | 177 | ) |
187 | } else { | 178 | } else { |
188 | this.error = 'Unknow error'; | 179 | this.error = 'Unknow error' |
189 | console.error(this.error); | 180 | console.error(this.error) |
190 | } | 181 | } |
191 | }; | 182 | } |
192 | 183 | ||
193 | this.uploader.uploadAll(); | 184 | this.uploader.uploadAll() |
194 | } | 185 | } |
195 | } | 186 | } |
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 933132cc0..9ee7ca6a8 100644 --- a/client/src/app/videos/video-edit/video-update.component.ts +++ b/client/src/app/videos/video-edit/video-update.component.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { Component, ElementRef, OnInit } from '@angular/core'; | 1 | import { Component, ElementRef, OnInit } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | import { ActivatedRoute, Router } from '@angular/router'; | 3 | import { ActivatedRoute, Router } from '@angular/router' |
4 | 4 | ||
5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload'; | 5 | import { FileUploader } from 'ng2-file-upload/ng2-file-upload' |
6 | import { NotificationsService } from 'angular2-notifications'; | 6 | import { NotificationsService } from 'angular2-notifications' |
7 | 7 | ||
8 | import { AuthService } from '../../core'; | 8 | import { AuthService } from '../../core' |
9 | import { | 9 | import { |
10 | FormReactive, | 10 | FormReactive, |
11 | VIDEO_NAME, | 11 | VIDEO_NAME, |
@@ -14,8 +14,8 @@ import { | |||
14 | VIDEO_LANGUAGE, | 14 | VIDEO_LANGUAGE, |
15 | VIDEO_DESCRIPTION, | 15 | VIDEO_DESCRIPTION, |
16 | VIDEO_TAGS | 16 | VIDEO_TAGS |
17 | } from '../../shared'; | 17 | } from '../../shared' |
18 | import { Video, VideoService } from '../shared'; | 18 | import { Video, VideoService } from '../shared' |
19 | 19 | ||
20 | @Component({ | 20 | @Component({ |
21 | selector: 'my-videos-update', | 21 | selector: 'my-videos-update', |
@@ -24,35 +24,35 @@ import { Video, VideoService } from '../shared'; | |||
24 | }) | 24 | }) |
25 | 25 | ||
26 | export class VideoUpdateComponent extends FormReactive implements OnInit { | 26 | export class VideoUpdateComponent extends FormReactive implements OnInit { |
27 | tags: string[] = []; | 27 | tags: string[] = [] |
28 | videoCategories = []; | 28 | videoCategories = [] |
29 | videoLicences = []; | 29 | videoLicences = [] |
30 | videoLanguages = []; | 30 | videoLanguages = [] |
31 | video: Video; | 31 | video: Video |
32 | 32 | ||
33 | tagValidators = VIDEO_TAGS.VALIDATORS; | 33 | tagValidators = VIDEO_TAGS.VALIDATORS |
34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES; | 34 | tagValidatorsMessages = VIDEO_TAGS.MESSAGES |
35 | 35 | ||
36 | error: string = null; | 36 | error: string = null |
37 | form: FormGroup; | 37 | form: FormGroup |
38 | formErrors = { | 38 | formErrors = { |
39 | name: '', | 39 | name: '', |
40 | category: '', | 40 | category: '', |
41 | licence: '', | 41 | licence: '', |
42 | language: '', | 42 | language: '', |
43 | description: '' | 43 | description: '' |
44 | }; | 44 | } |
45 | validationMessages = { | 45 | validationMessages = { |
46 | name: VIDEO_NAME.MESSAGES, | 46 | name: VIDEO_NAME.MESSAGES, |
47 | category: VIDEO_CATEGORY.MESSAGES, | 47 | category: VIDEO_CATEGORY.MESSAGES, |
48 | licence: VIDEO_LICENCE.MESSAGES, | 48 | licence: VIDEO_LICENCE.MESSAGES, |
49 | language: VIDEO_LANGUAGE.MESSAGES, | 49 | language: VIDEO_LANGUAGE.MESSAGES, |
50 | description: VIDEO_DESCRIPTION.MESSAGES | 50 | description: VIDEO_DESCRIPTION.MESSAGES |
51 | }; | 51 | } |
52 | 52 | ||
53 | fileError = ''; | 53 | fileError = '' |
54 | 54 | ||
55 | constructor( | 55 | constructor ( |
56 | private authService: AuthService, | 56 | private authService: AuthService, |
57 | private elementRef: ElementRef, | 57 | private elementRef: ElementRef, |
58 | private formBuilder: FormBuilder, | 58 | private formBuilder: FormBuilder, |
@@ -61,10 +61,10 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
61 | private notificationsService: NotificationsService, | 61 | private notificationsService: NotificationsService, |
62 | private videoService: VideoService | 62 | private videoService: VideoService |
63 | ) { | 63 | ) { |
64 | super(); | 64 | super() |
65 | } | 65 | } |
66 | 66 | ||
67 | buildForm() { | 67 | buildForm () { |
68 | this.form = this.formBuilder.group({ | 68 | this.form = this.formBuilder.group({ |
69 | name: [ '', VIDEO_NAME.VALIDATORS ], | 69 | name: [ '', VIDEO_NAME.VALIDATORS ], |
70 | nsfw: [ false ], | 70 | nsfw: [ false ], |
@@ -73,60 +73,63 @@ export class VideoUpdateComponent extends FormReactive implements OnInit { | |||
73 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], | 73 | language: [ '', VIDEO_LANGUAGE.VALIDATORS ], |
74 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], | 74 | description: [ '', VIDEO_DESCRIPTION.VALIDATORS ], |
75 | tags: [ '' ] | 75 | tags: [ '' ] |
76 | }); | 76 | }) |
77 | 77 | ||
78 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 78 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
79 | } | 79 | } |
80 | 80 | ||
81 | ngOnInit() { | 81 | ngOnInit () { |
82 | this.buildForm(); | 82 | this.buildForm() |
83 | 83 | ||
84 | this.videoCategories = this.videoService.videoCategories; | 84 | this.videoCategories = this.videoService.videoCategories |
85 | this.videoLicences = this.videoService.videoLicences; | 85 | this.videoLicences = this.videoService.videoLicences |
86 | this.videoLanguages = this.videoService.videoLanguages; | 86 | this.videoLanguages = this.videoService.videoLanguages |
87 | 87 | ||
88 | const id = this.route.snapshot.params['id']; | 88 | const id = this.route.snapshot.params['id'] |
89 | this.videoService.getVideo(id) | 89 | this.videoService.getVideo(id) |
90 | .subscribe( | 90 | .subscribe( |
91 | video => { | 91 | video => { |
92 | this.video = video; | 92 | this.video = video |
93 | 93 | ||
94 | this.hydrateFormFromVideo(); | 94 | this.hydrateFormFromVideo() |
95 | }, | 95 | }, |
96 | 96 | ||
97 | err => this.error = 'Cannot fetch video.' | 97 | err => { |
98 | ); | 98 | console.error(err) |
99 | this.error = 'Cannot fetch video.' | ||
100 | } | ||
101 | ) | ||
99 | } | 102 | } |
100 | 103 | ||
101 | checkForm() { | 104 | checkForm () { |
102 | this.forceCheck(); | 105 | this.forceCheck() |
103 | 106 | ||
104 | return this.form.valid; | 107 | return this.form.valid |
105 | } | 108 | } |
106 | 109 | ||
107 | update() { | 110 | update () { |
108 | if (this.checkForm() === false) { | 111 | if (this.checkForm() === false) { |
109 | return; | 112 | return |
110 | } | 113 | } |
111 | 114 | ||
112 | this.video.patch(this.form.value); | 115 | this.video.patch(this.form.value) |
113 | 116 | ||
114 | this.videoService.updateVideo(this.video) | 117 | this.videoService.updateVideo(this.video) |
115 | .subscribe( | 118 | .subscribe( |
116 | () => { | 119 | () => { |
117 | this.notificationsService.success('Success', 'Video updated.'); | 120 | this.notificationsService.success('Success', 'Video updated.') |
118 | this.router.navigate([ '/videos/watch', this.video.id ]); | 121 | this.router.navigate([ '/videos/watch', this.video.id ]) |
119 | }, | 122 | }, |
120 | 123 | ||
121 | err => { | 124 | err => { |
122 | this.error = 'Cannot update the video.'; | 125 | this.error = 'Cannot update the video.' |
123 | console.error(err); | 126 | console.error(err) |
124 | } | 127 | } |
125 | ); | 128 | ) |
126 | 129 | ||
127 | } | 130 | } |
128 | 131 | ||
129 | private hydrateFormFromVideo() { | 132 | private hydrateFormFromVideo () { |
130 | this.form.patchValue(this.video.toJSON()); | 133 | this.form.patchValue(this.video.toJSON()) |
131 | } | 134 | } |
132 | } | 135 | } |
diff --git a/client/src/app/videos/video-list/index.ts b/client/src/app/videos/video-list/index.ts index 71d3b78e6..a490e6bb5 100644 --- a/client/src/app/videos/video-list/index.ts +++ b/client/src/app/videos/video-list/index.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | export * from './loader.component'; | 1 | export * from './loader.component' |
2 | export * from './video-list.component'; | 2 | export * from './video-list.component' |
3 | export * from './video-miniature.component'; | 3 | export * from './video-miniature.component' |
4 | export * from './video-sort.component'; | 4 | export * from './video-sort.component' |
diff --git a/client/src/app/videos/video-list/loader.component.ts b/client/src/app/videos/video-list/loader.component.ts index e72d2f3f3..e5780e0fa 100644 --- a/client/src/app/videos/video-list/loader.component.ts +++ b/client/src/app/videos/video-list/loader.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component, Input } from '@angular/core'; | 1 | import { Component, Input } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | selector: 'my-loader', | 4 | selector: 'my-loader', |
@@ -7,5 +7,5 @@ import { Component, Input } from '@angular/core'; | |||
7 | }) | 7 | }) |
8 | 8 | ||
9 | export class LoaderComponent { | 9 | export class LoaderComponent { |
10 | @Input() loading: boolean; | 10 | @Input() loading: boolean |
11 | } | 11 | } |
diff --git a/client/src/app/videos/video-list/video-list.component.html b/client/src/app/videos/video-list/video-list.component.html index f80592279..680fba3f5 100644 --- a/client/src/app/videos/video-list/video-list.component.html +++ b/client/src/app/videos/video-list/video-list.component.html | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | <my-video-miniature | 18 | <my-video-miniature |
19 | class="ng-animate" | 19 | class="ng-animate" |
20 | *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort" (removed)="onRemoved(video)" | 20 | *ngFor="let video of videos" [video]="video" [user]="user" [currentSort]="sort" |
21 | > | 21 | > |
22 | </my-video-miniature> | 22 | </my-video-miniature> |
23 | </div> | 23 | </div> |
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 16a40bdc4..0c36e5b08 100644 --- a/client/src/app/videos/video-list/video-list.component.ts +++ b/client/src/app/videos/video-list/video-list.component.ts | |||
@@ -1,17 +1,17 @@ | |||
1 | import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core'; | 1 | import { ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router'; | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { BehaviorSubject } from 'rxjs/BehaviorSubject'; | 3 | import { BehaviorSubject } from 'rxjs/BehaviorSubject' |
4 | 4 | ||
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { | 7 | import { |
8 | SortField, | 8 | SortField, |
9 | Video, | 9 | Video, |
10 | VideoService | 10 | VideoService |
11 | } from '../shared'; | 11 | } from '../shared' |
12 | import { AuthService, AuthUser } from '../../core'; | 12 | import { AuthService, AuthUser } from '../../core' |
13 | import { RestPagination, Search, SearchField } from '../../shared'; | 13 | import { RestPagination, Search, SearchField } from '../../shared' |
14 | import { SearchService } from '../../shared'; | 14 | import { SearchService } from '../../shared' |
15 | 15 | ||
16 | @Component({ | 16 | @Component({ |
17 | selector: 'my-videos-list', | 17 | selector: 'my-videos-list', |
@@ -19,21 +19,21 @@ import { SearchService } from '../../shared'; | |||
19 | templateUrl: './video-list.component.html' | 19 | templateUrl: './video-list.component.html' |
20 | }) | 20 | }) |
21 | export class VideoListComponent implements OnInit, OnDestroy { | 21 | export class VideoListComponent implements OnInit, OnDestroy { |
22 | loading: BehaviorSubject<boolean> = new BehaviorSubject(false); | 22 | loading: BehaviorSubject<boolean> = new BehaviorSubject(false) |
23 | pagination: RestPagination = { | 23 | pagination: RestPagination = { |
24 | currentPage: 1, | 24 | currentPage: 1, |
25 | itemsPerPage: 25, | 25 | itemsPerPage: 25, |
26 | totalItems: null | 26 | totalItems: null |
27 | }; | 27 | } |
28 | sort: SortField; | 28 | sort: SortField |
29 | user: AuthUser = null; | 29 | user: AuthUser = null |
30 | videos: Video[] = []; | 30 | videos: Video[] = [] |
31 | 31 | ||
32 | private search: Search; | 32 | private search: Search |
33 | private subActivatedRoute: any; | 33 | private subActivatedRoute: any |
34 | private subSearch: any; | 34 | private subSearch: any |
35 | 35 | ||
36 | constructor( | 36 | constructor ( |
37 | private notificationsService: NotificationsService, | 37 | private notificationsService: NotificationsService, |
38 | private authService: AuthService, | 38 | private authService: AuthService, |
39 | private changeDetector: ChangeDetectorRef, | 39 | private changeDetector: ChangeDetectorRef, |
@@ -43,114 +43,114 @@ export class VideoListComponent implements OnInit, OnDestroy { | |||
43 | private searchService: SearchService | 43 | private searchService: SearchService |
44 | ) {} | 44 | ) {} |
45 | 45 | ||
46 | ngOnInit() { | 46 | ngOnInit () { |
47 | if (this.authService.isLoggedIn()) { | 47 | if (this.authService.isLoggedIn()) { |
48 | this.user = AuthUser.load(); | 48 | this.user = AuthUser.load() |
49 | } | 49 | } |
50 | 50 | ||
51 | // Subscribe to route changes | 51 | // Subscribe to route changes |
52 | this.subActivatedRoute = this.route.params.subscribe(routeParams => { | 52 | this.subActivatedRoute = this.route.params.subscribe(routeParams => { |
53 | this.loadRouteParams(routeParams); | 53 | this.loadRouteParams(routeParams) |
54 | 54 | ||
55 | // Update the search service component | 55 | // Update the search service component |
56 | this.searchService.updateSearch.next(this.search); | 56 | this.searchService.updateSearch.next(this.search) |
57 | this.getVideos(); | 57 | this.getVideos() |
58 | }); | 58 | }) |
59 | 59 | ||
60 | // Subscribe to search changes | 60 | // Subscribe to search changes |
61 | this.subSearch = this.searchService.searchUpdated.subscribe(search => { | 61 | this.subSearch = this.searchService.searchUpdated.subscribe(search => { |
62 | this.search = search; | 62 | this.search = search |
63 | // Reset pagination | 63 | // Reset pagination |
64 | this.pagination.currentPage = 1; | 64 | this.pagination.currentPage = 1 |
65 | 65 | ||
66 | this.navigateToNewParams(); | 66 | this.navigateToNewParams() |
67 | }); | 67 | }) |
68 | } | 68 | } |
69 | 69 | ||
70 | ngOnDestroy() { | 70 | ngOnDestroy () { |
71 | this.subActivatedRoute.unsubscribe(); | 71 | this.subActivatedRoute.unsubscribe() |
72 | this.subSearch.unsubscribe(); | 72 | this.subSearch.unsubscribe() |
73 | } | 73 | } |
74 | 74 | ||
75 | getVideos() { | 75 | getVideos () { |
76 | this.loading.next(true); | 76 | this.loading.next(true) |
77 | this.videos = []; | 77 | this.videos = [] |
78 | 78 | ||
79 | let observable = null; | 79 | let observable = null |
80 | if (this.search.value) { | 80 | if (this.search.value) { |
81 | observable = this.videoService.searchVideos(this.search, this.pagination, this.sort); | 81 | observable = this.videoService.searchVideos(this.search, this.pagination, this.sort) |
82 | } else { | 82 | } else { |
83 | observable = this.videoService.getVideos(this.pagination, this.sort); | 83 | observable = this.videoService.getVideos(this.pagination, this.sort) |
84 | } | 84 | } |
85 | 85 | ||
86 | observable.subscribe( | 86 | observable.subscribe( |
87 | ({ videos, totalVideos }) => { | 87 | ({ videos, totalVideos }) => { |
88 | this.videos = videos; | 88 | this.videos = videos |
89 | this.pagination.totalItems = totalVideos; | 89 | this.pagination.totalItems = totalVideos |
90 | 90 | ||
91 | this.loading.next(false); | 91 | this.loading.next(false) |
92 | }, | 92 | }, |
93 | error => this.notificationsService.error('Error', error.text) | 93 | error => this.notificationsService.error('Error', error.text) |
94 | ); | 94 | ) |
95 | } | 95 | } |
96 | 96 | ||
97 | isThereNoVideo() { | 97 | isThereNoVideo () { |
98 | return !this.loading.getValue() && this.videos.length === 0; | 98 | return !this.loading.getValue() && this.videos.length === 0 |
99 | } | 99 | } |
100 | 100 | ||
101 | onPageChanged(event: any) { | 101 | onPageChanged (event: any) { |
102 | // Be sure the current page is set | 102 | // Be sure the current page is set |
103 | this.pagination.currentPage = event.page; | 103 | this.pagination.currentPage = event.page |
104 | 104 | ||
105 | this.navigateToNewParams(); | 105 | this.navigateToNewParams() |
106 | } | 106 | } |
107 | 107 | ||
108 | onSort(sort: SortField) { | 108 | onSort (sort: SortField) { |
109 | this.sort = sort; | 109 | this.sort = sort |
110 | 110 | ||
111 | this.navigateToNewParams(); | 111 | this.navigateToNewParams() |
112 | } | 112 | } |
113 | 113 | ||
114 | private buildRouteParams() { | 114 | private buildRouteParams () { |
115 | // There is always a sort and a current page | 115 | // There is always a sort and a current page |
116 | const params: any = { | 116 | const params: any = { |
117 | sort: this.sort, | 117 | sort: this.sort, |
118 | page: this.pagination.currentPage | 118 | page: this.pagination.currentPage |
119 | }; | 119 | } |
120 | 120 | ||
121 | // Maybe there is a search | 121 | // Maybe there is a search |
122 | if (this.search.value) { | 122 | if (this.search.value) { |
123 | params.field = this.search.field; | 123 | params.field = this.search.field |
124 | params.search = this.search.value; | 124 | params.search = this.search.value |
125 | } | 125 | } |
126 | 126 | ||
127 | return params; | 127 | return params |
128 | } | 128 | } |
129 | 129 | ||
130 | private loadRouteParams(routeParams) { | 130 | private loadRouteParams (routeParams) { |
131 | if (routeParams['search'] !== undefined) { | 131 | if (routeParams['search'] !== undefined) { |
132 | this.search = { | 132 | this.search = { |
133 | value: routeParams['search'], | 133 | value: routeParams['search'], |
134 | field: <SearchField>routeParams['field'] | 134 | field: routeParams['field'] as SearchField |
135 | }; | 135 | } |
136 | } else { | 136 | } else { |
137 | this.search = { | 137 | this.search = { |
138 | value: '', | 138 | value: '', |
139 | field: 'name' | 139 | field: 'name' |
140 | }; | 140 | } |
141 | } | 141 | } |
142 | 142 | ||
143 | this.sort = <SortField>routeParams['sort'] || '-createdAt'; | 143 | this.sort = routeParams['sort'] as SortField || '-createdAt' |
144 | 144 | ||
145 | if (routeParams['page'] !== undefined) { | 145 | if (routeParams['page'] !== undefined) { |
146 | this.pagination.currentPage = parseInt(routeParams['page']); | 146 | this.pagination.currentPage = parseInt(routeParams['page'], 10) |
147 | } else { | 147 | } else { |
148 | this.pagination.currentPage = 1; | 148 | this.pagination.currentPage = 1 |
149 | } | 149 | } |
150 | } | 150 | } |
151 | 151 | ||
152 | private navigateToNewParams() { | 152 | private navigateToNewParams () { |
153 | const routeParams = this.buildRouteParams(); | 153 | const routeParams = this.buildRouteParams() |
154 | this.router.navigate(['/videos/list', routeParams]); | 154 | this.router.navigate(['/videos/list', routeParams]) |
155 | } | 155 | } |
156 | } | 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 28601ca7f..1cfeacf36 100644 --- a/client/src/app/videos/video-list/video-miniature.component.ts +++ b/client/src/app/videos/video-list/video-miniature.component.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Component, Input, Output, EventEmitter } from '@angular/core'; | 1 | import { Component, Input, Output, EventEmitter } from '@angular/core' |
2 | 2 | ||
3 | import { NotificationsService } from 'angular2-notifications'; | 3 | import { NotificationsService } from 'angular2-notifications' |
4 | 4 | ||
5 | import { ConfirmService, ConfigService } from '../../core'; | 5 | import { ConfirmService, ConfigService } from '../../core' |
6 | import { SortField, Video, VideoService } from '../shared'; | 6 | import { SortField, Video, VideoService } from '../shared' |
7 | import { User } from '../../shared'; | 7 | import { User } from '../../shared' |
8 | 8 | ||
9 | @Component({ | 9 | @Component({ |
10 | selector: 'my-video-miniature', | 10 | selector: 'my-video-miniature', |
@@ -13,25 +13,26 @@ import { User } from '../../shared'; | |||
13 | }) | 13 | }) |
14 | 14 | ||
15 | export class VideoMiniatureComponent { | 15 | export class VideoMiniatureComponent { |
16 | @Input() currentSort: SortField; | 16 | @Input() currentSort: SortField |
17 | @Input() user: User; | 17 | @Input() user: User |
18 | @Input() video: Video; | 18 | @Input() video: Video |
19 | 19 | ||
20 | constructor( | 20 | constructor ( |
21 | private notificationsService: NotificationsService, | 21 | private notificationsService: NotificationsService, |
22 | private confirmService: ConfirmService, | 22 | private confirmService: ConfirmService, |
23 | private configService: ConfigService, | 23 | private configService: ConfigService, |
24 | private videoService: VideoService | 24 | private videoService: VideoService |
25 | ) {} | 25 | ) {} |
26 | 26 | ||
27 | getVideoName() { | 27 | getVideoName () { |
28 | if (this.isVideoNSFWForThisUser()) | 28 | if (this.isVideoNSFWForThisUser()) { |
29 | return 'NSFW'; | 29 | return 'NSFW' |
30 | } | ||
30 | 31 | ||
31 | return this.video.name; | 32 | return this.video.name |
32 | } | 33 | } |
33 | 34 | ||
34 | isVideoNSFWForThisUser() { | 35 | isVideoNSFWForThisUser () { |
35 | return this.video.isVideoNSFWForUser(this.user); | 36 | return this.video.isVideoNSFWForUser(this.user) |
36 | } | 37 | } |
37 | } | 38 | } |
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 20979a395..64916bf16 100644 --- a/client/src/app/videos/video-list/video-sort.component.ts +++ b/client/src/app/videos/video-list/video-sort.component.ts | |||
@@ -1,6 +1,6 @@ | |||
1 | import { Component, EventEmitter, Input, Output } from '@angular/core'; | 1 | import { Component, EventEmitter, Input, Output } from '@angular/core' |
2 | 2 | ||
3 | import { SortField } from '../shared'; | 3 | import { SortField } from '../shared' |
4 | 4 | ||
5 | @Component({ | 5 | @Component({ |
6 | selector: 'my-video-sort', | 6 | selector: 'my-video-sort', |
@@ -8,9 +8,9 @@ import { SortField } from '../shared'; | |||
8 | }) | 8 | }) |
9 | 9 | ||
10 | export class VideoSortComponent { | 10 | export class VideoSortComponent { |
11 | @Output() sort = new EventEmitter<any>(); | 11 | @Output() sort = new EventEmitter<any>() |
12 | 12 | ||
13 | @Input() currentSort: SortField; | 13 | @Input() currentSort: SortField |
14 | 14 | ||
15 | sortChoices: { [ P in SortField ]: string } = { | 15 | sortChoices: { [ P in SortField ]: string } = { |
16 | 'name': 'Name - Asc', | 16 | 'name': 'Name - Asc', |
@@ -23,17 +23,17 @@ export class VideoSortComponent { | |||
23 | '-views': 'Views - Desc', | 23 | '-views': 'Views - Desc', |
24 | 'likes': 'Likes - Asc', | 24 | 'likes': 'Likes - Asc', |
25 | '-likes': 'Likes - Desc' | 25 | '-likes': 'Likes - Desc' |
26 | }; | 26 | } |
27 | 27 | ||
28 | get choiceKeys() { | 28 | get choiceKeys () { |
29 | return Object.keys(this.sortChoices); | 29 | return Object.keys(this.sortChoices) |
30 | } | 30 | } |
31 | 31 | ||
32 | getStringChoice(choiceKey: SortField) { | 32 | getStringChoice (choiceKey: SortField) { |
33 | return this.sortChoices[choiceKey]; | 33 | return this.sortChoices[choiceKey] |
34 | } | 34 | } |
35 | 35 | ||
36 | onSortChange() { | 36 | onSortChange () { |
37 | this.sort.emit(this.currentSort); | 37 | this.sort.emit(this.currentSort) |
38 | } | 38 | } |
39 | } | 39 | } |
diff --git a/client/src/app/videos/video-watch/index.ts b/client/src/app/videos/video-watch/index.ts index ed0ed2fc0..6e35262d3 100644 --- a/client/src/app/videos/video-watch/index.ts +++ b/client/src/app/videos/video-watch/index.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | export * from './video-magnet.component'; | 1 | export * from './video-magnet.component' |
2 | export * from './video-share.component'; | 2 | export * from './video-share.component' |
3 | export * from './video-report.component'; | 3 | export * from './video-report.component' |
4 | export * from './video-watch.component'; | 4 | export * from './video-watch.component' |
5 | export * from './webtorrent.service'; | 5 | export * from './webtorrent.service' |
diff --git a/client/src/app/videos/video-watch/video-magnet.component.ts b/client/src/app/videos/video-watch/video-magnet.component.ts index 894fa45fc..f9432e92c 100644 --- a/client/src/app/videos/video-watch/video-magnet.component.ts +++ b/client/src/app/videos/video-watch/video-magnet.component.ts | |||
@@ -1,27 +1,27 @@ | |||
1 | import { Component, Input, ViewChild } from '@angular/core'; | 1 | import { Component, Input, ViewChild } from '@angular/core' |
2 | 2 | ||
3 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 3 | import { ModalDirective } from 'ngx-bootstrap/modal' |
4 | 4 | ||
5 | import { Video } from '../shared'; | 5 | import { Video } from '../shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-video-magnet', | 8 | selector: 'my-video-magnet', |
9 | templateUrl: './video-magnet.component.html' | 9 | templateUrl: './video-magnet.component.html' |
10 | }) | 10 | }) |
11 | export class VideoMagnetComponent { | 11 | export class VideoMagnetComponent { |
12 | @Input() video: Video = null; | 12 | @Input() video: Video = null |
13 | 13 | ||
14 | @ViewChild('modal') modal: ModalDirective; | 14 | @ViewChild('modal') modal: ModalDirective |
15 | 15 | ||
16 | constructor() { | 16 | constructor () { |
17 | // empty | 17 | // empty |
18 | } | 18 | } |
19 | 19 | ||
20 | show() { | 20 | show () { |
21 | this.modal.show(); | 21 | this.modal.show() |
22 | } | 22 | } |
23 | 23 | ||
24 | hide() { | 24 | hide () { |
25 | this.modal.hide(); | 25 | this.modal.hide() |
26 | } | 26 | } |
27 | } | 27 | } |
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 528005b84..61213cd68 100644 --- a/client/src/app/videos/video-watch/video-report.component.ts +++ b/client/src/app/videos/video-watch/video-report.component.ts | |||
@@ -1,69 +1,69 @@ | |||
1 | import { Component, Input, OnInit, ViewChild } from '@angular/core'; | 1 | import { Component, Input, OnInit, ViewChild } from '@angular/core' |
2 | import { FormBuilder, FormGroup } from '@angular/forms'; | 2 | import { FormBuilder, FormGroup } from '@angular/forms' |
3 | 3 | ||
4 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 4 | import { ModalDirective } from 'ngx-bootstrap/modal' |
5 | import { NotificationsService } from 'angular2-notifications'; | 5 | import { NotificationsService } from 'angular2-notifications' |
6 | 6 | ||
7 | import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared'; | 7 | import { FormReactive, VideoAbuseService, VIDEO_ABUSE_REASON } from '../../shared' |
8 | import { Video, VideoService } from '../shared'; | 8 | import { Video, VideoService } from '../shared' |
9 | 9 | ||
10 | @Component({ | 10 | @Component({ |
11 | selector: 'my-video-report', | 11 | selector: 'my-video-report', |
12 | templateUrl: './video-report.component.html' | 12 | templateUrl: './video-report.component.html' |
13 | }) | 13 | }) |
14 | export class VideoReportComponent extends FormReactive implements OnInit { | 14 | export class VideoReportComponent extends FormReactive implements OnInit { |
15 | @Input() video: Video = null; | 15 | @Input() video: Video = null |
16 | 16 | ||
17 | @ViewChild('modal') modal: ModalDirective; | 17 | @ViewChild('modal') modal: ModalDirective |
18 | 18 | ||
19 | error: string = null; | 19 | error: string = null |
20 | form: FormGroup; | 20 | form: FormGroup |
21 | formErrors = { | 21 | formErrors = { |
22 | reason: '' | 22 | reason: '' |
23 | }; | 23 | } |
24 | validationMessages = { | 24 | validationMessages = { |
25 | reason: VIDEO_ABUSE_REASON.MESSAGES | 25 | reason: VIDEO_ABUSE_REASON.MESSAGES |
26 | }; | 26 | } |
27 | 27 | ||
28 | constructor( | 28 | constructor ( |
29 | private formBuilder: FormBuilder, | 29 | private formBuilder: FormBuilder, |
30 | private videoAbuseService: VideoAbuseService, | 30 | private videoAbuseService: VideoAbuseService, |
31 | private notificationsService: NotificationsService | 31 | private notificationsService: NotificationsService |
32 | ) { | 32 | ) { |
33 | super(); | 33 | super() |
34 | } | 34 | } |
35 | 35 | ||
36 | ngOnInit() { | 36 | ngOnInit () { |
37 | this.buildForm(); | 37 | this.buildForm() |
38 | } | 38 | } |
39 | 39 | ||
40 | buildForm() { | 40 | buildForm () { |
41 | this.form = this.formBuilder.group({ | 41 | this.form = this.formBuilder.group({ |
42 | reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] | 42 | reason: [ '', VIDEO_ABUSE_REASON.VALIDATORS ] |
43 | }); | 43 | }) |
44 | 44 | ||
45 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)); | 45 | this.form.valueChanges.subscribe(data => this.onValueChanged(data)) |
46 | } | 46 | } |
47 | 47 | ||
48 | show() { | 48 | show () { |
49 | this.modal.show(); | 49 | this.modal.show() |
50 | } | 50 | } |
51 | 51 | ||
52 | hide() { | 52 | hide () { |
53 | this.modal.hide(); | 53 | this.modal.hide() |
54 | } | 54 | } |
55 | 55 | ||
56 | report() { | 56 | report () { |
57 | const reason = this.form.value['reason']; | 57 | const reason = this.form.value['reason'] |
58 | 58 | ||
59 | this.videoAbuseService.reportVideo(this.video.id, reason) | 59 | this.videoAbuseService.reportVideo(this.video.id, reason) |
60 | .subscribe( | 60 | .subscribe( |
61 | () => { | 61 | () => { |
62 | this.notificationsService.success('Success', 'Video reported.'); | 62 | this.notificationsService.success('Success', 'Video reported.') |
63 | this.hide(); | 63 | this.hide() |
64 | }, | 64 | }, |
65 | 65 | ||
66 | err => this.notificationsService.error('Error', err.text) | 66 | err => this.notificationsService.error('Error', err.text) |
67 | ); | 67 | ) |
68 | } | 68 | } |
69 | } | 69 | } |
diff --git a/client/src/app/videos/video-watch/video-share.component.ts b/client/src/app/videos/video-watch/video-share.component.ts index aa921afc2..bbd25f5ef 100644 --- a/client/src/app/videos/video-watch/video-share.component.ts +++ b/client/src/app/videos/video-watch/video-share.component.ts | |||
@@ -1,42 +1,42 @@ | |||
1 | import { Component, Input, ViewChild } from '@angular/core'; | 1 | import { Component, Input, ViewChild } from '@angular/core' |
2 | 2 | ||
3 | import { ModalDirective } from 'ngx-bootstrap/modal'; | 3 | import { ModalDirective } from 'ngx-bootstrap/modal' |
4 | 4 | ||
5 | import { Video } from '../shared'; | 5 | import { Video } from '../shared' |
6 | 6 | ||
7 | @Component({ | 7 | @Component({ |
8 | selector: 'my-video-share', | 8 | selector: 'my-video-share', |
9 | templateUrl: './video-share.component.html' | 9 | templateUrl: './video-share.component.html' |
10 | }) | 10 | }) |
11 | export class VideoShareComponent { | 11 | export class VideoShareComponent { |
12 | @Input() video: Video = null; | 12 | @Input() video: Video = null |
13 | 13 | ||
14 | @ViewChild('modal') modal: ModalDirective; | 14 | @ViewChild('modal') modal: ModalDirective |
15 | 15 | ||
16 | constructor() { | 16 | constructor () { |
17 | // empty | 17 | // empty |
18 | } | 18 | } |
19 | 19 | ||
20 | show() { | 20 | show () { |
21 | this.modal.show(); | 21 | this.modal.show() |
22 | } | 22 | } |
23 | 23 | ||
24 | hide() { | 24 | hide () { |
25 | this.modal.hide(); | 25 | this.modal.hide() |
26 | } | 26 | } |
27 | 27 | ||
28 | getVideoIframeCode() { | 28 | getVideoIframeCode () { |
29 | return '<iframe width="560" height="315" ' + | 29 | return '<iframe width="560" height="315" ' + |
30 | 'src="' + window.location.origin + '/videos/embed/' + this.video.id + '" ' + | 30 | 'src="' + window.location.origin + '/videos/embed/' + this.video.id + '" ' + |
31 | 'frameborder="0" allowfullscreen>' + | 31 | 'frameborder="0" allowfullscreen>' + |
32 | '</iframe>'; | 32 | '</iframe>' |
33 | } | 33 | } |
34 | 34 | ||
35 | getVideoUrl() { | 35 | getVideoUrl () { |
36 | return window.location.href; | 36 | return window.location.href |
37 | } | 37 | } |
38 | 38 | ||
39 | notSecure() { | 39 | notSecure () { |
40 | return window.location.protocol === 'http:'; | 40 | return window.location.protocol === 'http:' |
41 | } | 41 | } |
42 | } | 42 | } |
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 bcfebf2fd..4a547f7e4 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,18 @@ | |||
1 | import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core'; | 1 | import { Component, ElementRef, NgZone, OnDestroy, OnInit, ViewChild } from '@angular/core' |
2 | import { ActivatedRoute, Router } from '@angular/router'; | 2 | import { ActivatedRoute, Router } from '@angular/router' |
3 | import { Observable } from 'rxjs/Observable'; | 3 | import { Observable } from 'rxjs/Observable' |
4 | import { Subscription } from 'rxjs/Subscription'; | 4 | import { Subscription } from 'rxjs/Subscription' |
5 | 5 | ||
6 | import * as videojs from 'video.js'; | 6 | import * as videojs from 'video.js' |
7 | import { MetaService } from '@nglibs/meta'; | 7 | import { MetaService } from '@nglibs/meta' |
8 | import { NotificationsService } from 'angular2-notifications'; | 8 | import { NotificationsService } from 'angular2-notifications' |
9 | 9 | ||
10 | import { AuthService, ConfirmService } from '../../core'; | 10 | import { AuthService, ConfirmService } from '../../core' |
11 | import { VideoMagnetComponent } from './video-magnet.component'; | 11 | import { VideoMagnetComponent } from './video-magnet.component' |
12 | import { VideoShareComponent } from './video-share.component'; | 12 | import { VideoShareComponent } from './video-share.component' |
13 | import { VideoReportComponent } from './video-report.component'; | 13 | import { VideoReportComponent } from './video-report.component' |
14 | import { RateType, Video, VideoService } from '../shared'; | 14 | import { RateType, Video, VideoService } from '../shared' |
15 | import { WebTorrentService } from './webtorrent.service'; | 15 | import { WebTorrentService } from './webtorrent.service' |
16 | 16 | ||
17 | @Component({ | 17 | @Component({ |
18 | selector: 'my-video-watch', | 18 | selector: 'my-video-watch', |
@@ -21,30 +21,30 @@ import { WebTorrentService } from './webtorrent.service'; | |||
21 | }) | 21 | }) |
22 | 22 | ||
23 | export class VideoWatchComponent implements OnInit, OnDestroy { | 23 | export class VideoWatchComponent implements OnInit, OnDestroy { |
24 | private static LOADTIME_TOO_LONG = 20000; | 24 | private static LOADTIME_TOO_LONG = 20000 |
25 | 25 | ||
26 | @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent; | 26 | @ViewChild('videoMagnetModal') videoMagnetModal: VideoMagnetComponent |
27 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent; | 27 | @ViewChild('videoShareModal') videoShareModal: VideoShareComponent |
28 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent; | 28 | @ViewChild('videoReportModal') videoReportModal: VideoReportComponent |
29 | 29 | ||
30 | downloadSpeed: number; | 30 | downloadSpeed: number |
31 | error = false; | 31 | error = false |
32 | loading = false; | 32 | loading = false |
33 | numPeers: number; | 33 | numPeers: number |
34 | player: videojs.Player; | 34 | player: videojs.Player |
35 | playerElement: Element; | 35 | playerElement: Element |
36 | uploadSpeed: number; | 36 | uploadSpeed: number |
37 | userRating: RateType = null; | 37 | userRating: RateType = null |
38 | video: Video = null; | 38 | video: Video = null |
39 | videoNotFound = false; | 39 | videoNotFound = false |
40 | 40 | ||
41 | private errorTimer: number; | 41 | private errorTimer: number |
42 | private paramsSub: Subscription; | 42 | private paramsSub: Subscription |
43 | private errorsSub: Subscription; | 43 | private errorsSub: Subscription |
44 | private warningsSub: Subscription; | 44 | private warningsSub: Subscription |
45 | private torrentInfosInterval: number; | 45 | private torrentInfosInterval: number |
46 | 46 | ||
47 | constructor( | 47 | constructor ( |
48 | private elementRef: ElementRef, | 48 | private elementRef: ElementRef, |
49 | private ngZone: NgZone, | 49 | private ngZone: NgZone, |
50 | private route: ActivatedRoute, | 50 | private route: ActivatedRoute, |
@@ -57,278 +57,281 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
57 | private notificationsService: NotificationsService | 57 | private notificationsService: NotificationsService |
58 | ) {} | 58 | ) {} |
59 | 59 | ||
60 | ngOnInit() { | 60 | ngOnInit () { |
61 | this.paramsSub = this.route.params.subscribe(routeParams => { | 61 | this.paramsSub = this.route.params.subscribe(routeParams => { |
62 | let id = routeParams['id']; | 62 | let id = routeParams['id'] |
63 | this.videoService.getVideo(id).subscribe( | 63 | this.videoService.getVideo(id).subscribe( |
64 | video => this.onVideoFetched(video), | 64 | video => this.onVideoFetched(video), |
65 | 65 | ||
66 | error => this.videoNotFound = true | 66 | error => { |
67 | ); | 67 | console.error(error) |
68 | }); | 68 | this.videoNotFound = true |
69 | } | ||
70 | ) | ||
71 | }) | ||
69 | 72 | ||
70 | this.playerElement = this.elementRef.nativeElement.querySelector('#video-container'); | 73 | this.playerElement = this.elementRef.nativeElement.querySelector('#video-container') |
71 | 74 | ||
72 | const videojsOptions = { | 75 | const videojsOptions = { |
73 | controls: true, | 76 | controls: true, |
74 | autoplay: false | 77 | autoplay: false |
75 | }; | 78 | } |
76 | 79 | ||
77 | const self = this; | 80 | const self = this |
78 | videojs(this.playerElement, videojsOptions, function () { | 81 | videojs(this.playerElement, videojsOptions, function () { |
79 | self.player = this; | 82 | self.player = this |
80 | }); | 83 | }) |
81 | 84 | ||
82 | this.errorsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.error('Error', err.message)); | 85 | this.errorsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.error('Error', err.message)) |
83 | this.warningsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.alert('Warning', err.message)); | 86 | this.warningsSub = this.webTorrentService.errors.subscribe(err => this.notificationsService.alert('Warning', err.message)) |
84 | } | 87 | } |
85 | 88 | ||
86 | ngOnDestroy() { | 89 | ngOnDestroy () { |
87 | // Remove WebTorrent stuff | 90 | // Remove WebTorrent stuff |
88 | console.log('Removing video from webtorrent.'); | 91 | console.log('Removing video from webtorrent.') |
89 | window.clearInterval(this.torrentInfosInterval); | 92 | window.clearInterval(this.torrentInfosInterval) |
90 | window.clearTimeout(this.errorTimer); | 93 | window.clearTimeout(this.errorTimer) |
91 | 94 | ||
92 | if (this.video !== null && this.webTorrentService.has(this.video.magnetUri)) { | 95 | if (this.video !== null && this.webTorrentService.has(this.video.magnetUri)) { |
93 | this.webTorrentService.remove(this.video.magnetUri); | 96 | this.webTorrentService.remove(this.video.magnetUri) |
94 | } | 97 | } |
95 | 98 | ||
96 | // Remove player | 99 | // Remove player |
97 | videojs(this.playerElement).dispose(); | 100 | videojs(this.playerElement).dispose() |
98 | 101 | ||
99 | // Unsubscribe subscriptions | 102 | // Unsubscribe subscriptions |
100 | this.paramsSub.unsubscribe(); | 103 | this.paramsSub.unsubscribe() |
101 | this.errorsSub.unsubscribe(); | 104 | this.errorsSub.unsubscribe() |
102 | this.warningsSub.unsubscribe(); | 105 | this.warningsSub.unsubscribe() |
103 | } | 106 | } |
104 | 107 | ||
105 | loadVideo() { | 108 | loadVideo () { |
106 | // Reset the error | 109 | // Reset the error |
107 | this.error = false; | 110 | this.error = false |
108 | // We are loading the video | 111 | // We are loading the video |
109 | this.loading = true; | 112 | this.loading = true |
110 | 113 | ||
111 | console.log('Adding ' + this.video.magnetUri + '.'); | 114 | console.log('Adding ' + this.video.magnetUri + '.') |
112 | 115 | ||
113 | // The callback might never return if there are network issues | 116 | // The callback might never return if there are network issues |
114 | // So we create a timer to inform the user the load is abnormally long | 117 | // So we create a timer to inform the user the load is abnormally long |
115 | this.errorTimer = window.setTimeout(() => this.loadTooLong(), VideoWatchComponent.LOADTIME_TOO_LONG); | 118 | this.errorTimer = window.setTimeout(() => this.loadTooLong(), VideoWatchComponent.LOADTIME_TOO_LONG) |
116 | 119 | ||
117 | this.webTorrentService.add(this.video.magnetUri, (torrent) => { | 120 | this.webTorrentService.add(this.video.magnetUri, (torrent) => { |
118 | // Clear the error timer | 121 | // Clear the error timer |
119 | window.clearTimeout(this.errorTimer); | 122 | window.clearTimeout(this.errorTimer) |
120 | // Maybe the error was fired by the timer, so reset it | 123 | // Maybe the error was fired by the timer, so reset it |
121 | this.error = false; | 124 | this.error = false |
122 | 125 | ||
123 | // We are not loading the video anymore | 126 | // We are not loading the video anymore |
124 | this.loading = false; | 127 | this.loading = false |
125 | 128 | ||
126 | console.log('Added ' + this.video.magnetUri + '.'); | 129 | console.log('Added ' + this.video.magnetUri + '.') |
127 | torrent.files[0].renderTo(this.playerElement, { autoplay: true }, (err) => { | 130 | torrent.files[0].renderTo(this.playerElement, { autoplay: true }, (err) => { |
128 | if (err) { | 131 | if (err) { |
129 | this.notificationsService.error('Error', 'Cannot append the file in the video element.'); | 132 | this.notificationsService.error('Error', 'Cannot append the file in the video element.') |
130 | console.error(err); | 133 | console.error(err) |
131 | } | 134 | } |
132 | }); | 135 | }) |
133 | 136 | ||
134 | this.runInProgress(torrent); | 137 | this.runInProgress(torrent) |
135 | }); | 138 | }) |
136 | } | 139 | } |
137 | 140 | ||
138 | setLike() { | 141 | setLike () { |
139 | if (this.isUserLoggedIn() === false) return; | 142 | if (this.isUserLoggedIn() === false) return |
140 | // Already liked this video | 143 | // Already liked this video |
141 | if (this.userRating === 'like') return; | 144 | if (this.userRating === 'like') return |
142 | 145 | ||
143 | this.videoService.setVideoLike(this.video.id) | 146 | this.videoService.setVideoLike(this.video.id) |
144 | .subscribe( | 147 | .subscribe( |
145 | () => { | 148 | () => { |
146 | // Update the video like attribute | 149 | // Update the video like attribute |
147 | this.updateVideoRating(this.userRating, 'like'); | 150 | this.updateVideoRating(this.userRating, 'like') |
148 | this.userRating = 'like'; | 151 | this.userRating = 'like' |
149 | }, | 152 | }, |
150 | 153 | ||
151 | err => this.notificationsService.error('Error', err.text) | 154 | err => this.notificationsService.error('Error', err.text) |
152 | ); | 155 | ) |
153 | } | 156 | } |
154 | 157 | ||
155 | setDislike() { | 158 | setDislike () { |
156 | if (this.isUserLoggedIn() === false) return; | 159 | if (this.isUserLoggedIn() === false) return |
157 | // Already disliked this video | 160 | // Already disliked this video |
158 | if (this.userRating === 'dislike') return; | 161 | if (this.userRating === 'dislike') return |
159 | 162 | ||
160 | this.videoService.setVideoDislike(this.video.id) | 163 | this.videoService.setVideoDislike(this.video.id) |
161 | .subscribe( | 164 | .subscribe( |
162 | () => { | 165 | () => { |
163 | // Update the video dislike attribute | 166 | // Update the video dislike attribute |
164 | this.updateVideoRating(this.userRating, 'dislike'); | 167 | this.updateVideoRating(this.userRating, 'dislike') |
165 | this.userRating = 'dislike'; | 168 | this.userRating = 'dislike' |
166 | }, | 169 | }, |
167 | 170 | ||
168 | err => this.notificationsService.error('Error', err.text) | 171 | err => this.notificationsService.error('Error', err.text) |
169 | ); | 172 | ) |
170 | } | 173 | } |
171 | 174 | ||
172 | removeVideo(event: Event) { | 175 | removeVideo (event: Event) { |
173 | event.preventDefault(); | 176 | event.preventDefault() |
174 | 177 | ||
175 | this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe( | 178 | this.confirmService.confirm('Do you really want to delete this video?', 'Delete').subscribe( |
176 | res => { | 179 | res => { |
177 | if (res === false) return; | 180 | if (res === false) return |
178 | 181 | ||
179 | this.videoService.removeVideo(this.video.id) | 182 | this.videoService.removeVideo(this.video.id) |
180 | .subscribe( | 183 | .subscribe( |
181 | status => { | 184 | status => { |
182 | this.notificationsService.success('Success', `Video ${this.video.name} deleted.`); | 185 | this.notificationsService.success('Success', `Video ${this.video.name} deleted.`) |
183 | // Go back to the video-list. | 186 | // Go back to the video-list. |
184 | this.router.navigate(['/videos/list']); | 187 | this.router.navigate(['/videos/list']) |
185 | }, | 188 | }, |
186 | 189 | ||
187 | error => this.notificationsService.error('Error', error.text) | 190 | error => this.notificationsService.error('Error', error.text) |
188 | ); | 191 | ) |
189 | } | 192 | } |
190 | ); | 193 | ) |
191 | } | 194 | } |
192 | 195 | ||
193 | blacklistVideo(event: Event) { | 196 | blacklistVideo (event: Event) { |
194 | event.preventDefault(); | 197 | event.preventDefault() |
195 | 198 | ||
196 | this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( | 199 | this.confirmService.confirm('Do you really want to blacklist this video ?', 'Blacklist').subscribe( |
197 | res => { | 200 | res => { |
198 | if (res === false) return; | 201 | if (res === false) return |
199 | 202 | ||
200 | this.videoService.blacklistVideo(this.video.id) | 203 | this.videoService.blacklistVideo(this.video.id) |
201 | .subscribe( | 204 | .subscribe( |
202 | status => { | 205 | status => { |
203 | this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`); | 206 | this.notificationsService.success('Success', `Video ${this.video.name} had been blacklisted.`) |
204 | this.router.navigate(['/videos/list']); | 207 | this.router.navigate(['/videos/list']) |
205 | }, | 208 | }, |
206 | 209 | ||
207 | error => this.notificationsService.error('Error', error.text) | 210 | error => this.notificationsService.error('Error', error.text) |
208 | ); | 211 | ) |
209 | } | 212 | } |
210 | ); | 213 | ) |
211 | } | 214 | } |
212 | 215 | ||
213 | showReportModal(event: Event) { | 216 | showReportModal (event: Event) { |
214 | event.preventDefault(); | 217 | event.preventDefault() |
215 | this.videoReportModal.show(); | 218 | this.videoReportModal.show() |
216 | } | 219 | } |
217 | 220 | ||
218 | showShareModal() { | 221 | showShareModal () { |
219 | this.videoShareModal.show(); | 222 | this.videoShareModal.show() |
220 | } | 223 | } |
221 | 224 | ||
222 | showMagnetUriModal(event: Event) { | 225 | showMagnetUriModal (event: Event) { |
223 | event.preventDefault(); | 226 | event.preventDefault() |
224 | this.videoMagnetModal.show(); | 227 | this.videoMagnetModal.show() |
225 | } | 228 | } |
226 | 229 | ||
227 | isUserLoggedIn() { | 230 | isUserLoggedIn () { |
228 | return this.authService.isLoggedIn(); | 231 | return this.authService.isLoggedIn() |
229 | } | 232 | } |
230 | 233 | ||
231 | canUserUpdateVideo() { | 234 | canUserUpdateVideo () { |
232 | return this.video.isUpdatableBy(this.authService.getUser()); | 235 | return this.video.isUpdatableBy(this.authService.getUser()) |
233 | } | 236 | } |
234 | 237 | ||
235 | isVideoRemovable() { | 238 | isVideoRemovable () { |
236 | return this.video.isRemovableBy(this.authService.getUser()); | 239 | return this.video.isRemovableBy(this.authService.getUser()) |
237 | } | 240 | } |
238 | 241 | ||
239 | isVideoBlacklistable() { | 242 | isVideoBlacklistable () { |
240 | return this.video.isBlackistableBy(this.authService.getUser()); | 243 | return this.video.isBlackistableBy(this.authService.getUser()) |
241 | } | 244 | } |
242 | 245 | ||
243 | private checkUserRating() { | 246 | private checkUserRating () { |
244 | // Unlogged users do not have ratings | 247 | // Unlogged users do not have ratings |
245 | if (this.isUserLoggedIn() === false) return; | 248 | if (this.isUserLoggedIn() === false) return |
246 | 249 | ||
247 | this.videoService.getUserVideoRating(this.video.id) | 250 | this.videoService.getUserVideoRating(this.video.id) |
248 | .subscribe( | 251 | .subscribe( |
249 | ratingObject => { | 252 | ratingObject => { |
250 | if (ratingObject) { | 253 | if (ratingObject) { |
251 | this.userRating = ratingObject.rating; | 254 | this.userRating = ratingObject.rating |
252 | } | 255 | } |
253 | }, | 256 | }, |
254 | 257 | ||
255 | err => this.notificationsService.error('Error', err.text) | 258 | err => this.notificationsService.error('Error', err.text) |
256 | ); | 259 | ) |
257 | } | 260 | } |
258 | 261 | ||
259 | private onVideoFetched(video: Video) { | 262 | private onVideoFetched (video: Video) { |
260 | this.video = video; | 263 | this.video = video |
261 | 264 | ||
262 | let observable; | 265 | let observable |
263 | if (this.video.isVideoNSFWForUser(this.authService.getUser())) { | 266 | if (this.video.isVideoNSFWForUser(this.authService.getUser())) { |
264 | observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW'); | 267 | observable = this.confirmService.confirm('This video is not safe for work. Are you sure you want to watch it?', 'NSFW') |
265 | } else { | 268 | } else { |
266 | observable = Observable.of(true); | 269 | observable = Observable.of(true) |
267 | } | 270 | } |
268 | 271 | ||
269 | observable.subscribe( | 272 | observable.subscribe( |
270 | res => { | 273 | res => { |
271 | if (res === false) { | 274 | if (res === false) { |
272 | return this.router.navigate([ '/videos/list' ]); | 275 | return this.router.navigate([ '/videos/list' ]) |
273 | } | 276 | } |
274 | 277 | ||
275 | this.setOpenGraphTags(); | 278 | this.setOpenGraphTags() |
276 | this.loadVideo(); | 279 | this.loadVideo() |
277 | this.checkUserRating(); | 280 | this.checkUserRating() |
278 | } | 281 | } |
279 | ); | 282 | ) |
280 | } | 283 | } |
281 | 284 | ||
282 | private updateVideoRating(oldRating: RateType, newRating: RateType) { | 285 | private updateVideoRating (oldRating: RateType, newRating: RateType) { |
283 | let likesToIncrement = 0; | 286 | let likesToIncrement = 0 |
284 | let dislikesToIncrement = 0; | 287 | let dislikesToIncrement = 0 |
285 | 288 | ||
286 | if (oldRating) { | 289 | if (oldRating) { |
287 | if (oldRating === 'like') likesToIncrement--; | 290 | if (oldRating === 'like') likesToIncrement-- |
288 | if (oldRating === 'dislike') dislikesToIncrement--; | 291 | if (oldRating === 'dislike') dislikesToIncrement-- |
289 | } | 292 | } |
290 | 293 | ||
291 | if (newRating === 'like') likesToIncrement++; | 294 | if (newRating === 'like') likesToIncrement++ |
292 | if (newRating === 'dislike') dislikesToIncrement++; | 295 | if (newRating === 'dislike') dislikesToIncrement++ |
293 | 296 | ||
294 | this.video.likes += likesToIncrement; | 297 | this.video.likes += likesToIncrement |
295 | this.video.dislikes += dislikesToIncrement; | 298 | this.video.dislikes += dislikesToIncrement |
296 | } | 299 | } |
297 | 300 | ||
298 | private loadTooLong() { | 301 | private loadTooLong () { |
299 | this.error = true; | 302 | this.error = true |
300 | console.error('The video load seems to be abnormally long.'); | 303 | console.error('The video load seems to be abnormally long.') |
301 | } | 304 | } |
302 | 305 | ||
303 | private setOpenGraphTags() { | 306 | private setOpenGraphTags () { |
304 | this.metaService.setTitle(this.video.name); | 307 | this.metaService.setTitle(this.video.name) |
305 | 308 | ||
306 | this.metaService.setTag('og:type', 'video'); | 309 | this.metaService.setTag('og:type', 'video') |
307 | 310 | ||
308 | this.metaService.setTag('og:title', this.video.name); | 311 | this.metaService.setTag('og:title', this.video.name) |
309 | this.metaService.setTag('name', this.video.name); | 312 | this.metaService.setTag('name', this.video.name) |
310 | 313 | ||
311 | this.metaService.setTag('og:description', this.video.description); | 314 | this.metaService.setTag('og:description', this.video.description) |
312 | this.metaService.setTag('description', this.video.description); | 315 | this.metaService.setTag('description', this.video.description) |
313 | 316 | ||
314 | this.metaService.setTag('og:image', this.video.thumbnailPath); | 317 | this.metaService.setTag('og:image', this.video.thumbnailPath) |
315 | 318 | ||
316 | this.metaService.setTag('og:duration', this.video.duration.toString()); | 319 | this.metaService.setTag('og:duration', this.video.duration.toString()) |
317 | 320 | ||
318 | this.metaService.setTag('og:site_name', 'PeerTube'); | 321 | this.metaService.setTag('og:site_name', 'PeerTube') |
319 | 322 | ||
320 | this.metaService.setTag('og:url', window.location.href); | 323 | this.metaService.setTag('og:url', window.location.href) |
321 | this.metaService.setTag('url', window.location.href); | 324 | this.metaService.setTag('url', window.location.href) |
322 | } | 325 | } |
323 | 326 | ||
324 | private runInProgress(torrent: any) { | 327 | private runInProgress (torrent: any) { |
325 | // Refresh each second | 328 | // Refresh each second |
326 | this.torrentInfosInterval = window.setInterval(() => { | 329 | this.torrentInfosInterval = window.setInterval(() => { |
327 | this.ngZone.run(() => { | 330 | this.ngZone.run(() => { |
328 | this.downloadSpeed = torrent.downloadSpeed; | 331 | this.downloadSpeed = torrent.downloadSpeed |
329 | this.numPeers = torrent.numPeers; | 332 | this.numPeers = torrent.numPeers |
330 | this.uploadSpeed = torrent.uploadSpeed; | 333 | this.uploadSpeed = torrent.uploadSpeed |
331 | }); | 334 | }) |
332 | }, 1000); | 335 | }, 1000) |
333 | } | 336 | } |
334 | } | 337 | } |
diff --git a/client/src/app/videos/video-watch/webtorrent.service.ts b/client/src/app/videos/video-watch/webtorrent.service.ts index 8936e7992..211894bfd 100644 --- a/client/src/app/videos/video-watch/webtorrent.service.ts +++ b/client/src/app/videos/video-watch/webtorrent.service.ts | |||
@@ -1,33 +1,33 @@ | |||
1 | import { Injectable } from '@angular/core'; | 1 | import { Injectable } from '@angular/core' |
2 | import { Subject } from 'rxjs/Subject'; | 2 | import { Subject } from 'rxjs/Subject' |
3 | 3 | ||
4 | import * as WebTorrent from 'webtorrent'; | 4 | import * as WebTorrent from 'webtorrent' |
5 | 5 | ||
6 | @Injectable() | 6 | @Injectable() |
7 | export class WebTorrentService { | 7 | export class WebTorrentService { |
8 | errors = new Subject<Error>(); | 8 | errors = new Subject<Error>() |
9 | warnings = new Subject<Error>(); | 9 | warnings = new Subject<Error>() |
10 | 10 | ||
11 | // TODO: use WebTorrent @type | 11 | // TODO: use WebTorrent @type |
12 | // private client: WebTorrent.Client; | 12 | // private client: WebTorrent.Client |
13 | private client: any; | 13 | private client: any |
14 | 14 | ||
15 | constructor() { | 15 | constructor () { |
16 | this.client = new WebTorrent({ dht: false }); | 16 | this.client = new WebTorrent({ dht: false }) |
17 | 17 | ||
18 | this.client.on('error', (err) => this.errors.next(err)); | 18 | this.client.on('error', (err) => this.errors.next(err)) |
19 | this.client.on('warning', (err) => this.warnings.next(err)); | 19 | this.client.on('warning', (err) => this.warnings.next(err)) |
20 | } | 20 | } |
21 | 21 | ||
22 | add(magnetUri: string, callback: Function) { | 22 | add (magnetUri: string, callback: Function) { |
23 | return this.client.add(magnetUri, callback); | 23 | return this.client.add(magnetUri, callback) |
24 | } | 24 | } |
25 | 25 | ||
26 | remove(magnetUri: string) { | 26 | remove (magnetUri: string) { |
27 | return this.client.remove(magnetUri); | 27 | return this.client.remove(magnetUri) |
28 | } | 28 | } |
29 | 29 | ||
30 | has(magnetUri: string) { | 30 | has (magnetUri: string) { |
31 | return this.client.get(magnetUri) !== null; | 31 | return this.client.get(magnetUri) !== null |
32 | } | 32 | } |
33 | } | 33 | } |
diff --git a/client/src/app/videos/videos-routing.module.ts b/client/src/app/videos/videos-routing.module.ts index 70968b4d1..7d002abde 100644 --- a/client/src/app/videos/videos-routing.module.ts +++ b/client/src/app/videos/videos-routing.module.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | import { RouterModule, Routes } from '@angular/router'; | 2 | import { RouterModule, Routes } from '@angular/router' |
3 | 3 | ||
4 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit'; | 4 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit' |
5 | import { VideoListComponent } from './video-list'; | 5 | import { VideoListComponent } from './video-list' |
6 | import { VideosComponent } from './videos.component'; | 6 | import { VideosComponent } from './videos.component' |
7 | import { VideoWatchComponent } from './video-watch'; | 7 | import { VideoWatchComponent } from './video-watch' |
8 | 8 | ||
9 | const videosRoutes: Routes = [ | 9 | const videosRoutes: Routes = [ |
10 | { | 10 | { |
@@ -48,7 +48,7 @@ const videosRoutes: Routes = [ | |||
48 | } | 48 | } |
49 | ] | 49 | ] |
50 | } | 50 | } |
51 | ]; | 51 | ] |
52 | 52 | ||
53 | @NgModule({ | 53 | @NgModule({ |
54 | imports: [ RouterModule.forChild(videosRoutes) ], | 54 | imports: [ RouterModule.forChild(videosRoutes) ], |
diff --git a/client/src/app/videos/videos.component.ts b/client/src/app/videos/videos.component.ts index 591e7523d..972c2221f 100644 --- a/client/src/app/videos/videos.component.ts +++ b/client/src/app/videos/videos.component.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { Component } from '@angular/core'; | 1 | import { Component } from '@angular/core' |
2 | 2 | ||
3 | @Component({ | 3 | @Component({ |
4 | template: '<router-outlet></router-outlet>' | 4 | template: '<router-outlet></router-outlet>' |
diff --git a/client/src/app/videos/videos.module.ts b/client/src/app/videos/videos.module.ts index adfbe7031..75a8dd24f 100644 --- a/client/src/app/videos/videos.module.ts +++ b/client/src/app/videos/videos.module.ts | |||
@@ -1,20 +1,20 @@ | |||
1 | import { NgModule } from '@angular/core'; | 1 | import { NgModule } from '@angular/core' |
2 | 2 | ||
3 | import { TagInputModule } from 'ng2-tag-input'; | 3 | import { TagInputModule } from 'ng2-tag-input' |
4 | 4 | ||
5 | import { VideosRoutingModule } from './videos-routing.module'; | 5 | import { VideosRoutingModule } from './videos-routing.module' |
6 | import { VideosComponent } from './videos.component'; | 6 | import { VideosComponent } from './videos.component' |
7 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit'; | 7 | import { VideoAddComponent, VideoUpdateComponent } from './video-edit' |
8 | import { LoaderComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list'; | 8 | import { LoaderComponent, VideoListComponent, VideoMiniatureComponent, VideoSortComponent } from './video-list' |
9 | import { | 9 | import { |
10 | VideoWatchComponent, | 10 | VideoWatchComponent, |
11 | VideoMagnetComponent, | 11 | VideoMagnetComponent, |
12 | VideoReportComponent, | 12 | VideoReportComponent, |
13 | VideoShareComponent, | 13 | VideoShareComponent, |
14 | WebTorrentService | 14 | WebTorrentService |
15 | } from './video-watch'; | 15 | } from './video-watch' |
16 | import { VideoService } from './shared'; | 16 | import { VideoService } from './shared' |
17 | import { SharedModule } from '../shared'; | 17 | import { SharedModule } from '../shared' |
18 | 18 | ||
19 | @NgModule({ | 19 | @NgModule({ |
20 | imports: [ | 20 | imports: [ |