Merge branch 'release/4.1.0' into develop

This commit is contained in:
Chocobozzz 2022-02-22 13:48:09 +01:00
commit f7298d0dcc
No known key found for this signature in database
GPG Key ID: 583A612D890159BE
6 changed files with 90 additions and 41 deletions

View File

@ -19,8 +19,13 @@ export class MyAccountDangerZoneComponent {
async deleteMe () { async deleteMe () {
const res = await this.confirmService.confirmWithInput( const res = await this.confirmService.confirmWithInput(
// eslint-disable-next-line max-len $localize`Are you sure you want to delete your account?` +
$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.`, '<br /><br />' +
// 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.` +
'<br /><br />' +
$localize`Content cached by other servers and other third-parties might make longer to be deleted.`,
$localize`Type your username to confirm`, $localize`Type your username to confirm`,
this.user.username, this.user.username,
$localize`Delete your account`, $localize`Delete your account`,

View File

@ -1,4 +1,5 @@
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core' import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'
import { HtmlRendererService } from '@app/core'
import { ConfirmService } from '@app/core/confirm/confirm.service' import { ConfirmService } from '@app/core/confirm/confirm.service'
import { POP_STATE_MODAL_DISMISS } from '@app/helpers' import { POP_STATE_MODAL_DISMISS } from '@app/helpers'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap' import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
@ -24,6 +25,7 @@ export class ConfirmComponent implements OnInit {
constructor ( constructor (
private modalService: NgbModal, private modalService: NgbModal,
private html: HtmlRendererService,
private confirmService: ConfirmService private confirmService: ConfirmService
) { } ) { }
@ -31,14 +33,18 @@ export class ConfirmComponent implements OnInit {
this.confirmService.showConfirm.subscribe( this.confirmService.showConfirm.subscribe(
({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => { ({ title, message, expectedInputValue, inputLabel, confirmButtonText }) => {
this.title = title this.title = title
this.message = message
this.inputLabel = inputLabel this.inputLabel = inputLabel
this.expectedInputValue = expectedInputValue this.expectedInputValue = expectedInputValue
this.confirmButtonText = confirmButtonText || $localize`Confirm` this.confirmButtonText = confirmButtonText || $localize`Confirm`
this.showModal() this.html.toSafeHtml(message)
.then(message => {
this.message = message
this.showModal()
})
} }
) )
} }

View File

@ -56,6 +56,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
private listenToPlaylistChangeSub: Subscription private listenToPlaylistChangeSub: Subscription
private playlistsData: CachedPlaylist[] = [] private playlistsData: CachedPlaylist[] = []
private pendingAddId: number
constructor ( constructor (
protected formValidatorService: FormValidatorService, protected formValidatorService: FormValidatorService,
private authService: AuthService, private authService: AuthService,
@ -215,8 +217,9 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
} }
isPrimaryCheckboxChecked (playlist: PlaylistSummary) { isPrimaryCheckboxChecked (playlist: PlaylistSummary) {
return playlist.elements.filter(e => e.enabled) // Reduce latency when adding a video to a playlist using pendingAddId
.length !== 0 return this.pendingAddId === playlist.id ||
playlist.elements.filter(e => e.enabled).length !== 0
} }
toggleOptionalRow (playlist: PlaylistSummary) { toggleOptionalRow (playlist: PlaylistSummary) {
@ -367,6 +370,8 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
if (element.startTimestamp) body.startTimestamp = element.startTimestamp if (element.startTimestamp) body.startTimestamp = element.startTimestamp
if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp if (element.stopTimestamp && element.stopTimestamp !== this.video.duration) body.stopTimestamp = element.stopTimestamp
this.pendingAddId = playlist.id
this.videoPlaylistService.addVideoInPlaylist(playlist.id, body) this.videoPlaylistService.addVideoInPlaylist(playlist.id, body)
.subscribe({ .subscribe({
next: res => { next: res => {
@ -379,9 +384,17 @@ export class VideoAddToPlaylistComponent extends FormReactive implements OnInit,
if (element) element.playlistElementId = res.videoPlaylistElement.id 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()
}
}) })
} }

View File

@ -1,10 +1,10 @@
import { Segment } from '@peertube/p2p-media-loader-core' import { Segment } from '@peertube/p2p-media-loader-core'
import { RedundancyUrlManager } from './redundancy-url-manager' import { RedundancyUrlManager } from './redundancy-url-manager'
function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager, requiredSegmentsPriority: number) { function segmentUrlBuilderFactory (redundancyUrlManager: RedundancyUrlManager, useOriginPriority: number) {
return function segmentBuilder (segment: Segment) { return function segmentBuilder (segment: Segment) {
// Don't use redundancy for high priority segments // 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) return redundancyUrlManager.buildUrl(segment.url)
} }

View File

@ -19,6 +19,7 @@ import {
VideoJSPluginOptions VideoJSPluginOptions
} from './peertube-videojs-typings' } from './peertube-videojs-typings'
import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils' import { buildVideoOrPlaylistEmbed, getRtcConfig, isIOS, isSafari } from './utils'
import { HybridLoaderSettings } from '@peertube/p2p-media-loader-core'
export type PlayerMode = 'webtorrent' | 'p2p-media-loader' export type PlayerMode = 'webtorrent' | 'p2p-media-loader'
@ -198,9 +199,6 @@ export class PeertubePlayerOptionsBuilder {
const p2pMediaLoaderOptions = this.options.p2pMediaLoader const p2pMediaLoaderOptions = this.options.p2pMediaLoader
const commonOptions = this.options.common const commonOptions = this.options.common
const trackerAnnounce = p2pMediaLoaderOptions.trackerAnnounce
.filter(t => t.startsWith('ws'))
const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls) const redundancyUrlManager = new RedundancyUrlManager(this.options.p2pMediaLoader.redundancyBaseUrls)
const p2pMediaLoader: P2PMediaLoaderPluginOptions = { const p2pMediaLoader: P2PMediaLoaderPluginOptions = {
@ -210,23 +208,8 @@ export class PeertubePlayerOptionsBuilder {
src: p2pMediaLoaderOptions.playlistUrl 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 = { const p2pMediaLoaderConfig: HlsJsEngineSettings = {
loader: { loader: this.getP2PMediaLoaderOptions(redundancyUrlManager),
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
},
segments: { segments: {
swarmId: p2pMediaLoaderOptions.playlistUrl swarmId: p2pMediaLoaderOptions.playlistUrl
} }
@ -256,6 +239,46 @@ export class PeertubePlayerOptionsBuilder {
return toAssign return toAssign
} }
private getP2PMediaLoaderOptions (redundancyUrlManager: RedundancyUrlManager): Partial<HybridLoaderSettings> {
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) { private getHLSOptions (p2pMediaLoaderConfig: HlsJsEngineSettings) {
const base = { const base = {
capLevelToPlayerSize: true, capLevelToPlayerSize: true,

View File

@ -104,7 +104,7 @@ async function generateVideoCommentsFeed (req: express.Request, res: express.Res
// Adding video items to the feed, one at a time // Adding video items to the feed, one at a time
for (const comment of comments) { for (const comment of comments) {
const link = WEBSERVER.URL + comment.getCommentStaticPath() const localLink = WEBSERVER.URL + comment.getCommentStaticPath()
let title = comment.Video.name let title = comment.Video.name
const author: { name: string, link: string }[] = [] const author: { name: string, link: string }[] = []
@ -119,8 +119,8 @@ async function generateVideoCommentsFeed (req: express.Request, res: express.Res
feed.addItem({ feed.addItem({
title, title,
id: comment.url, id: localLink,
link, link: localLink,
content: toSafeHtml(comment.text), content: toSafeHtml(comment.text),
author, author,
date: comment.createdAt date: comment.createdAt
@ -269,7 +269,7 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
size_in_bytes: videoFile.size size_in_bytes: videoFile.size
})) }))
const videos = formattedVideoFiles.map(videoFile => { const videoFiles = formattedVideoFiles.map(videoFile => {
const result = { const result = {
type: MIMETYPES.VIDEO.EXT_MIMETYPE[extname(videoFile.fileUrl)], type: MIMETYPES.VIDEO.EXT_MIMETYPE[extname(videoFile.fileUrl)],
medium: 'video', medium: 'video',
@ -293,10 +293,12 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
}) })
} }
const localLink = WEBSERVER.URL + video.getWatchStaticPath()
feed.addItem({ feed.addItem({
title: video.name, title: video.name,
id: video.url, id: localLink,
link: WEBSERVER.URL + video.getWatchStaticPath(), link: localLink,
description: mdToOneLinePlainText(video.getTruncatedDescription()), description: mdToOneLinePlainText(video.getTruncatedDescription()),
content: toSafeHtml(video.description), content: toSafeHtml(video.description),
author: [ author: [
@ -311,20 +313,20 @@ function addVideosToFeed (feed: Feed, videos: VideoModel[]) {
// Enclosure // Enclosure
video: { video: {
url: videos[0].url, url: videoFiles[0].url,
length: videos[0].fileSize, length: videoFiles[0].fileSize,
type: videos[0].type type: videoFiles[0].type
}, },
// Media RSS // Media RSS
videos, videos: videoFiles,
embed: { embed: {
url: video.getEmbedStaticPath(), url: WEBSERVER.URL + video.getEmbedStaticPath(),
allowFullscreen: true allowFullscreen: true
}, },
player: { player: {
url: video.getWatchStaticPath() url: WEBSERVER.URL + video.getWatchStaticPath()
}, },
categories, categories,
community: { community: {