diff options
Diffstat (limited to 'client/src')
5 files changed, 76 insertions, 29 deletions
diff --git a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts index 4a46f1ad9..2bae3499e 100644 --- a/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts +++ b/client/src/app/+my-account/my-account-settings/my-account-danger-zone/my-account-danger-zone.component.ts | |||
@@ -19,8 +19,13 @@ export class MyAccountDangerZoneComponent { | |||
19 | 19 | ||
20 | async deleteMe () { | 20 | async deleteMe () { |
21 | const res = await this.confirmService.confirmWithInput( | 21 | const res = await this.confirmService.confirmWithInput( |
22 | // eslint-disable-next-line max-len | 22 | $localize`Are you sure you want to delete your account?` + |
23 | $localize`Are you sure you want to delete your account? This will delete all your data, including channels, videos and comments. Content cached by other servers and other third-parties might make longer to be deleted.`, | 23 | '<br /><br />' + |
24 | // eslint-disable-next-line max-len | ||
25 | $localize`This will delete all your data, including channels, videos, comments and you won't be able to create another user on this instance with "${this.user.username}" username.` + | ||
26 | '<br /><br />' + | ||
27 | $localize`Content cached by other servers and other third-parties might make longer to be deleted.`, | ||
28 | |||
24 | $localize`Type your username to confirm`, | 29 | $localize`Type your username to confirm`, |
25 | this.user.username, | 30 | this.user.username, |
26 | $localize`Delete your account`, | 31 | $localize`Delete your account`, |
diff --git a/client/src/app/modal/confirm.component.ts b/client/src/app/modal/confirm.component.ts index 457dd1f3f..ec4e1d60f 100644 --- a/client/src/app/modal/confirm.component.ts +++ b/client/src/app/modal/confirm.component.ts | |||
@@ -1,4 +1,5 @@ | |||
1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' | 1 | import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' |
2 | import { HtmlRendererService } from '@app/core' | ||
2 | import { ConfirmService } from '@app/core/confirm/confirm.service' | 3 | import { ConfirmService } from '@app/core/confirm/confirm.service' |
3 | import { POP_STATE_MODAL_DISMISS } from '@app/helpers' | 4 | import { POP_STATE_MODAL_DISMISS } from '@app/helpers' |
4 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' | 5 | import { NgbModal } from '@ng-bootstrap/ng-bootstrap' |
@@ -24,6 +25,7 @@ export class ConfirmComponent implements OnInit { | |||
24 | 25 | ||
25 | constructor ( | 26 | constructor ( |
26 | private modalService: NgbModal, | 27 | private modalService: NgbModal, |
28 | private html: HtmlRendererService, | ||
27 | private confirmService: ConfirmService | 29 | private confirmService: ConfirmService |
28 | ) { } | 30 | ) { } |
29 | 31 | ||
@@ -31,14 +33,18 @@ export class ConfirmComponent implements OnInit { | |||
31 | this.confirmService.showConfirm.subscribe( | 33 | this.confirmService.showConfirm.subscribe( |
32 | ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => { | 34 | ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => { |
33 | this.title = title | 35 | this.title = title |
34 | this.message = message | ||
35 | 36 | ||
36 | this.inputLabel = inputLabel | 37 | this.inputLabel = inputLabel |
37 | this.expectedInputValue = expectedInputValue | 38 | this.expectedInputValue = expectedInputValue |
38 | 39 | ||
39 | this.confirmButtonText = confirmButtonText || $localize`Confirm` | 40 | this.confirmButtonText = confirmButtonText || $localize`Confirm` |
40 | 41 | ||
41 | this.showModal() | 42 | this.html.toSafeHtml(message) |
43 | .then(message => { | ||
44 | this.message = message | ||
45 | |||
46 | this.showModal() | ||
47 | }) | ||
42 | } | 48 | } |
43 | ) | 49 | ) |
44 | } | 50 | } |
diff --git a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts index 553930595..e4972ec10 100644 --- a/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts +++ b/client/src/app/shared/shared-video-playlist/video-add-to-playlist.component.ts | |||
@@ -56,6 +56,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, | |||
56 | private listenToPlaylistChangeSub: Subscription | 56 | private listenToPlaylistChangeSub: Subscription |
57 | private playlistsData: CachedPlaylist[] = [] | 57 | private playlistsData: CachedPlaylist[] = [] |
58 | 58 | ||
59 | private pendingAddId: number | ||
60 | |||
59 | constructor ( | 61 | constructor ( |
60 | protected formValidatorService: FormValidatorService, | 62 | protected formValidatorService: FormValidatorService, |
61 | private authService: AuthService, | 63 | private authService: AuthService, |
@@ -215,8 +217,9 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, | |||
215 | } | 217 | } |
216 | 218 | ||
217 | isPrimaryCheckboxChecked (playlist: PlaylistSummary) { | 219 | isPrimaryCheckboxChecked (playlist: PlaylistSummary) { |
218 | return playlist.elements.filter(e => e.enabled) | 220 | // Reduce latency when adding a video to a playlist using pendingAddId |
219 | .length !== 0 | 221 | return this.pendingAddId === playlist.id || |
222 | playlist.elements.filter(e => e.enabled).length !== 0 | ||
220 | } | 223 | } |
221 | 224 | ||
222 | toggleOptionalRow (playlist: PlaylistSummary) { | 225 | toggleOptionalRow (playlist: PlaylistSummary) { |
@@ -367,6 +370,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, | |||
367 | if (element.startTimestamp) body.startTimestamp = element.startTimestamp | 370 | if (element.startTimestamp) body.startTimestamp = element.startTimestamp |
368 | if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp | 371 | if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp |
369 | 372 | ||
373 | this.pendingAddId = playlist.id | ||
374 | |||
370 | this.videoPlaylistService.addVideoInPlaylist(playlist.id, body) | 375 | this.videoPlaylistService.addVideoInPlaylist(playlist.id, body) |
371 | .subscribe({ | 376 | .subscribe({ |
372 | next: res => { | 377 | next: res => { |
@@ -379,9 +384,17 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit, | |||
379 | if (element) element.playlistElementId = res.videoPlaylistElement.id | 384 | if (element) element.playlistElementId = res.videoPlaylistElement.id |
380 | }, | 385 | }, |
381 | 386 | ||
382 | error: err => this.notifier.error(err.message), | 387 | error: err => { |
388 | this.pendingAddId = undefined | ||
389 | this.cd.markForCheck() | ||
390 | |||
391 | this.notifier.error(err.message) | ||
392 | }, | ||
383 | 393 | ||
384 | complete: () => this.cd.markForCheck() | 394 | complete: () => { |
395 | this.pendingAddId = undefined | ||
396 | this.cd.markForCheck() | ||
397 | } | ||
385 | }) | 398 | }) |
386 | } | 399 | } |
387 | 400 | ||
diff --git a/client/src/assets/player/p2p-media-loader/segment-url-builder.ts b/client/src/assets/player/p2p-media-loader/segment-url-builder.ts index 5ddc81ff6..9d324078a 100644 --- a/client/src/assets/player/p2p-media-loader/segment-url-builder.ts +++ b/client/src/assets/player/p2p-media-loader/segment-url-builder.ts | |||
@@ -1,10 +1,10 @@ | |||
1 | import { Segment } from '@peertube/p2p-media-loader-core' | 1 | import { Segment } from '@peertube/p2p-media-loader-core' |
2 | import { RedundancyUrlManager } from './redundancy-url-manager' | 2 | import { RedundancyUrlManager } from './redundancy-url-manager' |
3 | 3 | ||
4 | function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager, requiredSegmentsPriority: number) { | 4 | function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager, useOriginPriority: number) { |
5 | return function segmentBuilder (segment: Segment) { | 5 | return function segmentBuilder (segment: Segment) { |
6 | // Don't use redundancy for high priority segments | 6 | // Don't use redundancy for high priority segments |
7 | if (segment.priority <= requiredSegmentsPriority) return segment.url | 7 | if (segment.priority <= useOriginPriority) return segment.url |
8 | 8 | ||
9 | return redundancyUrlManager.buildUrl(segment.url) | 9 | return redundancyUrlManager.buildUrl(segment.url) |
10 | } | 10 | } |
diff --git a/client/src/assets/player/peertube-player-options-builder.ts b/client/src/assets/player/peertube-player-options-builder.ts index 901f6cd3b..71be5ccff 100644 --- a/client/src/assets/player/peertube-player-options-builder.ts +++ b/client/src/assets/player/peertube-player-options-builder.ts | |||
@@ -19,6 +19,7 @@ import { | |||
19 | VideoJSPluginOptions | 19 | VideoJSPluginOptions |
20 | } from './peertube-videojs-typings' | 20 | } from './peertube-videojs-typings' |
21 | import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils' | 21 | import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils' |
22 | import { HybridLoaderSettings } from '@peertube/p2p-media-loader-core' | ||
22 | 23 | ||
23 | export type PlayerMode = 'webtorrent' | 'p2p-media-loader' | 24 | export type PlayerMode = 'webtorrent' | 'p2p-media-loader' |
24 | 25 | ||
@@ -198,9 +199,6 @@ export class PeertubePlayerOptionsBuilder { | |||
198 | const p2pMediaLoaderOptions = this.options.p2pMediaLoader | 199 | const p2pMediaLoaderOptions = this.options.p2pMediaLoader |
199 | const commonOptions = this.options.common | 200 | const commonOptions = this.options.common |
200 | 201 | ||
201 | const trackerAnnounce = p2pMediaLoaderOptions.trackerAnnounce | ||
202 | .filter(t => t.startsWith('ws')) | ||
203 | |||
204 | const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls) | 202 | const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls) |
205 | 203 | ||
206 | const p2pMediaLoader: P2PMediaLoaderPluginOptions = { | 204 | const p2pMediaLoader: P2PMediaLoaderPluginOptions = { |
@@ -210,23 +208,8 @@ export class PeertubePlayerOptionsBuilder { | |||
210 | src: p2pMediaLoaderOptions.playlistUrl | 208 | src: p2pMediaLoaderOptions.playlistUrl |
211 | } | 209 | } |
212 | 210 | ||
213 | let consumeOnly = false | ||
214 | if ((navigator as any)?.connection?.type === 'cellular') { | ||
215 | console.log('We are on a cellular connection: disabling seeding.') | ||
216 | consumeOnly = true | ||
217 | } | ||
218 | |||
219 | const p2pMediaLoaderConfig: HlsJsEngineSettings = { | 211 | const p2pMediaLoaderConfig: HlsJsEngineSettings = { |
220 | loader: { | 212 | loader: this.getP2PMediaLoaderOptions(redundancyUrlManager), |
221 | trackerAnnounce, | ||
222 | segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive), | ||
223 | rtcConfig: getRtcConfig(), | ||
224 | requiredSegmentsPriority: 1, | ||
225 | simultaneousHttpDownloads: 1, | ||
226 | segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1), | ||
227 | useP2P: commonOptions.p2pEnabled, | ||
228 | consumeOnly | ||
229 | }, | ||
230 | segments: { | 213 | segments: { |
231 | swarmId: p2pMediaLoaderOptions.playlistUrl | 214 | swarmId: p2pMediaLoaderOptions.playlistUrl |
232 | } | 215 | } |
@@ -256,6 +239,46 @@ export class PeertubePlayerOptionsBuilder { | |||
256 | return toAssign | 239 | return toAssign |
257 | } | 240 | } |
258 | 241 | ||
242 | private getP2PMediaLoaderOptions (redundancyUrlManager: RedundancyUrlManager): Partial<HybridLoaderSettings> { | ||
243 | let consumeOnly = false | ||
244 | if ((navigator as any)?.connection?.type === 'cellular') { | ||
245 | console.log('We are on a cellular connection: disabling seeding.') | ||
246 | consumeOnly = true | ||
247 | } | ||
248 | |||
249 | const trackerAnnounce = this.options.p2pMediaLoader.trackerAnnounce | ||
250 | .filter(t => t.startsWith('ws')) | ||
251 | |||
252 | const specificLiveOrVODOptions = this.options.common.isLive | ||
253 | ? { // Live | ||
254 | requiredSegmentsPriority: 1 | ||
255 | } | ||
256 | : { // VOD | ||
257 | requiredSegmentsPriority: 3, | ||
258 | |||
259 | cachedSegmentExpiration: 86400000, | ||
260 | cachedSegmentsCount: 100, | ||
261 | |||
262 | httpDownloadMaxPriority: 9, | ||
263 | httpDownloadProbability: 0.06, | ||
264 | httpDownloadProbabilitySkipIfNoPeers: true, | ||
265 | |||
266 | p2pDownloadMaxPriority: 50 | ||
267 | } | ||
268 | |||
269 | return { | ||
270 | trackerAnnounce, | ||
271 | segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive), | ||
272 | rtcConfig: getRtcConfig(), | ||
273 | simultaneousHttpDownloads: 1, | ||
274 | segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1), | ||
275 | useP2P: this.options.common.p2pEnabled, | ||
276 | consumeOnly, | ||
277 | |||
278 | ...specificLiveOrVODOptions | ||
279 | } | ||
280 | } | ||
281 | |||
259 | private getHLSOptions (p2pMediaLoaderConfig: HlsJsEngineSettings) { | 282 | private getHLSOptions (p2pMediaLoaderConfig: HlsJsEngineSettings) { |
260 | const base = { | 283 | const base = { |
261 | capLevelToPlayerSize: true, | 284 | capLevelToPlayerSize: true, |