aboutsummaryrefslogtreecommitdiffhomepage
path: root/client/src/app
diff options
context:
space:
mode:
Diffstat (limited to 'client/src/app')
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.html147
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.scss37
-rw-r--r--client/src/app/shared/shared-video-miniature/video-download.component.ts19
3 files changed, 135 insertions, 68 deletions
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 0e659fbe2..8a9218343 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
@@ -17,22 +17,12 @@
17 </div> 17 </div>
18 18
19 <div class="modal-body"> 19 <div class="modal-body">
20 <div class="form-group"> 20 <div class="alert alert-warning" *ngIf="isConfidentialVideo()" i18n>
21 <div class="alert alert-warning" *ngIf="isConfidentialVideo()" i18n> 21 The following link contains a private token and should not be shared with anyone.
22 The following link contains a private token and should not be shared with anyone. 22 </div>
23 </div>
24 23
24 <ng-container *ngIf="type === 'subtitles'">
25 <div class="input-group input-group-sm"> 25 <div class="input-group input-group-sm">
26 <div class="input-group-prepend peertube-select-container">
27 <select *ngIf="type === 'video'" [(ngModel)]="resolutionId" (ngModelChange)="onResolutionIdChange()">
28 <option *ngFor="let file of getVideoFiles()" [value]="file.resolution.id">{{ file.resolution.label }}</option>
29 </select>
30
31 <select *ngIf="type === 'subtitles'" [(ngModel)]="subtitleLanguageId">
32 <option *ngFor="let caption of videoCaptions" [value]="caption.language.id">{{ caption.language.label }}</option>
33 </select>
34 </div>
35
36 <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" /> 26 <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" />
37 <div class="input-group-append" *ngIf="!isConfidentialVideo()"> 27 <div class="input-group-append" *ngIf="!isConfidentialVideo()">
38 <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary"> 28 <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
@@ -40,62 +30,103 @@
40 </button> 30 </button>
41 </div> 31 </div>
42 </div> 32 </div>
43 </div> 33 </ng-container>
44 34
45 <ng-container *ngIf="type === 'video' && videoFile?.metadata"> 35 <ng-container *ngIf="type === 'video'">
46 <div ngbNav #nav="ngbNav" class="nav-tabs"> 36 <div ngbNav #resolutionNav="ngbNav" class="nav-tabs" [activeId]="resolutionId" (activeIdChange)="onResolutionIdChange($event)">
47 37
48 <ng-container ngbNavItem> 38 <ng-container *ngFor="let file of getVideoFiles()" [ngbNavItem]="file.resolution.id">
49 <a ngbNavLink i18n>Format</a> 39 <a ngbNavLink i18n>{{ file.resolution.label }}</a>
40
50 <ng-template ngbNavContent> 41 <ng-template ngbNavContent>
51 <div class="file-metadata"> 42 <div class="nav-content">
52 <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataFormat | keyvalue"> 43 <div class="input-group input-group-sm">
53 <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> 44 <input #urlInput (click)="urlInput.select()" type="text" class="form-control input-sm readonly" readonly [value]="getLink()" />
54 <span class="metadata-attribute-value">{{ item.value.value }}</span> 45 <div class="input-group-append" *ngIf="!isConfidentialVideo()">
46 <button [cdkCopyToClipboard]="urlInput.value" (click)="activateCopiedMessage()" type="button" class="btn btn-outline-secondary">
47 <span class="glyphicon glyphicon-duplicate"></span>
48 </button>
49 </div>
55 </div> 50 </div>
56 </div> 51 </div>
57 </ng-template> 52 </ng-template>
58 </ng-container> 53 </ng-container>
59 54 </div>
60 <ng-container ngbNavItem [disabled]="videoFileMetadataVideoStream === undefined"> 55 <div [ngbNavOutlet]="resolutionNav"></div>
61 <a ngbNavLink i18n>Video stream</a> 56
62 <ng-template ngbNavContent> 57 <div class="advanced-filters collapse-transition" [ngbCollapse]="isAdvancedCustomizationCollapsed">
63 <div class="file-metadata"> 58 <ng-container *ngIf="videoFile?.metadata">
64 <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataVideoStream | keyvalue"> 59 <div ngbNav #nav="ngbNav" class="nav-tabs nav-metadata">
65 <span i18n class="metadata-attribute-label">{{ item.value.label }}</span> 60 <ng-container ngbNavItem>
66 <span class="metadata-attribute-value">{{ item.value.value }}</span> 61 <a ngbNavLink i18n>Format</a>
67 </div> 62 <ng-template ngbNavContent>
63 <div class="file-metadata">
64 <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataFormat | keyvalue">
65 <span i18n class="metadata-attribute-label">{{ item.value.label }}</span>
66 <span class="metadata-attribute-value">{{ item.value.value }}</span>
67 </div>
68 </div>
69 </ng-template>
70
71 <ng-container ngbNavItem [disabled]="videoFileMetadataVideoStream === undefined">
72 <a ngbNavLink i18n>Video stream</a>
73 <ng-template ngbNavContent>
74 <div class="file-metadata">
75 <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataVideoStream | keyvalue">
76 <span i18n class="metadata-attribute-label">{{ item.value.label }}</span>
77 <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>
92 </ng-template>
93 </ng-container>
94
95 </ng-container>
96 </div>
97 <div [ngbNavOutlet]="nav"></div>
98 <div class="download-type">
99 <div class="peertube-radio-container">
100 <input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct">
101 <label i18n for="download-direct">Direct download</label>
68 </div> 102 </div>
69 </ng-template> 103 <div class="peertube-radio-container">
70 </ng-container> 104 <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent">
71 105 <label i18n for="download-torrent">Torrent (.torrent file)</label>
72 <ng-container ngbNavItem [disabled]="videoFileMetadataAudioStream === undefined">
73 <a ngbNavLink i18n>Audio stream</a>
74 <ng-template ngbNavContent>
75 <div class="file-metadata">
76 <div class="metadata-attribute metadata-attribute-tags" *ngFor="let item of videoFileMetadataAudioStream | keyvalue">
77 <span i18n class="metadata-attribute-label">{{ item.value.label }}</span>
78 <span class="metadata-attribute-value">{{ item.value.value }}</span>
79 </div>
80 </div> 106 </div>
81 </ng-template> 107 </div>
82 </ng-container> 108 </ng-container>
83 </div> 109 </div>
84 110
85 <div [ngbNavOutlet]="nav"></div> 111 <div (click)="isAdvancedCustomizationCollapsed = !isAdvancedCustomizationCollapsed" role="button" class="advanced-filters-button"
86 </ng-container> 112 [attr.aria-expanded]="!isAdvancedCustomizationCollapsed" aria-controls="collapseBasic">
87 113 <ng-container *ngIf="isAdvancedCustomizationCollapsed">
88 <div class="download-type" *ngIf="type === 'video'"> 114 <span class="glyphicon glyphicon-menu-down"></span>
89 <div class="peertube-radio-container"> 115
90 <input type="radio" name="download" id="download-direct" [(ngModel)]="downloadType" value="direct"> 116 <ng-container i18n>
91 <label i18n for="download-direct">Direct download</label> 117 Advanced
92 </div> 118 </ng-container>
93 119 </ng-container>
94 <div class="peertube-radio-container"> 120
95 <input type="radio" name="download" id="download-torrent" [(ngModel)]="downloadType" value="torrent"> 121 <ng-container *ngIf="!isAdvancedCustomizationCollapsed">
96 <label i18n for="download-torrent">Torrent (.torrent file)</label> 122 <span class="glyphicon glyphicon-menu-up"></span>
123
124 <ng-container i18n>
125 Simple
126 </ng-container>
127 </ng-container>
97 </div> 128 </div>
98 </div> 129 </ng-container>
99 </div> 130 </div>
100 131
101 <div class="modal-footer inputs"> 132 <div class="modal-footer inputs">
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 d407e9531..199c3dac8 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
@@ -1,6 +1,28 @@
1@import 'variables'; 1@import 'variables';
2@import 'mixins'; 2@import 'mixins';
3 3
4.nav-content {
5 margin-top: 30px;
6}
7
8.advanced-filters-button {
9 display: flex;
10 justify-content: center;
11 align-items: center;
12 margin-top: 20px;
13 font-size: 16px;
14 font-weight: 600;
15 cursor: pointer;
16
17 .nav-tabs {
18 margin-top: 10x;
19 }
20
21 .glyphicon {
22 margin-right: 5px;
23 }
24}
25
4.peertube-select-container { 26.peertube-select-container {
5 @include peertube-select-container(85px); 27 @include peertube-select-container(85px);
6 28
@@ -15,12 +37,21 @@
15 } 37 }
16} 38}
17 39
40.action-button-cancel {
41 @include peertube-button-link;
42}
43
44.action-button-submit {
45 @include peertube-button-link;
46 @include orange-button;
47}
48
18#dropdownDownloadType { 49#dropdownDownloadType {
19 cursor: pointer; 50 cursor: pointer;
20} 51}
21 52
22.download-type { 53.download-type {
23 margin-top: 30px; 54 margin-top: 20px;
24 55
25 .peertube-radio-container { 56 .peertube-radio-container {
26 @include peertube-radio-container; 57 @include peertube-radio-container;
@@ -30,6 +61,10 @@
30 } 61 }
31} 62}
32 63
64.nav-metadata {
65 margin-top: 20px;
66}
67
33.file-metadata { 68.file-metadata {
34 padding: 1rem; 69 padding: 1rem;
35} 70}
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 e0b7b51ff..1e3745d94 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
@@ -30,6 +30,8 @@ export class VideoDownloadComponent {
30 videoCaptions: VideoCaption[] 30 videoCaptions: VideoCaption[]
31 activeModal: NgbModalRef 31 activeModal: NgbModalRef
32 32
33 isAdvancedCustomizationCollapsed = true
34
33 type: DownloadType = 'video' 35 type: DownloadType = 'video'
34 36
35 private bytesPipe: BytesPipe 37 private bytesPipe: BytesPipe
@@ -65,8 +67,7 @@ export class VideoDownloadComponent {
65 67
66 this.activeModal = this.modalService.open(this.modal, { centered: true }) 68 this.activeModal = this.modalService.open(this.modal, { centered: true })
67 69
68 this.resolutionId = this.getVideoFiles()[0].resolution.id 70 this.onResolutionIdChange(this.getVideoFiles()[0].resolution.id)
69 this.onResolutionIdChange()
70 71
71 if (this.videoCaptions) this.subtitleLanguageId = this.videoCaptions[0].language.id 72 if (this.videoCaptions) this.subtitleLanguageId = this.videoCaptions[0].language.id
72 73
@@ -91,12 +92,15 @@ export class VideoDownloadComponent {
91 : this.getVideoFileLink() 92 : this.getVideoFileLink()
92 } 93 }
93 94
94 async onResolutionIdChange () { 95 async onResolutionIdChange (resolutionId: number) {
96 this.resolutionId = resolutionId
95 this.videoFile = this.getVideoFile() 97 this.videoFile = this.getVideoFile()
96 if (this.videoFile.metadata || !this.videoFile.metadataUrl) return
97 98
98 await this.hydrateMetadataFromMetadataUrl(this.videoFile) 99 if (!this.videoFile.metadata) {
99 if (!this.videoFile.metadata) return 100 if (!this.videoFile.metadataUrl) return
101
102 await this.hydrateMetadataFromMetadataUrl(this.videoFile)
103 }
100 104
101 this.videoFileMetadataFormat = this.videoFile 105 this.videoFileMetadataFormat = this.videoFile
102 ? this.getMetadataFormat(this.videoFile.metadata.format) 106 ? this.getMetadataFormat(this.videoFile.metadata.format)
@@ -110,9 +114,6 @@ export class VideoDownloadComponent {
110 } 114 }
111 115
112 getVideoFile () { 116 getVideoFile () {
113 // HTML select send us a string, so convert it to a number
114 this.resolutionId = parseInt(this.resolutionId.toString(), 10)
115
116 const file = this.getVideoFiles().find(f => f.resolution.id === this.resolutionId) 117 const file = this.getVideoFiles().find(f => f.resolution.id === this.resolutionId)
117 if (!file) { 118 if (!file) {
118 console.error('Could not find file with resolution %d.', this.resolutionId) 119 console.error('Could not find file with resolution %d.', this.resolutionId)