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 {
async deleteMe () {
const res = await this.confirmService.confirmWithInput(
- // eslint-disable-next-line max-len
- $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.`,
+ $localize`Are you sure you want to delete your account?` +
+ '
' +
+ // eslint-disable-next-line max-len
+ $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.` +
+ '
' +
+ $localize`Content cached by other servers and other third-parties might make longer to be deleted.`,
+
$localize`Type your username to confirm`,
this.user.username,
$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 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
+import { HtmlRendererService } from '@app/core'
import { ConfirmService } from '@app/core/confirm/confirm.service'
import { POP_STATE_MODAL_DISMISS } from '@app/helpers'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
@@ -24,6 +25,7 @@ export class ConfirmComponent implements OnInit {
constructor (
private modalService: NgbModal,
+ private html: HtmlRendererService,
private confirmService: ConfirmService
) { }
@@ -31,14 +33,18 @@ export class ConfirmComponent implements OnInit {
this.confirmService.showConfirm.subscribe(
({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => {
this.title = title
- this.message = message
this.inputLabel = inputLabel
this.expectedInputValue = expectedInputValue
this.confirmButtonText = confirmButtonText || $localize`Confirm`
- this.showModal()
+ this.html.toSafeHtml(message)
+ .then(message => {
+ this.message = message
+
+ this.showModal()
+ })
}
)
}
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,
private listenToPlaylistChangeSub: Subscription
private playlistsData: CachedPlaylist[] = []
+ private pendingAddId: number
+
constructor (
protected formValidatorService: FormValidatorService,
private authService: AuthService,
@@ -215,8 +217,9 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
}
isPrimaryCheckboxChecked (playlist: PlaylistSummary) {
- return playlist.elements.filter(e => e.enabled)
- .length !== 0
+ // Reduce latency when adding a video to a playlist using pendingAddId
+ return this.pendingAddId === playlist.id ||
+ playlist.elements.filter(e => e.enabled).length !== 0
}
toggleOptionalRow (playlist: PlaylistSummary) {
@@ -367,6 +370,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
if (element.startTimestamp) body.startTimestamp = element.startTimestamp
if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp
+ this.pendingAddId = playlist.id
+
this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
.subscribe({
next: res => {
@@ -379,9 +384,17 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
if (element) element.playlistElementId = res.videoPlaylistElement.id
},
- error: err => this.notifier.error(err.message),
+ error: err => {
+ this.pendingAddId = undefined
+ this.cd.markForCheck()
- complete: () => this.cd.markForCheck()
+ this.notifier.error(err.message)
+ },
+
+ complete: () => {
+ this.pendingAddId = undefined
+ this.cd.markForCheck()
+ }
})
}
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 @@
import { Segment } from '@peertube/p2p-media-loader-core'
import { RedundancyUrlManager } from './redundancy-url-manager'
-function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager, requiredSegmentsPriority: number) {
+function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager, useOriginPriority: number) {
return function segmentBuilder (segment: Segment) {
// Don't use redundancy for high priority segments
- if (segment.priority <= requiredSegmentsPriority) return segment.url
+ if (segment.priority <= useOriginPriority) return segment.url
return redundancyUrlManager.buildUrl(segment.url)
}
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 {
VideoJSPluginOptions
} from './peertube-videojs-typings'
import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils'
+import { HybridLoaderSettings } from '@peertube/p2p-media-loader-core'
export type PlayerMode = 'webtorrent' | 'p2p-media-loader'
@@ -198,9 +199,6 @@ export class PeertubePlayerOptionsBuilder {
const p2pMediaLoaderOptions = this.options.p2pMediaLoader
const commonOptions = this.options.common
- const trackerAnnounce = p2pMediaLoaderOptions.trackerAnnounce
- .filter(t => t.startsWith('ws'))
-
const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls)
const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
@@ -210,23 +208,8 @@ export class PeertubePlayerOptionsBuilder {
src: p2pMediaLoaderOptions.playlistUrl
}
- let consumeOnly = false
- if ((navigator as any)?.connection?.type === 'cellular') {
- console.log('We are on a cellular connection: disabling seeding.')
- consumeOnly = true
- }
-
const p2pMediaLoaderConfig: HlsJsEngineSettings = {
- loader: {
- trackerAnnounce,
- segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive),
- rtcConfig: getRtcConfig(),
- requiredSegmentsPriority: 1,
- simultaneousHttpDownloads: 1,
- segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1),
- useP2P: commonOptions.p2pEnabled,
- consumeOnly
- },
+ loader: this.getP2PMediaLoaderOptions(redundancyUrlManager),
segments: {
swarmId: p2pMediaLoaderOptions.playlistUrl
}
@@ -256,6 +239,46 @@ export class PeertubePlayerOptionsBuilder {
return toAssign
}
+ private getP2PMediaLoaderOptions (redundancyUrlManager: RedundancyUrlManager): Partial {
+ let consumeOnly = false
+ if ((navigator as any)?.connection?.type === 'cellular') {
+ console.log('We are on a cellular connection: disabling seeding.')
+ consumeOnly = true
+ }
+
+ const trackerAnnounce = this.options.p2pMediaLoader.trackerAnnounce
+ .filter(t => t.startsWith('ws'))
+
+ const specificLiveOrVODOptions = this.options.common.isLive
+ ? { // Live
+ requiredSegmentsPriority: 1
+ }
+ : { // VOD
+ requiredSegmentsPriority: 3,
+
+ cachedSegmentExpiration: 86400000,
+ cachedSegmentsCount: 100,
+
+ httpDownloadMaxPriority: 9,
+ httpDownloadProbability: 0.06,
+ httpDownloadProbabilitySkipIfNoPeers: true,
+
+ p2pDownloadMaxPriority: 50
+ }
+
+ return {
+ trackerAnnounce,
+ segmentValidator: segmentValidatorFactory(this.options.p2pMediaLoader.segmentsSha256Url, this.options.common.isLive),
+ rtcConfig: getRtcConfig(),
+ simultaneousHttpDownloads: 1,
+ segmentUrlBuilder: segmentUrlBuilderFactory(redundancyUrlManager, 1),
+ useP2P: this.options.common.p2pEnabled,
+ consumeOnly,
+
+ ...specificLiveOrVODOptions
+ }
+ }
+
private getHLSOptions (p2pMediaLoaderConfig: HlsJsEngineSettings) {
const base = {
capLevelToPlayerSize: true,
diff --git a/server/controllers/feeds.ts b/server/controllers/feeds.ts
index 90faaf024..c929a6726 100644
--- a/server/controllers/feeds.ts
+++ b/server/controllers/feeds.ts
@@ -104,7 +104,7 @@ async function generateVideoCommentsFeed (req: express.Request, res: express.Res
// Adding video items to the feed, one at a time
for (const comment of comments) {
- const link = WEBSERVER.URL + comment.getCommentStaticPath()
+ const localLink = WEBSERVER.URL + comment.getCommentStaticPath()
let title = comment.Video.name
const author: { name: string, link: string }[] = []
@@ -119,8 +119,8 @@ async function generateVideoCommentsFeed (req: express.Request, res: express.Res
feed.addItem({
title,
- id: comment.url,
- link,
+ id: localLink,
+ link: localLink,
content: toSafeHtml(comment.text),
author,
date: comment.createdAt
@@ -269,7 +269,7 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
size_in_bytes: videoFile.size
}))
- const videos = formattedVideoFiles.map(videoFile => {
+ const videoFiles = formattedVideoFiles.map(videoFile => {
const result = {
type: MIMETYPES.VIDEO.EXT_MIMETYPE[extname(videoFile.fileUrl)],
medium: 'video',
@@ -293,10 +293,12 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
})
}
+ const localLink = WEBSERVER.URL + video.getWatchStaticPath()
+
feed.addItem({
title: video.name,
- id: video.url,
- link: WEBSERVER.URL + video.getWatchStaticPath(),
+ id: localLink,
+ link: localLink,
description: mdToOneLinePlainText(video.getTruncatedDescription()),
content: toSafeHtml(video.description),
author: [
@@ -311,20 +313,20 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
// Enclosure
video: {
- url: videos[0].url,
- length: videos[0].fileSize,
- type: videos[0].type
+ url: videoFiles[0].url,
+ length: videoFiles[0].fileSize,
+ type: videoFiles[0].type
},
// Media RSS
- videos,
+ videos: videoFiles,
embed: {
- url: video.getEmbedStaticPath(),
+ url: WEBSERVER.URL + video.getEmbedStaticPath(),
allowFullscreen: true
},
player: {
- url: video.getWatchStaticPath()
+ url: WEBSERVER.URL + video.getWatchStaticPath()
},
categories,
community: {