aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/+videos/+video-watch/video-watch.component.ts53
-rw-r--r--client/src/app/core/auth/auth-user.model.ts18
-rw-r--r--client/src/app/core/auth/auth.service.ts4
-rw-r--r--client/src/app/core/users/user-local-storage.service.ts14
-rw-r--r--client/src/app/helpers/utils/url.ts5
-rw-r--r--client/src/app/shared/shared-main/shared-main.module.ts11
-rw-r--r--client/src/app/shared/shared-main/video/index.ts1
-rw-r--r--client/src/app/shared/shared-main/video/video-file-token.service.ts33
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.html5
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.ts19
10 files changed, 117 insertions, 46 deletions
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 9ae6f9f12..b3818c8de 100644
--- a/client/src/app/+videos/+video-watch/video-watch.component.ts
+++ b/client/src/app/+videos/+video-watch/video-watch.component.ts
@@ -20,12 +20,12 @@ import {
20} from '@app/core' 20} from '@app/core'
21import { HooksService } from '@app/core/plugins/hooks.service' 21import { HooksService } from '@app/core/plugins/hooks.service'
22import { isXPercentInViewport, scrollToTop } from '@app/helpers' 22import { isXPercentInViewport, scrollToTop } from '@app/helpers'
23import { Video, VideoCaptionService, VideoDetails, VideoService } from '@app/shared/shared-main' 23import { Video, VideoCaptionService, VideoDetails, VideoFileTokenService, VideoService } from '@app/shared/shared-main'
24import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription' 24import { SubscribeButtonComponent } from '@app/shared/shared-user-subscription'
25import { LiveVideoService } from '@app/shared/shared-video-live' 25import { LiveVideoService } from '@app/shared/shared-video-live'
26import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist' 26import { VideoPlaylist, VideoPlaylistService } from '@app/shared/shared-video-playlist'
27import { logger } from '@root-helpers/logger' 27import { logger } from '@root-helpers/logger'
28import { isP2PEnabled } from '@root-helpers/video' 28import { isP2PEnabled, videoRequiresAuth } from '@root-helpers/video'
29import { timeToInt } from '@shared/core-utils' 29import { timeToInt } from '@shared/core-utils'
30import { 30import {
31 HTMLServerConfig, 31 HTMLServerConfig,
@@ -78,6 +78,8 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
78 private nextVideoUUID = '' 78 private nextVideoUUID = ''
79 private nextVideoTitle = '' 79 private nextVideoTitle = ''
80 80
81 private videoFileToken: string
82
81 private currentTime: number 83 private currentTime: number
82 84
83 private paramsSub: Subscription 85 private paramsSub: Subscription
@@ -110,6 +112,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
110 private pluginService: PluginService, 112 private pluginService: PluginService,
111 private peertubeSocket: PeerTubeSocket, 113 private peertubeSocket: PeerTubeSocket,
112 private screenService: ScreenService, 114 private screenService: ScreenService,
115 private videoFileTokenService: VideoFileTokenService,
113 private location: PlatformLocation, 116 private location: PlatformLocation,
114 @Inject(LOCALE_ID) private localeId: string 117 @Inject(LOCALE_ID) private localeId: string
115 ) { } 118 ) { }
@@ -252,12 +255,19 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
252 'filter:api.video-watch.video.get.result' 255 'filter:api.video-watch.video.get.result'
253 ) 256 )
254 257
255 const videoAndLiveObs: Observable<{ video: VideoDetails, live?: LiveVideo }> = videoObs.pipe( 258 const videoAndLiveObs: Observable<{ video: VideoDetails, live?: LiveVideo, videoFileToken?: string }> = videoObs.pipe(
256 switchMap(video => { 259 switchMap(video => {
257 if (!video.isLive) return of({ video }) 260 if (!video.isLive) return of({ video, live: undefined })
258 261
259 return this.liveVideoService.getVideoLive(video.uuid) 262 return this.liveVideoService.getVideoLive(video.uuid)
260 .pipe(map(live => ({ live, video }))) 263 .pipe(map(live => ({ live, video })))
264 }),
265
266 switchMap(({ video, live }) => {
267 if (!videoRequiresAuth(video)) return of({ video, live, videoFileToken: undefined })
268
269 return this.videoFileTokenService.getVideoFileToken(video.uuid)
270 .pipe(map(({ token }) => ({ video, live, videoFileToken: token })))
261 }) 271 })
262 ) 272 )
263 273
@@ -266,7 +276,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
266 this.videoCaptionService.listCaptions(videoId), 276 this.videoCaptionService.listCaptions(videoId),
267 this.userService.getAnonymousOrLoggedUser() 277 this.userService.getAnonymousOrLoggedUser()
268 ]).subscribe({ 278 ]).subscribe({
269 next: ([ { video, live }, captionsResult, loggedInOrAnonymousUser ]) => { 279 next: ([ { video, live, videoFileToken }, captionsResult, loggedInOrAnonymousUser ]) => {
270 const queryParams = this.route.snapshot.queryParams 280 const queryParams = this.route.snapshot.queryParams
271 281
272 const urlOptions = { 282 const urlOptions = {
@@ -283,7 +293,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
283 peertubeLink: false 293 peertubeLink: false
284 } 294 }
285 295
286 this.onVideoFetched({ video, live, videoCaptions: captionsResult.data, loggedInOrAnonymousUser, urlOptions }) 296 this.onVideoFetched({ video, live, videoCaptions: captionsResult.data, videoFileToken, loggedInOrAnonymousUser, urlOptions })
287 .catch(err => this.handleGlobalError(err)) 297 .catch(err => this.handleGlobalError(err))
288 }, 298 },
289 299
@@ -356,16 +366,19 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
356 video: VideoDetails 366 video: VideoDetails
357 live: LiveVideo 367 live: LiveVideo
358 videoCaptions: VideoCaption[] 368 videoCaptions: VideoCaption[]
369 videoFileToken: string
370
359 urlOptions: URLOptions 371 urlOptions: URLOptions
360 loggedInOrAnonymousUser: User 372 loggedInOrAnonymousUser: User
361 }) { 373 }) {
362 const { video, live, videoCaptions, urlOptions, loggedInOrAnonymousUser } = options 374 const { video, live, videoCaptions, urlOptions, videoFileToken, loggedInOrAnonymousUser } = options
363 375
364 this.subscribeToLiveEventsIfNeeded(this.video, video) 376 this.subscribeToLiveEventsIfNeeded(this.video, video)
365 377
366 this.video = video 378 this.video = video
367 this.videoCaptions = videoCaptions 379 this.videoCaptions = videoCaptions
368 this.liveVideo = live 380 this.liveVideo = live
381 this.videoFileToken = videoFileToken
369 382
370 // Re init attributes 383 // Re init attributes
371 this.playerPlaceholderImgSrc = undefined 384 this.playerPlaceholderImgSrc = undefined
@@ -414,6 +427,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
414 video: this.video, 427 video: this.video,
415 videoCaptions: this.videoCaptions, 428 videoCaptions: this.videoCaptions,
416 liveVideo: this.liveVideo, 429 liveVideo: this.liveVideo,
430 videoFileToken: this.videoFileToken,
417 urlOptions, 431 urlOptions,
418 loggedInOrAnonymousUser, 432 loggedInOrAnonymousUser,
419 user: this.user 433 user: this.user
@@ -561,11 +575,15 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
561 video: VideoDetails 575 video: VideoDetails
562 liveVideo: LiveVideo 576 liveVideo: LiveVideo
563 videoCaptions: VideoCaption[] 577 videoCaptions: VideoCaption[]
578
579 videoFileToken: string
580
564 urlOptions: CustomizationOptions & { playerMode: PlayerMode } 581 urlOptions: CustomizationOptions & { playerMode: PlayerMode }
582
565 loggedInOrAnonymousUser: User 583 loggedInOrAnonymousUser: User
566 user?: AuthUser // Keep for plugins 584 user?: AuthUser // Keep for plugins
567 }) { 585 }) {
568 const { video, liveVideo, videoCaptions, urlOptions, loggedInOrAnonymousUser } = params 586 const { video, liveVideo, videoCaptions, videoFileToken, urlOptions, loggedInOrAnonymousUser } = params
569 587
570 const getStartTime = () => { 588 const getStartTime = () => {
571 const byUrl = urlOptions.startTime !== undefined 589 const byUrl = urlOptions.startTime !== undefined
@@ -623,13 +641,6 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
623 theaterButton: true, 641 theaterButton: true,
624 captions: videoCaptions.length !== 0, 642 captions: videoCaptions.length !== 0,
625 643
626 videoViewUrl: video.privacy.id !== VideoPrivacy.PRIVATE
627 ? this.videoService.getVideoViewUrl(video.uuid)
628 : null,
629 authorizationHeader: this.authService.getRequestHeaderValue(),
630
631 metricsUrl: environment.apiUrl + '/api/v1/metrics/playback',
632
633 embedUrl: video.embedUrl, 644 embedUrl: video.embedUrl,
634 embedTitle: video.name, 645 embedTitle: video.name,
635 instanceName: this.serverConfig.instance.name, 646 instanceName: this.serverConfig.instance.name,
@@ -639,7 +650,17 @@ export class VideoWatchComponent implements OnInit, OnDestroy {
639 650
640 language: this.localeId, 651 language: this.localeId,
641 652
642 serverUrl: environment.apiUrl, 653 metricsUrl: environment.apiUrl + '/api/v1/metrics/playback',
654
655 videoViewUrl: video.privacy.id !== VideoPrivacy.PRIVATE
656 ? this.videoService.getVideoViewUrl(video.uuid)
657 : null,
658 authorizationHeader: () => this.authService.getRequestHeaderValue(),
659
660 serverUrl: environment.originServerUrl,
661
662 videoFileToken: () => videoFileToken,
663 requiresAuth: videoRequiresAuth(video),
643 664
644 videoCaptions: playerCaptions, 665 videoCaptions: playerCaptions,
645 666
diff --git a/client/src/app/core/auth/auth-user.model.ts b/client/src/app/core/auth/auth-user.model.ts
index cd9665e37..a12325421 100644
--- a/client/src/app/core/auth/auth-user.model.ts
+++ b/client/src/app/core/auth/auth-user.model.ts
@@ -1,7 +1,7 @@
1import { Observable, of } from 'rxjs' 1import { Observable, of } from 'rxjs'
2import { map } from 'rxjs/operators' 2import { map } from 'rxjs/operators'
3import { User } from '@app/core/users/user.model' 3import { User } from '@app/core/users/user.model'
4import { UserTokens } from '@root-helpers/users' 4import { OAuthUserTokens } from '@root-helpers/users'
5import { hasUserRight } from '@shared/core-utils/users' 5import { hasUserRight } from '@shared/core-utils/users'
6import { 6import {
7 MyUser as ServerMyUserModel, 7 MyUser as ServerMyUserModel,
@@ -13,33 +13,33 @@ import {
13} from '@shared/models' 13} from '@shared/models'
14 14
15export class AuthUser extends User implements ServerMyUserModel { 15export class AuthUser extends User implements ServerMyUserModel {
16 tokens: UserTokens 16 oauthTokens: OAuthUserTokens
17 specialPlaylists: MyUserSpecialPlaylist[] 17 specialPlaylists: MyUserSpecialPlaylist[]
18 18
19 canSeeVideosLink = true 19 canSeeVideosLink = true
20 20
21 constructor (userHash: Partial<ServerMyUserModel>, hashTokens: Partial<UserTokens>) { 21 constructor (userHash: Partial<ServerMyUserModel>, hashTokens: Partial<OAuthUserTokens>) {
22 super(userHash) 22 super(userHash)
23 23
24 this.tokens = new UserTokens(hashTokens) 24 this.oauthTokens = new OAuthUserTokens(hashTokens)
25 this.specialPlaylists = userHash.specialPlaylists 25 this.specialPlaylists = userHash.specialPlaylists
26 } 26 }
27 27
28 getAccessToken () { 28 getAccessToken () {
29 return this.tokens.accessToken 29 return this.oauthTokens.accessToken
30 } 30 }
31 31
32 getRefreshToken () { 32 getRefreshToken () {
33 return this.tokens.refreshToken 33 return this.oauthTokens.refreshToken
34 } 34 }
35 35
36 getTokenType () { 36 getTokenType () {
37 return this.tokens.tokenType 37 return this.oauthTokens.tokenType
38 } 38 }
39 39
40 refreshTokens (accessToken: string, refreshToken: string) { 40 refreshTokens (accessToken: string, refreshToken: string) {
41 this.tokens.accessToken = accessToken 41 this.oauthTokens.accessToken = accessToken
42 this.tokens.refreshToken = refreshToken 42 this.oauthTokens.refreshToken = refreshToken
43 } 43 }
44 44
45 hasRight (right: UserRight) { 45 hasRight (right: UserRight) {
diff --git a/client/src/app/core/auth/auth.service.ts b/client/src/app/core/auth/auth.service.ts
index 7f4fae4aa..4de28e51e 100644
--- a/client/src/app/core/auth/auth.service.ts
+++ b/client/src/app/core/auth/auth.service.ts
@@ -5,7 +5,7 @@ import { HttpClient, HttpErrorResponse, HttpHeaders, HttpParams } from '@angular
5import { Injectable } from '@angular/core' 5import { Injectable } from '@angular/core'
6import { Router } from '@angular/router' 6import { Router } from '@angular/router'
7import { Notifier } from '@app/core/notification/notifier.service' 7import { Notifier } from '@app/core/notification/notifier.service'
8import { logger, objectToUrlEncoded, peertubeLocalStorage, UserTokens } from '@root-helpers/index' 8import { logger, OAuthUserTokens, objectToUrlEncoded, peertubeLocalStorage } from '@root-helpers/index'
9import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models' 9import { HttpStatusCode, MyUser as UserServerModel, OAuthClientLocal, User, UserLogin, UserRefreshToken } from '@shared/models'
10import { environment } from '../../../environments/environment' 10import { environment } from '../../../environments/environment'
11import { RestExtractor } from '../rest/rest-extractor.service' 11import { RestExtractor } from '../rest/rest-extractor.service'
@@ -74,7 +74,7 @@ export class AuthService {
74 ] 74 ]
75 } 75 }
76 76
77 buildAuthUser (userInfo: Partial<User>, tokens: UserTokens) { 77 buildAuthUser (userInfo: Partial<User>, tokens: OAuthUserTokens) {
78 this.user = new AuthUser(userInfo, tokens) 78 this.user = new AuthUser(userInfo, tokens)
79 } 79 }
80 80
diff --git a/client/src/app/core/users/user-local-storage.service.ts b/client/src/app/core/users/user-local-storage.service.ts
index fff649eef..f1588bdd2 100644
--- a/client/src/app/core/users/user-local-storage.service.ts
+++ b/client/src/app/core/users/user-local-storage.service.ts
@@ -4,7 +4,7 @@ import { Injectable } from '@angular/core'
4import { AuthService, AuthStatus } from '@app/core/auth' 4import { AuthService, AuthStatus } from '@app/core/auth'
5import { getBoolOrDefault } from '@root-helpers/local-storage-utils' 5import { getBoolOrDefault } from '@root-helpers/local-storage-utils'
6import { logger } from '@root-helpers/logger' 6import { logger } from '@root-helpers/logger'
7import { UserLocalStorageKeys, UserTokens } from '@root-helpers/users' 7import { UserLocalStorageKeys, OAuthUserTokens } from '@root-helpers/users'
8import { UserRole, UserUpdateMe } from '@shared/models' 8import { UserRole, UserUpdateMe } from '@shared/models'
9import { NSFWPolicyType } from '@shared/models/videos' 9import { NSFWPolicyType } from '@shared/models/videos'
10import { ServerService } from '../server' 10import { ServerService } from '../server'
@@ -24,7 +24,7 @@ export class UserLocalStorageService {
24 24
25 this.setLoggedInUser(user) 25 this.setLoggedInUser(user)
26 this.setUserInfo(user) 26 this.setUserInfo(user)
27 this.setTokens(user.tokens) 27 this.setTokens(user.oauthTokens)
28 } 28 }
29 }) 29 })
30 30
@@ -43,7 +43,7 @@ export class UserLocalStorageService {
43 next: () => { 43 next: () => {
44 const user = this.authService.getUser() 44 const user = this.authService.getUser()
45 45
46 this.setTokens(user.tokens) 46 this.setTokens(user.oauthTokens)
47 } 47 }
48 }) 48 })
49 } 49 }
@@ -174,14 +174,14 @@ export class UserLocalStorageService {
174 // --------------------------------------------------------------------------- 174 // ---------------------------------------------------------------------------
175 175
176 getTokens () { 176 getTokens () {
177 return UserTokens.getUserTokens(this.localStorageService) 177 return OAuthUserTokens.getUserTokens(this.localStorageService)
178 } 178 }
179 179
180 setTokens (tokens: UserTokens) { 180 setTokens (tokens: OAuthUserTokens) {
181 UserTokens.saveToLocalStorage(this.localStorageService, tokens) 181 OAuthUserTokens.saveToLocalStorage(this.localStorageService, tokens)
182 } 182 }
183 183
184 flushTokens () { 184 flushTokens () {
185 UserTokens.flushLocalStorage(this.localStorageService) 185 OAuthUserTokens.flushLocalStorage(this.localStorageService)
186 } 186 }
187} 187}
diff --git a/client/src/app/helpers/utils/url.ts b/client/src/app/helpers/utils/url.ts
index 08c27e3c1..9e7dc3e6f 100644
--- a/client/src/app/helpers/utils/url.ts
+++ b/client/src/app/helpers/utils/url.ts
@@ -54,8 +54,9 @@ function objectToFormData (obj: any, form?: FormData, namespace?: string) {
54} 54}
55 55
56export { 56export {
57 objectToFormData,
58 getAbsoluteAPIUrl, 57 getAbsoluteAPIUrl,
59 getAPIHost, 58 getAPIHost,
60 getAbsoluteEmbedUrl 59 getAbsoluteEmbedUrl,
60
61 objectToFormData
61} 62}
diff --git a/client/src/app/shared/shared-main/shared-main.module.ts b/client/src/app/shared/shared-main/shared-main.module.ts
index 04b223cc5..c1523bc50 100644
--- a/client/src/app/shared/shared-main/shared-main.module.ts
+++ b/client/src/app/shared/shared-main/shared-main.module.ts
@@ -44,7 +44,15 @@ import {
44import { PluginPlaceholderComponent, PluginSelectorDirective } from './plugins' 44import { PluginPlaceholderComponent, PluginSelectorDirective } from './plugins'
45import { ActorRedirectGuard } from './router' 45import { ActorRedirectGuard } from './router'
46import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users' 46import { UserHistoryService, UserNotificationsComponent, UserNotificationService, UserQuotaComponent } from './users'
47import { EmbedComponent, RedundancyService, VideoImportService, VideoOwnershipService, VideoResolver, VideoService } from './video' 47import {
48 EmbedComponent,
49 RedundancyService,
50 VideoFileTokenService,
51 VideoImportService,
52 VideoOwnershipService,
53 VideoResolver,
54 VideoService
55} from './video'
48import { VideoCaptionService } from './video-caption' 56import { VideoCaptionService } from './video-caption'
49import { VideoChannelService } from './video-channel' 57import { VideoChannelService } from './video-channel'
50 58
@@ -185,6 +193,7 @@ import { VideoChannelService } from './video-channel'
185 VideoImportService, 193 VideoImportService,
186 VideoOwnershipService, 194 VideoOwnershipService,
187 VideoService, 195 VideoService,
196 VideoFileTokenService,
188 VideoResolver, 197 VideoResolver,
189 198
190 VideoCaptionService, 199 VideoCaptionService,
diff --git a/client/src/app/shared/shared-main/video/index.ts b/client/src/app/shared/shared-main/video/index.ts
index 361601456..a2e47883e 100644
--- a/client/src/app/shared/shared-main/video/index.ts
+++ b/client/src/app/shared/shared-main/video/index.ts
@@ -2,6 +2,7 @@ export * from './embed.component'
2export * from './redundancy.service' 2export * from './redundancy.service'
3export * from './video-details.model' 3export * from './video-details.model'
4export * from './video-edit.model' 4export * from './video-edit.model'
5export * from './video-file-token.service'
5export * from './video-import.service' 6export * from './video-import.service'
6export * from './video-ownership.service' 7export * from './video-ownership.service'
7export * from './video.model' 8export * from './video.model'
diff --git a/client/src/app/shared/shared-main/video/video-file-token.service.ts b/client/src/app/shared/shared-main/video/video-file-token.service.ts
new file mode 100644
index 000000000..791607249
--- /dev/null
+++ b/client/src/app/shared/shared-main/video/video-file-token.service.ts
@@ -0,0 +1,33 @@
1import { catchError, map, of, tap } from 'rxjs'
2import { HttpClient } from '@angular/common/http'
3import { Injectable } from '@angular/core'
4import { RestExtractor } from '@app/core'
5import { VideoToken } from '@shared/models'
6import { VideoService } from './video.service'
7
8@Injectable()
9export class VideoFileTokenService {
10
11 private readonly store = new Map<string, { token: string, expires: Date }>()
12
13 constructor (
14 private authHttp: HttpClient,
15 private restExtractor: RestExtractor
16 ) {}
17
18 getVideoFileToken (videoUUID: string) {
19 const existing = this.store.get(videoUUID)
20 if (existing) return of(existing)
21
22 return this.createVideoFileToken(videoUUID)
23 .pipe(tap(result => this.store.set(videoUUID, { token: result.token, expires: new Date(result.expires) })))
24 }
25
26 private createVideoFileToken (videoUUID: string) {
27 return this.authHttp.post<VideoToken>(`${VideoService.BASE_VIDEO_URL}/${videoUUID}/token`, {})
28 .pipe(
29 map(({ files }) => files),
30 catchError(err => this.restExtractor.handleError(err))
31 )
32 }
33}
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.html b/client/src/app/shared/shared-video-miniature/video-download.component.html
index 1c7458b4b..1f622933d 100644
--- a/client/src/app/shared/shared-video-miniature/video-download.component.html
+++ b/client/src/app/shared/shared-video-miniature/video-download.component.html
@@ -48,10 +48,7 @@
48 48
49 <ng-template ngbNavContent> 49 <ng-template ngbNavContent>
50 <div class="nav-content"> 50 <div class="nav-content">
51 <my-input-text 51 <my-input-text [show]="true" [readonly]="true" [withCopy]="true" [withToggle]="false" [value]="getLink()"></my-input-text>
52 *ngIf="!isConfidentialVideo()"
53 [show]="true" [readonly]="true" [withCopy]="true" [withToggle]="false" [value]="getLink()"
54 ></my-input-text>
55 </div> 52 </div>
56 </ng-template> 53 </ng-template>
57 </ng-container> 54 </ng-container>
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.ts b/client/src/app/shared/shared-video-miniature/video-download.component.ts
index 47482caaa..667cb107f 100644
--- a/client/src/app/shared/shared-video-miniature/video-download.component.ts
+++ b/client/src/app/shared/shared-video-miniature/video-download.component.ts
@@ -2,11 +2,12 @@ import { mapValues, pick } from 'lodash-es'
2import { firstValueFrom } from 'rxjs' 2import { firstValueFrom } from 'rxjs'
3import { tap } from 'rxjs/operators' 3import { tap } from 'rxjs/operators'
4import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' 4import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core'
5import { AuthService, HooksService, Notifier } from '@app/core' 5import { HooksService } from '@app/core'
6import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap' 6import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'
7import { logger } from '@root-helpers/logger' 7import { logger } from '@root-helpers/logger'
8import { videoRequiresAuth } from '@root-helpers/video'
8import { VideoCaption, VideoFile, VideoPrivacy } from '@shared/models' 9import { VideoCaption, VideoFile, VideoPrivacy } from '@shared/models'
9import { BytesPipe, NumberFormatterPipe, VideoDetails, VideoService } from '../shared-main' 10import { BytesPipe, NumberFormatterPipe, VideoDetails, VideoFileTokenService, VideoService } from '../shared-main'
10 11
11type DownloadType = 'video' | 'subtitles' 12type DownloadType = 'video' | 'subtitles'
12type FileMetadata = { [key: string]: { label: string, value: string }} 13type FileMetadata = { [key: string]: { label: string, value: string }}
@@ -32,6 +33,8 @@ export class VideoDownloadComponent {
32 33
33 type: DownloadType = 'video' 34 type: DownloadType = 'video'
34 35
36 videoFileToken: string
37
35 private activeModal: NgbModalRef 38 private activeModal: NgbModalRef
36 39
37 private bytesPipe: BytesPipe 40 private bytesPipe: BytesPipe
@@ -42,10 +45,9 @@ export class VideoDownloadComponent {
42 45
43 constructor ( 46 constructor (
44 @Inject(LOCALE_ID) private localeId: string, 47 @Inject(LOCALE_ID) private localeId: string,
45 private notifier: Notifier,
46 private modalService: NgbModal, 48 private modalService: NgbModal,
47 private videoService: VideoService, 49 private videoService: VideoService,
48 private auth: AuthService, 50 private videoFileTokenService: VideoFileTokenService,
49 private hooks: HooksService 51 private hooks: HooksService
50 ) { 52 ) {
51 this.bytesPipe = new BytesPipe() 53 this.bytesPipe = new BytesPipe()
@@ -71,6 +73,8 @@ export class VideoDownloadComponent {
71 } 73 }
72 74
73 show (video: VideoDetails, videoCaptions?: VideoCaption[]) { 75 show (video: VideoDetails, videoCaptions?: VideoCaption[]) {
76 this.videoFileToken = undefined
77
74 this.video = video 78 this.video = video
75 this.videoCaptions = videoCaptions 79 this.videoCaptions = videoCaptions
76 80
@@ -84,6 +88,11 @@ export class VideoDownloadComponent {
84 this.subtitleLanguageId = this.videoCaptions[0].language.id 88 this.subtitleLanguageId = this.videoCaptions[0].language.id
85 } 89 }
86 90
91 if (videoRequiresAuth(this.video)) {
92 this.videoFileTokenService.getVideoFileToken(this.video.uuid)
93 .subscribe(({ token }) => this.videoFileToken = token)
94 }
95
87 this.activeModal.shown.subscribe(() => { 96 this.activeModal.shown.subscribe(() => {
88 this.hooks.runAction('action:modal.video-download.shown', 'common') 97 this.hooks.runAction('action:modal.video-download.shown', 'common')
89 }) 98 })
@@ -155,7 +164,7 @@ export class VideoDownloadComponent {
155 if (!file) return '' 164 if (!file) return ''
156 165
157 const suffix = this.isConfidentialVideo() 166 const suffix = this.isConfidentialVideo()
158 ? '?access_token=' + this.auth.getAccessToken() 167 ? '?videoFileToken=' + this.videoFileToken
159 : '' 168 : ''
160 169
161 switch (this.downloadType) { 170 switch (this.downloadType) {