Add i18n attributes
[oweals/peertube.git] / client / src / app / shared / video / video.service.ts
1 import { catchError, map } from 'rxjs/operators'
2 import { HttpClient, HttpParams, HttpRequest } from '@angular/common/http'
3 import { Injectable } from '@angular/core'
4 import { Observable } from 'rxjs'
5 import { Video as VideoServerModel, VideoDetails as VideoDetailsServerModel } from '../../../../../shared'
6 import { ResultList } from '../../../../../shared/models/result-list.model'
7 import { UserVideoRateUpdate } from '../../../../../shared/models/videos/user-video-rate-update.model'
8 import { UserVideoRate } from '../../../../../shared/models/videos/user-video-rate.model'
9 import { VideoFilter } from '../../../../../shared/models/videos/video-query.type'
10 import { FeedFormat } from '../../../../../shared/models/feeds/feed-format.enum'
11 import { VideoRateType } from '../../../../../shared/models/videos/video-rate.type'
12 import { VideoUpdate } from '../../../../../shared/models/videos/video-update.model'
13 import { environment } from '../../../environments/environment'
14 import { ComponentPagination } from '../rest/component-pagination.model'
15 import { RestExtractor } from '../rest/rest-extractor.service'
16 import { RestService } from '../rest/rest.service'
17 import { UserService } from '../users/user.service'
18 import { VideoSortField } from './sort-field.type'
19 import { VideoDetails } from './video-details.model'
20 import { VideoEdit } from './video-edit.model'
21 import { Video } from './video.model'
22 import { objectToFormData } from '@app/shared/misc/utils'
23 import { Account } from '@app/shared/account/account.model'
24 import { AccountService } from '@app/shared/account/account.service'
25 import { VideoChannel } from '../../../../../shared/models/videos'
26 import { VideoChannelService } from '@app/shared/video-channel/video-channel.service'
27
28 @Injectable()
29 export class VideoService {
30   private static BASE_VIDEO_URL = environment.apiUrl + '/api/v1/videos/'
31   private static BASE_FEEDS_URL = environment.apiUrl + '/feeds/videos.'
32
33   constructor (
34     private authHttp: HttpClient,
35     private restExtractor: RestExtractor,
36     private restService: RestService
37   ) {}
38
39   getVideoViewUrl (uuid: string) {
40     return VideoService.BASE_VIDEO_URL + uuid + '/views'
41   }
42
43   getVideo (uuid: string): Observable<VideoDetails> {
44     return this.authHttp.get<VideoDetailsServerModel>(VideoService.BASE_VIDEO_URL + uuid)
45                .pipe(
46                  map(videoHash => new VideoDetails(videoHash)),
47                  catchError(res => this.restExtractor.handleError(res))
48                )
49   }
50
51   viewVideo (uuid: string): Observable<boolean> {
52     return this.authHttp.post(this.getVideoViewUrl(uuid), {})
53                .pipe(
54                  map(this.restExtractor.extractDataBool),
55                  catchError(this.restExtractor.handleError)
56                )
57   }
58
59   updateVideo (video: VideoEdit) {
60     const language = video.language || null
61     const licence = video.licence || null
62     const category = video.category || null
63     const description = video.description || null
64     const support = video.support || null
65
66     const body: VideoUpdate = {
67       name: video.name,
68       category,
69       licence,
70       language,
71       support,
72       description,
73       channelId: video.channelId,
74       privacy: video.privacy,
75       tags: video.tags,
76       nsfw: video.nsfw,
77       commentsEnabled: video.commentsEnabled,
78       thumbnailfile: video.thumbnailfile,
79       previewfile: video.previewfile
80     }
81
82     const data = objectToFormData(body)
83
84     return this.authHttp.put(VideoService.BASE_VIDEO_URL + video.id, data)
85                .pipe(
86                  map(this.restExtractor.extractDataBool),
87                  catchError(this.restExtractor.handleError)
88                )
89   }
90
91   uploadVideo (video: FormData) {
92     const req = new HttpRequest('POST', VideoService.BASE_VIDEO_URL + 'upload', video, { reportProgress: true })
93
94     return this.authHttp
95                .request<{ video: { id: number, uuid: string} }>(req)
96                .pipe(catchError(this.restExtractor.handleError))
97   }
98
99   getMyVideos (videoPagination: ComponentPagination, sort: VideoSortField): Observable<{ videos: Video[], totalVideos: number}> {
100     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
101
102     let params = new HttpParams()
103     params = this.restService.addRestGetParams(params, pagination, sort)
104
105     return this.authHttp.get(UserService.BASE_USERS_URL + '/me/videos', { params })
106                .pipe(
107                  map(this.extractVideos),
108                  catchError(res => this.restExtractor.handleError(res))
109                )
110   }
111
112   getAccountVideos (
113     account: Account,
114     videoPagination: ComponentPagination,
115     sort: VideoSortField
116   ): Observable<{ videos: Video[], totalVideos: number}> {
117     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
118
119     let params = new HttpParams()
120     params = this.restService.addRestGetParams(params, pagination, sort)
121
122     return this.authHttp
123                .get(AccountService.BASE_ACCOUNT_URL + account.nameWithHost + '/videos', { params })
124                .pipe(
125                  map(this.extractVideos),
126                  catchError(res => this.restExtractor.handleError(res))
127                )
128   }
129
130   getVideoChannelVideos (
131     videoChannel: VideoChannel,
132     videoPagination: ComponentPagination,
133     sort: VideoSortField
134   ): Observable<{ videos: Video[], totalVideos: number}> {
135     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
136
137     let params = new HttpParams()
138     params = this.restService.addRestGetParams(params, pagination, sort)
139
140     return this.authHttp
141                .get(VideoChannelService.BASE_VIDEO_CHANNEL_URL + videoChannel.uuid + '/videos', { params })
142                .pipe(
143                  map(this.extractVideos),
144                  catchError(res => this.restExtractor.handleError(res))
145                )
146   }
147
148   getVideos (
149     videoPagination: ComponentPagination,
150     sort: VideoSortField,
151     filter?: VideoFilter
152   ): Observable<{ videos: Video[], totalVideos: number}> {
153     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
154
155     let params = new HttpParams()
156     params = this.restService.addRestGetParams(params, pagination, sort)
157
158     if (filter) {
159       params = params.set('filter', filter)
160     }
161
162     return this.authHttp
163                .get(VideoService.BASE_VIDEO_URL, { params })
164                .pipe(
165                  map(this.extractVideos),
166                  catchError(res => this.restExtractor.handleError(res))
167                )
168   }
169
170   buildBaseFeedUrls (params: HttpParams) {
171     const feeds = [
172       {
173         label: 'rss 2.0',
174         url: VideoService.BASE_FEEDS_URL + FeedFormat.RSS.toLowerCase()
175       },
176       {
177         label: 'atom 1.0',
178         url: VideoService.BASE_FEEDS_URL + FeedFormat.ATOM.toLowerCase()
179       },
180       {
181         label: 'json 1.0',
182         url: VideoService.BASE_FEEDS_URL + FeedFormat.JSON.toLowerCase()
183       }
184     ]
185
186     if (params && params.keys().length !== 0) {
187       for (const feed of feeds) {
188         feed.url += '?' + params.toString()
189       }
190     }
191
192     return feeds
193   }
194
195   getVideoFeedUrls (sort: VideoSortField, filter?: VideoFilter) {
196     let params = this.restService.addRestGetParams(new HttpParams(), undefined, sort)
197
198     if (filter) params = params.set('filter', filter)
199
200     return this.buildBaseFeedUrls(params)
201   }
202
203   getAccountFeedUrls (accountId: number) {
204     let params = this.restService.addRestGetParams(new HttpParams())
205     params = params.set('accountId', accountId.toString())
206
207     return this.buildBaseFeedUrls(params)
208   }
209
210   getVideoChannelFeedUrls (videoChannelId: number) {
211     let params = this.restService.addRestGetParams(new HttpParams())
212     params = params.set('videoChannelId', videoChannelId.toString())
213
214     return this.buildBaseFeedUrls(params)
215   }
216
217   searchVideos (
218     search: string,
219     videoPagination: ComponentPagination,
220     sort: VideoSortField
221   ): Observable<{ videos: Video[], totalVideos: number}> {
222     const url = VideoService.BASE_VIDEO_URL + 'search'
223
224     const pagination = this.restService.componentPaginationToRestPagination(videoPagination)
225
226     let params = new HttpParams()
227     params = this.restService.addRestGetParams(params, pagination, sort)
228     params = params.append('search', search)
229
230     return this.authHttp
231                .get<ResultList<VideoServerModel>>(url, { params })
232                .pipe(
233                  map(this.extractVideos),
234                  catchError(res => this.restExtractor.handleError(res))
235                )
236   }
237
238   removeVideo (id: number) {
239     return this.authHttp
240                .delete(VideoService.BASE_VIDEO_URL + id)
241                .pipe(
242                  map(this.restExtractor.extractDataBool),
243                  catchError(res => this.restExtractor.handleError(res))
244                )
245   }
246
247   loadCompleteDescription (descriptionPath: string) {
248     return this.authHttp
249                .get(environment.apiUrl + descriptionPath)
250                .pipe(
251                  map(res => res[ 'description' ]),
252                  catchError(res => this.restExtractor.handleError(res))
253                )
254   }
255
256   setVideoLike (id: number) {
257     return this.setVideoRate(id, 'like')
258   }
259
260   setVideoDislike (id: number) {
261     return this.setVideoRate(id, 'dislike')
262   }
263
264   unsetVideoLike (id: number) {
265     return this.setVideoRate(id, 'none')
266   }
267
268   getUserVideoRating (id: number) {
269     const url = UserService.BASE_USERS_URL + 'me/videos/' + id + '/rating'
270
271     return this.authHttp.get<UserVideoRate>(url)
272                .pipe(catchError(res => this.restExtractor.handleError(res)))
273   }
274
275   private setVideoRate (id: number, rateType: VideoRateType) {
276     const url = VideoService.BASE_VIDEO_URL + id + '/rate'
277     const body: UserVideoRateUpdate = {
278       rating: rateType
279     }
280
281     return this.authHttp
282                .put(url, body)
283                .pipe(
284                  map(this.restExtractor.extractDataBool),
285                  catchError(res => this.restExtractor.handleError(res))
286                )
287   }
288
289   private extractVideos (result: ResultList<VideoServerModel>) {
290     const videosJson = result.data
291     const totalVideos = result.total
292     const videos = []
293
294     for (const videoJson of videosJson) {
295       videos.push(new Video(videoJson))
296     }
297
298     return { videos, totalVideos }
299   }
300 }