diff options
Diffstat (limited to 'client/src/app')
9 files changed, 105 insertions, 28 deletions
diff --git a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts index 3242bcf46..422d873c0 100644 --- a/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts +++ b/client/src/app/+admin/moderation/video-block-list/video-block-list.component.ts | |||
@@ -7,7 +7,7 @@ import { DropdownAction, Video, VideoService } from '@app/shared/shared-main' | |||
7 | import { VideoBlockService } from '@app/shared/shared-moderation' | 7 | import { VideoBlockService } from '@app/shared/shared-moderation' |
8 | import { I18n } from '@ngx-translate/i18n-polyfill' | 8 | import { I18n } from '@ngx-translate/i18n-polyfill' |
9 | import { VideoBlacklist, VideoBlacklistType } from '@shared/models' | 9 | import { VideoBlacklist, VideoBlacklistType } from '@shared/models' |
10 | import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' | 10 | import { buildVideoOrPlaylistEmbed, buildVideoLink } from 'src/assets/player/utils' |
11 | import { environment } from 'src/environments/environment' | 11 | import { environment } from 'src/environments/environment' |
12 | import { DomSanitizer } from '@angular/platform-browser' | 12 | import { DomSanitizer } from '@angular/platform-browser' |
13 | 13 | ||
@@ -176,7 +176,7 @@ export class VideoBlockListComponent extends RestTable implements OnInit, AfterV | |||
176 | } | 176 | } |
177 | 177 | ||
178 | getVideoEmbed (entry: VideoBlacklist) { | 178 | getVideoEmbed (entry: VideoBlacklist) { |
179 | return buildVideoEmbed( | 179 | return buildVideoOrPlaylistEmbed( |
180 | buildVideoLink({ | 180 | buildVideoLink({ |
181 | baseUrl: `${environment.embedUrl}/videos/embed/${entry.video.uuid}`, | 181 | baseUrl: `${environment.embedUrl}/videos/embed/${entry.video.uuid}`, |
182 | title: false, | 182 | title: false, |
diff --git a/client/src/app/+videos/+video-watch/comment/video-comment.component.ts b/client/src/app/+videos/+video-watch/comment/video-comment.component.ts index 6744a0954..36ec6e9f9 100644 --- a/client/src/app/+videos/+video-watch/comment/video-comment.component.ts +++ b/client/src/app/+videos/+video-watch/comment/video-comment.component.ts | |||
@@ -135,7 +135,7 @@ export class VideoCommentComponent implements OnInit, OnChanges { | |||
135 | this.comment.account = null | 135 | this.comment.account = null |
136 | } | 136 | } |
137 | 137 | ||
138 | if (this.isUserLoggedIn() && this.authService.getUser().account.id !== this.comment.account.id) { | 138 | if (this.isUserLoggedIn() && this.comment.isDeleted === false && this.authService.getUser().account.id !== this.comment.account.id) { |
139 | this.prependModerationActions = [ | 139 | this.prependModerationActions = [ |
140 | { | 140 | { |
141 | label: this.i18n('Report comment'), | 141 | label: this.i18n('Report comment'), |
diff --git a/client/src/app/+videos/+video-watch/modal/video-share.component.html b/client/src/app/+videos/+video-watch/modal/video-share.component.html index 5e6a2d518..946e8d8ca 100644 --- a/client/src/app/+videos/+video-watch/modal/video-share.component.html +++ b/client/src/app/+videos/+video-watch/modal/video-share.component.html | |||
@@ -6,18 +6,56 @@ | |||
6 | 6 | ||
7 | 7 | ||
8 | <div class="modal-body"> | 8 | <div class="modal-body"> |
9 | |||
9 | <div class="playlist" *ngIf="hasPlaylist()"> | 10 | <div class="playlist" *ngIf="hasPlaylist()"> |
10 | <div class="title-page title-page-single" i18n>Share the playlist</div> | 11 | <div class="title-page title-page-single" i18n>Share the playlist</div> |
11 | 12 | ||
12 | <my-input-readonly-copy [value]="getPlaylistUrl()"></my-input-readonly-copy> | 13 | <div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activePlaylistId"> |
14 | |||
15 | <ng-container ngbNavItem="url"> | ||
16 | <a ngbNavLink i18n>URL</a> | ||
17 | |||
18 | <ng-template ngbNavContent> | ||
19 | <div class="nav-content"> | ||
20 | |||
21 | <my-input-readonly-copy [value]="getPlaylistUrl()"></my-input-readonly-copy> | ||
22 | </div> | ||
23 | </ng-template> | ||
24 | </ng-container> | ||
25 | |||
26 | <ng-container ngbNavItem="qrcode"> | ||
27 | <a ngbNavLink i18n>QR-Code</a> | ||
28 | |||
29 | <ng-template ngbNavContent> | ||
30 | <div class="nav-content"> | ||
31 | <qrcode [qrdata]="getPlaylistUrl()" [size]="256" level="Q"></qrcode> | ||
32 | </div> | ||
33 | </ng-template> | ||
34 | </ng-container> | ||
35 | |||
36 | <ng-container ngbNavItem="embed"> | ||
37 | <a ngbNavLink i18n>Embed</a> | ||
38 | |||
39 | <ng-template ngbNavContent> | ||
40 | <div class="nav-content"> | ||
41 | <my-input-readonly-copy [value]="getPlaylistIframeCode()"></my-input-readonly-copy> | ||
42 | |||
43 | <div i18n *ngIf="notSecure()" class="alert alert-warning"> | ||
44 | The url is not secured (no HTTPS), so the embed video won't work on HTTPS websites (web browsers block non secured HTTP requests on HTTPS websites). | ||
45 | </div> | ||
46 | </div> | ||
47 | </ng-template> | ||
48 | </ng-container> | ||
49 | |||
50 | </div> | ||
51 | |||
52 | <div [ngbNavOutlet]="nav"></div> | ||
13 | 53 | ||
14 | <div class="filters"> | 54 | <div class="filters"> |
15 | 55 | ||
16 | <div class="form-group"> | 56 | <div class="form-group"> |
17 | <my-peertube-checkbox | 57 | <my-peertube-checkbox inputName="includeVideoInPlaylist" [(ngModel)]="includeVideoInPlaylist" i18n-labelText |
18 | inputName="includeVideoInPlaylist" [(ngModel)]="includeVideoInPlaylist" | 58 | labelText="Share the playlist at this video position"></my-peertube-checkbox> |
19 | i18n-labelText labelText="Share the playlist at this video position" | ||
20 | ></my-peertube-checkbox> | ||
21 | </div> | 59 | </div> |
22 | 60 | ||
23 | </div> | 61 | </div> |
@@ -27,7 +65,7 @@ | |||
27 | <div class="video"> | 65 | <div class="video"> |
28 | <div class="title-page title-page-single" *ngIf="hasPlaylist()" i18n>Share the video</div> | 66 | <div class="title-page title-page-single" *ngIf="hasPlaylist()" i18n>Share the video</div> |
29 | 67 | ||
30 | <div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activeId"> | 68 | <div ngbNav #nav="ngbNav" class="nav-tabs" [(activeId)]="activeVideoId"> |
31 | 69 | ||
32 | <ng-container ngbNavItem="url"> | 70 | <ng-container ngbNavItem="url"> |
33 | <a ngbNavLink i18n>URL</a> | 71 | <a ngbNavLink i18n>URL</a> |
@@ -137,7 +175,7 @@ | |||
137 | </div> | 175 | </div> |
138 | </div> | 176 | </div> |
139 | 177 | ||
140 | <ng-container *ngIf="isInEmbedTab()"> | 178 | <ng-container *ngIf="isVideoInEmbedTab()"> |
141 | <div class="form-group"> | 179 | <div class="form-group"> |
142 | <my-peertube-checkbox | 180 | <my-peertube-checkbox |
143 | inputName="title" [(ngModel)]="customizations.title" | 181 | inputName="title" [(ngModel)]="customizations.title" |
@@ -158,6 +196,13 @@ | |||
158 | i18n-labelText labelText="Display player controls" | 196 | i18n-labelText labelText="Display player controls" |
159 | ></my-peertube-checkbox> | 197 | ></my-peertube-checkbox> |
160 | </div> | 198 | </div> |
199 | |||
200 | <div class="form-group"> | ||
201 | <my-peertube-checkbox | ||
202 | inputName="controls" [(ngModel)]="customizations.peertubeLink" | ||
203 | i18n-labelText labelText="Display PeerTube button link" | ||
204 | ></my-peertube-checkbox> | ||
205 | </div> | ||
161 | </ng-container> | 206 | </ng-container> |
162 | </div> | 207 | </div> |
163 | 208 | ||
diff --git a/client/src/app/+videos/+video-watch/modal/video-share.component.ts b/client/src/app/+videos/+video-watch/modal/video-share.component.ts index b42b775c1..d9171fe0e 100644 --- a/client/src/app/+videos/+video-watch/modal/video-share.component.ts +++ b/client/src/app/+videos/+video-watch/modal/video-share.component.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { Component, ElementRef, Input, ViewChild } from '@angular/core' | 1 | import { Component, ElementRef, Input, ViewChild } from '@angular/core' |
2 | import { buildVideoEmbed, buildVideoLink } from '../../../../assets/player/utils' | 2 | import { buildVideoOrPlaylistEmbed, buildVideoLink, buildPlaylistLink } from '../../../../assets/player/utils' |
3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 3 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
4 | import { VideoCaption } from '@shared/models' | 4 | import { VideoCaption } from '@shared/models' |
5 | import { VideoDetails } from '@app/shared/shared-main' | 5 | import { VideoDetails } from '@app/shared/shared-main' |
@@ -21,8 +21,11 @@ type Customizations = { | |||
21 | title: boolean | 21 | title: boolean |
22 | warningTitle: boolean | 22 | warningTitle: boolean |
23 | controls: boolean | 23 | controls: boolean |
24 | peertubeLink: boolean | ||
24 | } | 25 | } |
25 | 26 | ||
27 | type TabId = 'url' | 'qrcode' | 'embed' | ||
28 | |||
26 | @Component({ | 29 | @Component({ |
27 | selector: 'my-video-share', | 30 | selector: 'my-video-share', |
28 | templateUrl: './video-share.component.html', | 31 | templateUrl: './video-share.component.html', |
@@ -35,14 +38,18 @@ export class VideoShareComponent { | |||
35 | @Input() videoCaptions: VideoCaption[] = [] | 38 | @Input() videoCaptions: VideoCaption[] = [] |
36 | @Input() playlist: VideoPlaylist = null | 39 | @Input() playlist: VideoPlaylist = null |
37 | 40 | ||
38 | activeId: 'url' | 'qrcode' | 'embed' = 'url' | 41 | activeVideoId: TabId = 'url' |
42 | activePlaylistId: TabId = 'url' | ||
43 | |||
39 | customizations: Customizations | 44 | customizations: Customizations |
40 | isAdvancedCustomizationCollapsed = true | 45 | isAdvancedCustomizationCollapsed = true |
41 | includeVideoInPlaylist = false | 46 | includeVideoInPlaylist = false |
42 | 47 | ||
48 | private playlistPosition: number = null | ||
49 | |||
43 | constructor (private modalService: NgbModal) { } | 50 | constructor (private modalService: NgbModal) { } |
44 | 51 | ||
45 | show (currentVideoTimestamp?: number) { | 52 | show (currentVideoTimestamp?: number, currentPlaylistPosition?: number) { |
46 | let subtitle: string | 53 | let subtitle: string |
47 | if (this.videoCaptions.length !== 0) { | 54 | if (this.videoCaptions.length !== 0) { |
48 | subtitle = this.videoCaptions[0].language.id | 55 | subtitle = this.videoCaptions[0].language.id |
@@ -65,22 +72,32 @@ export class VideoShareComponent { | |||
65 | // Embed options | 72 | // Embed options |
66 | title: true, | 73 | title: true, |
67 | warningTitle: true, | 74 | warningTitle: true, |
68 | controls: true | 75 | controls: true, |
76 | peertubeLink: true | ||
69 | } | 77 | } |
70 | 78 | ||
79 | this.playlistPosition = currentPlaylistPosition | ||
80 | |||
71 | this.modalService.open(this.modal, { centered: true }) | 81 | this.modalService.open(this.modal, { centered: true }) |
72 | } | 82 | } |
73 | 83 | ||
74 | getVideoIframeCode () { | 84 | getVideoIframeCode () { |
75 | const options = this.getOptions(this.video.embedUrl) | 85 | const options = this.getVideoOptions(this.video.embedUrl) |
76 | 86 | ||
77 | const embedUrl = buildVideoLink(options) | 87 | const embedUrl = buildVideoLink(options) |
78 | return buildVideoEmbed(embedUrl) | 88 | return buildVideoOrPlaylistEmbed(embedUrl) |
89 | } | ||
90 | |||
91 | getPlaylistIframeCode () { | ||
92 | const options = this.getPlaylistOptions(this.playlist.embedUrl) | ||
93 | |||
94 | const embedUrl = buildPlaylistLink(options) | ||
95 | return buildVideoOrPlaylistEmbed(embedUrl) | ||
79 | } | 96 | } |
80 | 97 | ||
81 | getVideoUrl () { | 98 | getVideoUrl () { |
82 | const baseUrl = window.location.origin + '/videos/watch/' + this.video.uuid | 99 | const baseUrl = window.location.origin + '/videos/watch/' + this.video.uuid |
83 | const options = this.getOptions(baseUrl) | 100 | const options = this.getVideoOptions(baseUrl) |
84 | 101 | ||
85 | return buildVideoLink(options) | 102 | return buildVideoLink(options) |
86 | } | 103 | } |
@@ -97,15 +114,23 @@ export class VideoShareComponent { | |||
97 | return window.location.protocol === 'http:' | 114 | return window.location.protocol === 'http:' |
98 | } | 115 | } |
99 | 116 | ||
100 | isInEmbedTab () { | 117 | isVideoInEmbedTab () { |
101 | return this.activeId === 'embed' | 118 | return this.activeVideoId === 'embed' |
102 | } | 119 | } |
103 | 120 | ||
104 | hasPlaylist () { | 121 | hasPlaylist () { |
105 | return !!this.playlist | 122 | return !!this.playlist |
106 | } | 123 | } |
107 | 124 | ||
108 | private getOptions (baseUrl?: string) { | 125 | private getPlaylistOptions (baseUrl?: string) { |
126 | return { | ||
127 | baseUrl, | ||
128 | |||
129 | playlistPosition: this.playlistPosition || undefined | ||
130 | } | ||
131 | } | ||
132 | |||
133 | private getVideoOptions (baseUrl?: string) { | ||
109 | return { | 134 | return { |
110 | baseUrl, | 135 | baseUrl, |
111 | 136 | ||
@@ -120,7 +145,8 @@ export class VideoShareComponent { | |||
120 | 145 | ||
121 | title: this.customizations.title, | 146 | title: this.customizations.title, |
122 | warningTitle: this.customizations.warningTitle, | 147 | warningTitle: this.customizations.warningTitle, |
123 | controls: this.customizations.controls | 148 | controls: this.customizations.controls, |
149 | peertubeLink: this.customizations.peertubeLink | ||
124 | } | 150 | } |
125 | } | 151 | } |
126 | } | 152 | } |
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 dfe73d14d..d8136ab4f 100644 --- a/client/src/app/+videos/+video-watch/video-watch.component.ts +++ b/client/src/app/+videos/+video-watch/video-watch.component.ts | |||
@@ -244,7 +244,7 @@ export class VideoWatchComponent implements OnInit, OnDestroy { | |||
244 | showShareModal () { | 244 | showShareModal () { |
245 | this.pausePlayer() | 245 | this.pausePlayer() |
246 | 246 | ||
247 | this.videoShareModal.show(this.currentTime) | 247 | this.videoShareModal.show(this.currentTime, this.videoWatchPlaylist.currentPlaylistPosition) |
248 | } | 248 | } |
249 | 249 | ||
250 | isUserLoggedIn () { | 250 | isUserLoggedIn () { |
diff --git a/client/src/app/app.component.html b/client/src/app/app.component.html index b66c9afde..9a8a8e14f 100644 --- a/client/src/app/app.component.html +++ b/client/src/app/app.component.html | |||
@@ -41,7 +41,7 @@ | |||
41 | </div> | 41 | </div> |
42 | </div> | 42 | </div> |
43 | 43 | ||
44 | <ngx-loading-bar [includeSpinner]="false"></ngx-loading-bar> | 44 | <ngx-loading-bar [includeSpinner]="false" color="var(--mainColor)"></ngx-loading-bar> |
45 | 45 | ||
46 | <my-confirm></my-confirm> | 46 | <my-confirm></my-confirm> |
47 | 47 | ||
diff --git a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts index 21d2ea47d..c7dc5f4d2 100644 --- a/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts +++ b/client/src/app/shared/shared-abuse-list/abuse-list-table.component.ts | |||
@@ -1,7 +1,7 @@ | |||
1 | import * as debug from 'debug' | 1 | import * as debug from 'debug' |
2 | import truncate from 'lodash-es/truncate' | 2 | import truncate from 'lodash-es/truncate' |
3 | import { SortMeta } from 'primeng/api' | 3 | import { SortMeta } from 'primeng/api' |
4 | import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' | 4 | import { buildVideoOrPlaylistEmbed, buildVideoLink } from 'src/assets/player/utils' |
5 | import { environment } from 'src/environments/environment' | 5 | import { environment } from 'src/environments/environment' |
6 | import { AfterViewInit, Component, OnInit, ViewChild, Input } from '@angular/core' | 6 | import { AfterViewInit, Component, OnInit, ViewChild, Input } from '@angular/core' |
7 | import { DomSanitizer } from '@angular/platform-browser' | 7 | import { DomSanitizer } from '@angular/platform-browser' |
@@ -141,7 +141,7 @@ export class AbuseListTableComponent extends RestTable implements OnInit, AfterV | |||
141 | } | 141 | } |
142 | 142 | ||
143 | getVideoEmbed (abuse: AdminAbuse) { | 143 | getVideoEmbed (abuse: AdminAbuse) { |
144 | return buildVideoEmbed( | 144 | return buildVideoOrPlaylistEmbed( |
145 | buildVideoLink({ | 145 | buildVideoLink({ |
146 | baseUrl: `${environment.embedUrl}/videos/embed/${abuse.video.uuid}`, | 146 | baseUrl: `${environment.embedUrl}/videos/embed/${abuse.video.uuid}`, |
147 | title: false, | 147 | title: false, |
diff --git a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts index 09ab98dfe..794dd54bb 100644 --- a/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts +++ b/client/src/app/shared/shared-moderation/report-modals/video-report.component.ts | |||
@@ -1,5 +1,5 @@ | |||
1 | import { mapValues, pickBy } from 'lodash-es' | 1 | import { mapValues, pickBy } from 'lodash-es' |
2 | import { buildVideoEmbed, buildVideoLink } from 'src/assets/player/utils' | 2 | import { buildVideoOrPlaylistEmbed, buildVideoLink } from 'src/assets/player/utils' |
3 | import { Component, Input, OnInit, ViewChild } from '@angular/core' | 3 | import { Component, Input, OnInit, ViewChild } from '@angular/core' |
4 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser' | 4 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser' |
5 | import { Notifier } from '@app/core' | 5 | import { Notifier } from '@app/core' |
@@ -58,7 +58,7 @@ export class VideoReportComponent extends FormReactive implements OnInit { | |||
58 | 58 | ||
59 | getVideoEmbed () { | 59 | getVideoEmbed () { |
60 | return this.sanitizer.bypassSecurityTrustHtml( | 60 | return this.sanitizer.bypassSecurityTrustHtml( |
61 | buildVideoEmbed( | 61 | buildVideoOrPlaylistEmbed( |
62 | buildVideoLink({ | 62 | buildVideoLink({ |
63 | baseUrl: this.video.embedUrl, | 63 | baseUrl: this.video.embedUrl, |
64 | title: false, | 64 | title: false, |
diff --git a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts index 7de379cdf..3db3b7a2e 100644 --- a/client/src/app/shared/shared-video-playlist/video-playlist.model.ts +++ b/client/src/app/shared/shared-video-playlist/video-playlist.model.ts | |||
@@ -1,4 +1,4 @@ | |||
1 | import { getAbsoluteAPIUrl } from '@app/helpers' | 1 | import { getAbsoluteAPIUrl, getAbsoluteEmbedUrl } from '@app/helpers' |
2 | import { Actor } from '@app/shared/shared-main' | 2 | import { Actor } from '@app/shared/shared-main' |
3 | import { peertubeTranslate } from '@shared/core-utils/i18n' | 3 | import { peertubeTranslate } from '@shared/core-utils/i18n' |
4 | import { | 4 | import { |
@@ -33,6 +33,9 @@ export class VideoPlaylist implements ServerVideoPlaylist { | |||
33 | 33 | ||
34 | thumbnailUrl: string | 34 | thumbnailUrl: string |
35 | 35 | ||
36 | embedPath: string | ||
37 | embedUrl: string | ||
38 | |||
36 | ownerBy: string | 39 | ownerBy: string |
37 | ownerAvatarUrl: string | 40 | ownerAvatarUrl: string |
38 | 41 | ||
@@ -63,6 +66,9 @@ export class VideoPlaylist implements ServerVideoPlaylist { | |||
63 | this.thumbnailUrl = window.location.origin + '/client/assets/images/default-playlist.jpg' | 66 | this.thumbnailUrl = window.location.origin + '/client/assets/images/default-playlist.jpg' |
64 | } | 67 | } |
65 | 68 | ||
69 | this.embedPath = hash.embedPath | ||
70 | this.embedUrl = getAbsoluteEmbedUrl() + hash.embedPath | ||
71 | |||
66 | this.videosLength = hash.videosLength | 72 | this.videosLength = hash.videosLength |
67 | 73 | ||
68 | this.type = hash.type | 74 | this.type = hash.type |