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