Merge branch 'release/4.1.0' into develop
This commit is contained in:
commit
f7298d0dcc
|
@ -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`,
|
||||||
|
|
|
@ -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()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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()
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
Loading…
Reference in New Issue