diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-25 17:02:39 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2021-06-25 17:23:33 +0200 |
commit | 262f8ff63109c8a95d9d149c1951cffd4c8301ef (patch) | |
tree | cc58f0555fb0c88a2aeef18ec30c2bdc6dd10ff5 /client | |
parent | c6bfbaebe759caa679f23674fed2ba5c9aee5217 (diff) | |
download | PeerTube-262f8ff63109c8a95d9d149c1951cffd4c8301ef.tar.gz PeerTube-262f8ff63109c8a95d9d149c1951cffd4c8301ef.tar.zst PeerTube-262f8ff63109c8a95d9d149c1951cffd4c8301ef.zip |
Fix subtitle download
Diffstat (limited to 'client')
4 files changed, 161 insertions, 98 deletions
diff --git a/client/src/app/shared/shared-video-miniature/abstract-video-list.ts b/client/src/app/shared/shared-video-miniature/abstract-video-list.ts index bf433aabd..52e72d35b 100644 --- a/client/src/app/shared/shared-video-miniature/abstract-video-list.ts +++ b/client/src/app/shared/shared-video-miniature/abstract-video-list.ts | |||
@@ -196,7 +196,6 @@ export abstract class AbstractVideoList implements OnInit, OnDestroy, AfterConte | |||
196 | // No more results | 196 | // No more results |
197 | if (this.lastQueryLength !== undefined && this.lastQueryLength < this.pagination.itemsPerPage) return | 197 | if (this.lastQueryLength !== undefined && this.lastQueryLength < this.pagination.itemsPerPage) return |
198 | 198 | ||
199 | console.log('near of bottom') | ||
200 | this.pagination.currentPage += 1 | 199 | this.pagination.currentPage += 1 |
201 | 200 | ||
202 | this.setScrollRouteParams() | 201 | this.setScrollRouteParams() |
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 4ac74c106..b50544057 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 | |||
@@ -3,16 +3,14 @@ | |||
3 | <h4 class="modal-title"> | 3 | <h4 class="modal-title"> |
4 | <ng-container i18n>Download</ng-container> | 4 | <ng-container i18n>Download</ng-container> |
5 | 5 | ||
6 | <div *ngIf="videoCaptions" ngbDropdown class="d-inline-block ml-1"> | 6 | <div class="peertube-select-container title-select" *ngIf="hasCaptions()"> |
7 | <span id="dropdown-download-type" ngbDropdownToggle> | 7 | <select id="type" name="type" [(ngModel)]="type" class="form-control"> |
8 | {{ type }} | 8 | <option value="video" i18n>Video</option> |
9 | </span> | 9 | <option value="subtitles" i18n>Subtitles</option> |
10 | <div ngbDropdownMenu aria-labelledby="dropdown-download-type"> | 10 | </select> |
11 | <button *ngIf="type === 'video'" (click)="switchToType('subtitles')" ngbDropdownItem i18n>subtitles</button> | ||
12 | <button *ngIf="type === 'subtitles'" (click)="switchToType('video')" ngbDropdownItem i18n>video</button> | ||
13 | </div> | ||
14 | </div> | 11 | </div> |
15 | </h4> | 12 | </h4> |
13 | |||
16 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> | 14 | <my-global-icon iconName="cross" aria-label="Close" role="button" (click)="hide()"></my-global-icon> |
17 | </div> | 15 | </div> |
18 | 16 | ||
@@ -21,20 +19,35 @@ | |||
21 | The following link contains a private token and should not be shared with anyone. | 19 | The following link contains a private token and should not be shared with anyone. |
22 | </div> | 20 | </div> |
23 | 21 | ||
22 | <!-- Subtitle tab --> | ||
24 | <ng-container *ngIf="type === 'subtitles'"> | 23 | <ng-container *ngIf="type === 'subtitles'"> |
25 | <div class="input-group input-group-sm"> | 24 | <div ngbNav #subtitleNav="ngbNav" class="nav-tabs" [activeId]="subtitleLanguageId" (activeIdChange)="onSubtitleIdChange($event)"> |
26 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" /> | 25 | |
27 | <div class="input-group-append" *ngIf="!isConfidentialVideo()"> | 26 | <ng-container *ngFor="let caption of getCaptions()" [ngbNavItem]="caption.language.id"> |
28 | <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | 27 | <a ngbNavLink i18n>{{ caption.language.label }}</a> |
29 | <span class="glyphicon glyphicon-duplicate"></span> | 28 | |
30 | </button> | 29 | <ng-template ngbNavContent> |
31 | </div> | 30 | <div class="nav-content"> |
31 | <div class="input-group input-group-sm"> | ||
32 | <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" /> | ||
33 | |||
34 | <div class="input-group-append" *ngIf="!isConfidentialVideo()"> | ||
35 | <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> | ||
36 | <span class="glyphicon glyphicon-duplicate"></span> | ||
37 | </button> | ||
38 | </div> | ||
39 | </div> | ||
40 | </div> | ||
41 | </ng-template> | ||
42 | </ng-container> | ||
32 | </div> | 43 | </div> |
44 | |||
45 | <div [ngbNavOutlet]="subtitleNav"></div> | ||
33 | </ng-container> | 46 | </ng-container> |
34 | 47 | ||
48 | <!-- Video tab --> | ||
35 | <ng-container *ngIf="type === 'video'"> | 49 | <ng-container *ngIf="type === 'video'"> |
36 | <div ngbNav #resolutionNav="ngbNav" class="nav-tabs" [activeId]="resolutionId" (activeIdChange)="onResolutionIdChange($event)"> | 50 | <div ngbNav #resolutionNav="ngbNav" class="nav-tabs" [activeId]="resolutionId" (activeIdChange)="onResolutionIdChange($event)"> |
37 | |||
38 | <ng-container *ngFor="let file of getVideoFiles()" [ngbNavItem]="file.resolution.id"> | 51 | <ng-container *ngFor="let file of getVideoFiles()" [ngbNavItem]="file.resolution.id"> |
39 | <a ngbNavLink i18n>{{ file.resolution.label }}</a> | 52 | <a ngbNavLink i18n>{{ file.resolution.label }}</a> |
40 | 53 | ||
@@ -52,64 +65,69 @@ | |||
52 | </ng-template> | 65 | </ng-template> |
53 | </ng-container> | 66 | </ng-container> |
54 | </div> | 67 | </div> |
68 | |||
55 | <div [ngbNavOutlet]="resolutionNav"></div> | 69 | <div [ngbNavOutlet]="resolutionNav"></div> |
56 | 70 | ||
57 | <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed"> | 71 | <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed"> |
58 | <ng-container *ngIf="videoFile?.metadata"> | 72 | <div ngbNav #navMetadata="ngbNav" class="nav-tabs nav-metadata"> |
59 | <div ngbNav #nav="ngbNav" class="nav-tabs nav-metadata"> | 73 | <ng-container ngbNavItem> |
60 | <ng-container ngbNavItem> | 74 | <a ngbNavLink i18n>Format</a> |
61 | <a ngbNavLink i18n>Format</a> | 75 | <ng-template ngbNavContent> |
76 | <div class="file-metadata"> | ||
77 | <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataFormat | keyvalue"> | ||
78 | <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> | ||
79 | <span class="metadata-attribute-value">{{ item.value.value }}</span> | ||
80 | </div> | ||
81 | </div> | ||
82 | </ng-template> | ||
83 | |||
84 | <ng-container ngbNavItem [disabled]="videoFileMetadataVideoStream === undefined"> | ||
85 | <a ngbNavLink i18n>Video stream</a> | ||
62 | <ng-template ngbNavContent> | 86 | <ng-template ngbNavContent> |
63 | <div class="file-metadata"> | 87 | <div class="file-metadata"> |
64 | <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataFormat | keyvalue"> | 88 | <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataVideoStream | keyvalue"> |
65 | <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> | 89 | <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> |
66 | <span class="metadata-attribute-value">{{ item.value.value }}</span> | 90 | <span class="metadata-attribute-value">{{ item.value.value }}</span> |
67 | </div> | 91 | </div> |
68 | </div> | 92 | </div> |
69 | </ng-template> | 93 | </ng-template> |
94 | </ng-container> | ||
70 | 95 | ||
71 | <ng-container ngbNavItem [disabled]="videoFileMetadataVideoStream === undefined"> | 96 | <ng-container ngbNavItem [disabled]="videoFileMetadataAudioStream === undefined"> |
72 | <a ngbNavLink i18n>Video stream</a> | 97 | <a ngbNavLink i18n>Audio stream</a> |
73 | <ng-template ngbNavContent> | 98 | <ng-template ngbNavContent> |
74 | <div class="file-metadata"> | 99 | <div class="file-metadata"> |
75 | <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataVideoStream | keyvalue"> | 100 | <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataAudioStream | keyvalue"> |
76 | <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> | 101 | <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> |
77 | <span class="metadata-attribute-value">{{ item.value.value }}</span> | 102 | <span class="metadata-attribute-value">{{ item.value.value }}</span> |
78 | </div> | ||
79 | </div> | ||
80 | </ng-template> | ||
81 | </ng-container> | ||
82 | |||
83 | <ng-container ngbNavItem [disabled]="videoFileMetadataAudioStream === undefined"> | ||
84 | <a ngbNavLink i18n>Audio stream</a> | ||
85 | <ng-template ngbNavContent> | ||
86 | <div class="file-metadata"> | ||
87 | <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataAudioStream | keyvalue"> | ||
88 | <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> | ||
89 | <span class="metadata-attribute-value">{{ item.value.value }}</span> | ||
90 | </div> | ||
91 | </div> | 103 | </div> |
92 | </ng-template> | 104 | </div> |
93 | </ng-container> | 105 | </ng-template> |
94 | |||
95 | </ng-container> | 106 | </ng-container> |
107 | |||
108 | </ng-container> | ||
109 | </div> | ||
110 | |||
111 | <div *ngIf="getFileMetadata()" [ngbNavOutlet]="navMetadata"></div> | ||
112 | |||
113 | <div class="download-type"> | ||
114 | <div class="peertube-radio-container"> | ||
115 | <input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct"> | ||
116 | <label i18n for="download-direct">Direct download</label> | ||
96 | </div> | 117 | </div> |
97 | <div [ngbNavOutlet]="nav"></div> | 118 | |
98 | <div class="download-type"> | 119 | <div class="peertube-radio-container"> |
99 | <div class="peertube-radio-container"> | 120 | <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent"> |
100 | <input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct"> | 121 | <label i18n for="download-torrent">Torrent (.torrent file)</label> |
101 | <label i18n for="download-direct">Direct download</label> | ||
102 | </div> | ||
103 | <div class="peertube-radio-container"> | ||
104 | <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent"> | ||
105 | <label i18n for="download-torrent">Torrent (.torrent file)</label> | ||
106 | </div> | ||
107 | </div> | 122 | </div> |
108 | </ng-container> | 123 | </div> |
109 | </div> | 124 | </div> |
110 | 125 | ||
111 | <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button" | 126 | <div |
112 | [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic"> | 127 | (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" |
128 | role="button" class="advanced-filters-button" | ||
129 | [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic" | ||
130 | > | ||
113 | <ng-container *ngIf="isAdvancedCustomizationCollapsed"> | 131 | <ng-container *ngIf="isAdvancedCustomizationCollapsed"> |
114 | <span class="glyphicon glyphicon-menu-down"></span> | 132 | <span class="glyphicon glyphicon-menu-down"></span> |
115 | 133 | ||
diff --git a/client/src/app/shared/shared-video-miniature/video-download.component.scss b/client/src/app/shared/shared-video-miniature/video-download.component.scss index b0d80e530..f03034571 100644 --- a/client/src/app/shared/shared-video-miniature/video-download.component.scss +++ b/client/src/app/shared/shared-video-miniature/video-download.component.scss | |||
@@ -23,18 +23,12 @@ | |||
23 | } | 23 | } |
24 | } | 24 | } |
25 | 25 | ||
26 | .peertube-select-container { | 26 | .peertube-select-container.title-select { |
27 | @include peertube-select-container(85px); | 27 | @include peertube-select-container(auto); |
28 | 28 | ||
29 | border-top-right-radius: 0; | 29 | display: inline-block; |
30 | border-bottom-right-radius: 0; | 30 | margin-left: 10px; |
31 | border-right: 0; | 31 | vertical-align: top; |
32 | |||
33 | select { | ||
34 | height: inherit; | ||
35 | border-top-left-radius: .2rem; | ||
36 | border-bottom-left-radius: .2rem; | ||
37 | } | ||
38 | } | 32 | } |
39 | 33 | ||
40 | #dropdown-download-type { | 34 | #dropdown-download-type { |
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 1e3745d94..355ce8be3 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 | |||
@@ -1,5 +1,4 @@ | |||
1 | import { mapValues, pick } from 'lodash-es' | 1 | import { mapValues, pick } from 'lodash-es' |
2 | import { pipe } from 'rxjs' | ||
3 | import { tap } from 'rxjs/operators' | 2 | import { tap } from 'rxjs/operators' |
4 | import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' | 3 | import { Component, ElementRef, Inject, LOCALE_ID, ViewChild } from '@angular/core' |
5 | import { AuthService, HooksService, Notifier } from '@app/core' | 4 | import { AuthService, HooksService, Notifier } from '@app/core' |
@@ -19,24 +18,26 @@ export class VideoDownloadComponent { | |||
19 | @ViewChild('modal', { static: true }) modal: ElementRef | 18 | @ViewChild('modal', { static: true }) modal: ElementRef |
20 | 19 | ||
21 | downloadType: 'direct' | 'torrent' = 'direct' | 20 | downloadType: 'direct' | 'torrent' = 'direct' |
21 | |||
22 | resolutionId: number | string = -1 | 22 | resolutionId: number | string = -1 |
23 | subtitleLanguageId: string | 23 | subtitleLanguageId: string |
24 | 24 | ||
25 | video: VideoDetails | ||
26 | videoFile: VideoFile | ||
27 | videoFileMetadataFormat: FileMetadata | 25 | videoFileMetadataFormat: FileMetadata |
28 | videoFileMetadataVideoStream: FileMetadata | undefined | 26 | videoFileMetadataVideoStream: FileMetadata | undefined |
29 | videoFileMetadataAudioStream: FileMetadata | undefined | 27 | videoFileMetadataAudioStream: FileMetadata | undefined |
30 | videoCaptions: VideoCaption[] | ||
31 | activeModal: NgbModalRef | ||
32 | 28 | ||
33 | isAdvancedCustomizationCollapsed = true | 29 | isAdvancedCustomizationCollapsed = true |
34 | 30 | ||
35 | type: DownloadType = 'video' | 31 | type: DownloadType = 'video' |
36 | 32 | ||
33 | private activeModal: NgbModalRef | ||
34 | |||
37 | private bytesPipe: BytesPipe | 35 | private bytesPipe: BytesPipe |
38 | private numbersPipe: NumberFormatterPipe | 36 | private numbersPipe: NumberFormatterPipe |
39 | 37 | ||
38 | private video: VideoDetails | ||
39 | private videoCaptions: VideoCaption[] | ||
40 | |||
40 | constructor ( | 41 | constructor ( |
41 | @Inject(LOCALE_ID) private localeId: string, | 42 | @Inject(LOCALE_ID) private localeId: string, |
42 | private notifier: Notifier, | 43 | private notifier: Notifier, |
@@ -61,15 +62,25 @@ export class VideoDownloadComponent { | |||
61 | return this.video.getFiles() | 62 | return this.video.getFiles() |
62 | } | 63 | } |
63 | 64 | ||
65 | getCaptions () { | ||
66 | if (!this.videoCaptions) return [] | ||
67 | |||
68 | return this.videoCaptions | ||
69 | } | ||
70 | |||
64 | show (video: VideoDetails, videoCaptions?: VideoCaption[]) { | 71 | show (video: VideoDetails, videoCaptions?: VideoCaption[]) { |
65 | this.video = video | 72 | this.video = video |
66 | this.videoCaptions = videoCaptions && videoCaptions.length ? videoCaptions : undefined | 73 | this.videoCaptions = videoCaptions |
67 | 74 | ||
68 | this.activeModal = this.modalService.open(this.modal, { centered: true }) | 75 | this.activeModal = this.modalService.open(this.modal, { centered: true }) |
69 | 76 | ||
70 | this.onResolutionIdChange(this.getVideoFiles()[0].resolution.id) | 77 | if (this.hasFiles()) { |
78 | this.onResolutionIdChange(this.getVideoFiles()[0].resolution.id) | ||
79 | } | ||
71 | 80 | ||
72 | if (this.videoCaptions) this.subtitleLanguageId = this.videoCaptions[0].language.id | 81 | if (this.hasCaptions()) { |
82 | this.subtitleLanguageId = this.videoCaptions[0].language.id | ||
83 | } | ||
73 | 84 | ||
74 | this.activeModal.shown.subscribe(() => { | 85 | this.activeModal.shown.subscribe(() => { |
75 | this.hooks.runAction('action:modal.video-download.shown', 'common') | 86 | this.hooks.runAction('action:modal.video-download.shown', 'common') |
@@ -83,48 +94,63 @@ export class VideoDownloadComponent { | |||
83 | 94 | ||
84 | download () { | 95 | download () { |
85 | window.location.assign(this.getLink()) | 96 | window.location.assign(this.getLink()) |
97 | |||
86 | this.activeModal.close() | 98 | this.activeModal.close() |
87 | } | 99 | } |
88 | 100 | ||
89 | getLink () { | 101 | getLink () { |
90 | return this.type === 'subtitles' && this.videoCaptions | 102 | return this.type === 'subtitles' && this.videoCaptions |
91 | ? this.getSubtitlesLink() | 103 | ? this.getCaptionLink() |
92 | : this.getVideoFileLink() | 104 | : this.getVideoFileLink() |
93 | } | 105 | } |
94 | 106 | ||
95 | async onResolutionIdChange (resolutionId: number) { | 107 | async onResolutionIdChange (resolutionId: number) { |
96 | this.resolutionId = resolutionId | 108 | this.resolutionId = resolutionId |
97 | this.videoFile = this.getVideoFile() | ||
98 | 109 | ||
99 | if (!this.videoFile.metadata) { | 110 | const videoFile = this.getVideoFile() |
100 | if (!this.videoFile.metadataUrl) return | 111 | |
112 | if (!videoFile.metadata) { | ||
113 | if (!videoFile.metadataUrl) return | ||
101 | 114 | ||
102 | await this.hydrateMetadataFromMetadataUrl(this.videoFile) | 115 | await this.hydrateMetadataFromMetadataUrl(videoFile) |
103 | } | 116 | } |
104 | 117 | ||
105 | this.videoFileMetadataFormat = this.videoFile | 118 | if (!videoFile.metadata) return |
106 | ? this.getMetadataFormat(this.videoFile.metadata.format) | 119 | |
120 | this.videoFileMetadataFormat = videoFile | ||
121 | ? this.getMetadataFormat(videoFile.metadata.format) | ||
107 | : undefined | 122 | : undefined |
108 | this.videoFileMetadataVideoStream = this.videoFile | 123 | this.videoFileMetadataVideoStream = videoFile |
109 | ? this.getMetadataStream(this.videoFile.metadata.streams, 'video') | 124 | ? this.getMetadataStream(videoFile.metadata.streams, 'video') |
110 | : undefined | 125 | : undefined |
111 | this.videoFileMetadataAudioStream = this.videoFile | 126 | this.videoFileMetadataAudioStream = videoFile |
112 | ? this.getMetadataStream(this.videoFile.metadata.streams, 'audio') | 127 | ? this.getMetadataStream(videoFile.metadata.streams, 'audio') |
113 | : undefined | 128 | : undefined |
114 | } | 129 | } |
115 | 130 | ||
131 | onSubtitleIdChange (subtitleId: string) { | ||
132 | this.subtitleLanguageId = subtitleId | ||
133 | } | ||
134 | |||
135 | hasFiles () { | ||
136 | return this.getVideoFiles().length !== 0 | ||
137 | } | ||
138 | |||
116 | getVideoFile () { | 139 | getVideoFile () { |
117 | const file = this.getVideoFiles().find(f => f.resolution.id === this.resolutionId) | 140 | const file = this.getVideoFiles() |
141 | .find(f => f.resolution.id === this.resolutionId) | ||
142 | |||
118 | if (!file) { | 143 | if (!file) { |
119 | console.error('Could not find file with resolution %d.', this.resolutionId) | 144 | console.error('Could not find file with resolution %d.', this.resolutionId) |
120 | return | 145 | return undefined |
121 | } | 146 | } |
147 | |||
122 | return file | 148 | return file |
123 | } | 149 | } |
124 | 150 | ||
125 | getVideoFileLink () { | 151 | getVideoFileLink () { |
126 | const file = this.videoFile | 152 | const file = this.getVideoFile() |
127 | if (!file) return | 153 | if (!file) return '' |
128 | 154 | ||
129 | const suffix = this.isConfidentialVideo() | 155 | const suffix = this.isConfidentialVideo() |
130 | ? '?access_token=' + this.auth.getAccessToken() | 156 | ? '?access_token=' + this.auth.getAccessToken() |
@@ -139,12 +165,31 @@ export class VideoDownloadComponent { | |||
139 | } | 165 | } |
140 | } | 166 | } |
141 | 167 | ||
142 | isConfidentialVideo () { | 168 | hasCaptions () { |
143 | return this.video.privacy.id === VideoPrivacy.PRIVATE || this.video.privacy.id === VideoPrivacy.INTERNAL | 169 | return this.getCaptions().length !== 0 |
170 | } | ||
171 | |||
172 | getCaption () { | ||
173 | const caption = this.getCaptions() | ||
174 | .find(c => c.language.id === this.subtitleLanguageId) | ||
175 | |||
176 | if (!caption) { | ||
177 | console.error('Cannot find caption %s.', this.subtitleLanguageId) | ||
178 | return undefined | ||
179 | } | ||
180 | |||
181 | return caption | ||
144 | } | 182 | } |
145 | 183 | ||
146 | getSubtitlesLink () { | 184 | getCaptionLink () { |
147 | return window.location.origin + this.videoCaptions.find(caption => caption.language.id === this.subtitleLanguageId).captionPath | 185 | const caption = this.getCaption() |
186 | if (!caption) return '' | ||
187 | |||
188 | return window.location.origin + caption.captionPath | ||
189 | } | ||
190 | |||
191 | isConfidentialVideo () { | ||
192 | return this.video.privacy.id === VideoPrivacy.PRIVATE || this.video.privacy.id === VideoPrivacy.INTERNAL | ||
148 | } | 193 | } |
149 | 194 | ||
150 | activateCopiedMessage () { | 195 | activateCopiedMessage () { |
@@ -155,7 +200,14 @@ export class VideoDownloadComponent { | |||
155 | this.type = type | 200 | this.type = type |
156 | } | 201 | } |
157 | 202 | ||
158 | getMetadataFormat (format: any) { | 203 | getFileMetadata () { |
204 | const file = this.getVideoFile() | ||
205 | if (!file) return undefined | ||
206 | |||
207 | return file.metadata | ||
208 | } | ||
209 | |||
210 | private getMetadataFormat (format: any) { | ||
159 | const keyToTranslateFunction = { | 211 | const keyToTranslateFunction = { |
160 | 'encoder': (value: string) => ({ label: $localize`Encoder`, value }), | 212 | 'encoder': (value: string) => ({ label: $localize`Encoder`, value }), |
161 | 'format_long_name': (value: string) => ({ label: $localize`Format name`, value }), | 213 | 'format_long_name': (value: string) => ({ label: $localize`Format name`, value }), |
@@ -176,7 +228,7 @@ export class VideoDownloadComponent { | |||
176 | ) | 228 | ) |
177 | } | 229 | } |
178 | 230 | ||
179 | getMetadataStream (streams: any[], type: 'video' | 'audio') { | 231 | private getMetadataStream (streams: any[], type: 'video' | 'audio') { |
180 | const stream = streams.find(s => s.codec_type === type) | 232 | const stream = streams.find(s => s.codec_type === type) |
181 | if (!stream) return undefined | 233 | if (!stream) return undefined |
182 | 234 | ||