Resolutions to generate
diff --git a/client/src/app/shared/form-validators/custom-config-validators.ts b/client/src/app/shared/form-validators/custom-config-validators.ts
index 8579cfaa4..519a1480a 100644
--- a/client/src/app/shared/form-validators/custom-config-validators.ts
+++ b/client/src/app/shared/form-validators/custom-config-validators.ts
@@ -65,6 +65,14 @@ export const TRANSCODING_THREADS_VALIDATOR: BuildFormValidator = {
}
}
+export const TRANSCODING_MAX_FPS_VALIDATOR: BuildFormValidator = {
+ VALIDATORS: [ Validators.required, Validators.min(1) ],
+ MESSAGES: {
+ required: $localize`Transcoding max FPS is required.`,
+ min: $localize`Transcoding max FPS must be greater or equal to 1.`
+ }
+}
+
export const MAX_LIVE_DURATION_VALIDATOR: BuildFormValidator = {
VALIDATORS: [ Validators.required, Validators.min(-1) ],
MESSAGES: {
diff --git a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts
index 2648529de..00085f317 100644
--- a/client/src/app/shared/shared-forms/advanced-input-filter.component.ts
+++ b/client/src/app/shared/shared-forms/advanced-input-filter.component.ts
@@ -155,25 +155,30 @@ export class AdvancedInputFilterComponent implements OnInit, AfterViewInit {
}
private addFilterToSearch (search: string, newFilter: AdvancedInputFilterChild) {
- const prefix = newFilter.value.split(':').shift()
+ const filterTokens = this.restService.tokenizeString(newFilter.value)
+ let searchTokens = this.restService.tokenizeString(search)
- // Tokenize search and remove a potential existing filter
- const tokens = this.restService.tokenizeString(search)
- .filter(t => !t.startsWith(prefix))
+ for (const filterToken of filterTokens) {
+ const prefix = filterToken.split(':').shift()
- tokens.push(newFilter.value)
+ // Tokenize search and remove a potential existing filter
+ searchTokens = searchTokens.filter(t => !t.startsWith(prefix))
+ searchTokens.push(filterToken)
+ }
- return tokens.join(' ')
+ return searchTokens.join(' ')
}
private parseFilters (search: string) {
- const tokens = this.restService.tokenizeString(search)
+ const searchTokens = this.restService.tokenizeString(search)
this.enabledFilters = new Set()
for (const group of this.filters) {
for (const filter of group.children) {
- if (tokens.includes(filter.value)) {
+ const filterTokens = this.restService.tokenizeString(filter.value)
+
+ if (filterTokens.every(filterToken => searchTokens.includes(filterToken))) {
this.enabledFilters.add(filter.value)
}
}
diff --git a/client/src/app/shared/shared-main/video/video.service.ts b/client/src/app/shared/shared-main/video/video.service.ts
index 69a30e29d..cbc8bbc42 100644
--- a/client/src/app/shared/shared-main/video/video.service.ts
+++ b/client/src/app/shared/shared-main/video/video.service.ts
@@ -384,14 +384,17 @@ export class VideoService {
generateDownloadUrl (options: {
video: Video
files: VideoFile[]
+ videoFileToken?: string
}) {
- const { video, files } = options
+ const { video, files, videoFileToken } = options
if (files.length === 0) throw new Error('Cannot generate download URL without files')
let url = `${VideoService.BASE_VIDEO_DOWNLOAD_URL}/${video.uuid}?`
url += files.map(f => 'videoFileIds=' + f.id).join('&')
+ if (videoFileToken) url += `&videoFileToken=${videoFileToken}`
+
return url
}
diff --git a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
index ad2dddf59..bf474ecec 100644
--- a/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
+++ b/client/src/app/shared/shared-user-settings/user-video-settings.component.ts
@@ -136,7 +136,7 @@ export class UserVideoSettingsComponent extends FormReactive implements OnInit,
next: () => {
this.authService.refreshUserInformation()
- if (this.notifyOnUpdate) this.notifier.success($localize`Video settings updated.`, 'toto', 15000)
+ if (this.notifyOnUpdate) this.notifier.success($localize`Video settings updated.`)
},
error: err => this.notifier.error(err.message)
diff --git a/client/src/app/shared/shared-video-miniature/download/video-generate-download.component.ts b/client/src/app/shared/shared-video-miniature/download/video-generate-download.component.ts
index 52bb04552..6cbe96cc4 100644
--- a/client/src/app/shared/shared-video-miniature/download/video-generate-download.component.ts
+++ b/client/src/app/shared/shared-video-miniature/download/video-generate-download.component.ts
@@ -104,7 +104,7 @@ export class VideoGenerateDownloadComponent implements OnInit {
files.push(this.findAudioFileOnly())
}
- return this.videoService.generateDownloadUrl({ video: this.video, files })
+ return this.videoService.generateDownloadUrl({ video: this.video, videoFileToken: this.videoFileToken, files })
}
// ---------------------------------------------------------------------------
diff --git a/client/src/app/shared/shared-video-miniature/video-filters.model.ts b/client/src/app/shared/shared-video-miniature/video-filters.model.ts
index a958f3aac..04cf6df45 100644
--- a/client/src/app/shared/shared-video-miniature/video-filters.model.ts
+++ b/client/src/app/shared/shared-video-miniature/video-filters.model.ts
@@ -45,7 +45,8 @@ export class VideoFilters {
[ 'categoryOneOf', undefined ],
[ 'scope', 'federated' ],
[ 'allVideos', false ],
- [ 'live', 'both' ]
+ [ 'live', 'both' ],
+ [ 'search', '' ]
])
private activeFilters: VideoFilterActive[] = []
diff --git a/client/src/assets/player/peertube-player.ts b/client/src/assets/player/peertube-player.ts
index d4d4d4a7b..12c8b5e84 100644
--- a/client/src/assets/player/peertube-player.ts
+++ b/client/src/assets/player/peertube-player.ts
@@ -502,7 +502,7 @@ export class PeerTubePlayer {
{
label: player.localize('Copy the video URL'),
listener: function () {
- copyToClipboard(buildVideoLink({ shortUUID }))
+ copyToClipboard(buildVideoLink({ shortUUID }), player.el() as HTMLElement)
}
},
{
@@ -510,17 +510,17 @@ export class PeerTubePlayer {
listener: function () {
const url = buildVideoLink({ shortUUID })
- copyToClipboard(decorateVideoLink({ url, startTime: player.currentTime() }))
+ copyToClipboard(decorateVideoLink({ url, startTime: player.currentTime() }), player.el() as HTMLElement)
}
},
{
icon: 'code',
label: player.localize('Copy embed code'),
listener: () => {
- copyToClipboard(buildVideoOrPlaylistEmbed({
- embedUrl: self.currentLoadOptions.embedUrl,
- embedTitle: self.currentLoadOptions.embedTitle
- }))
+ copyToClipboard(
+ buildVideoOrPlaylistEmbed({ embedUrl: self.currentLoadOptions.embedUrl, embedTitle: self.currentLoadOptions.embedTitle }),
+ player.el() as HTMLElement
+ )
}
}
]
diff --git a/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts b/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
index 247e6190a..008eab112 100644
--- a/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
+++ b/client/src/assets/player/shared/mobile/peertube-mobile-plugin.ts
@@ -36,12 +36,15 @@ class PeerTubeMobilePlugin extends Plugin {
this.seekAmount = 0
- this.peerTubeMobileButtons = player.addChild('PeerTubeMobileButtons', { reportTouchActivity: false }) as PeerTubeMobileButtons
-
if (videojs.browser.IS_ANDROID && screen.orientation) {
this.handleFullscreenRotation()
}
+ // Don't add buttons if the player doesn't have controls
+ if (!player.controls()) return
+
+ this.peerTubeMobileButtons = player.addChild('PeerTubeMobileButtons', { reportTouchActivity: false }) as PeerTubeMobileButtons
+
if (!this.player.options_.userActions) this.player.options_.userActions = {};
// FIXME: typings
diff --git a/client/src/root-helpers/utils.ts b/client/src/root-helpers/utils.ts
index af94ed6ca..7addfadc4 100644
--- a/client/src/root-helpers/utils.ts
+++ b/client/src/root-helpers/utils.ts
@@ -1,13 +1,15 @@
-function copyToClipboard (text: string) {
+function copyToClipboard (text: string, container?: HTMLElement) {
+ if (!container) container = document.body
+
const el = document.createElement('textarea')
el.value = text
el.setAttribute('readonly', '')
el.style.position = 'absolute'
el.style.left = '-9999px'
- document.body.appendChild(el)
+ container.appendChild(el)
el.select()
document.execCommand('copy')
- document.body.removeChild(el)
+ container.removeChild(el)
}
function wait (ms: number) {
diff --git a/package.json b/package.json
index b791ae6b9..b03c487b9 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "peertube",
"description": "PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.",
- "version": "6.3.1",
+ "version": "6.3.2",
"private": true,
"licence": "AGPL-3.0",
"engines": {
diff --git a/server/core/lib/job-queue/handlers/video-live-ending.ts b/server/core/lib/job-queue/handlers/video-live-ending.ts
index dba971649..ad862799f 100644
--- a/server/core/lib/job-queue/handlers/video-live-ending.ts
+++ b/server/core/lib/job-queue/handlers/video-live-ending.ts
@@ -178,7 +178,14 @@ async function saveReplayToExternalVideo (options: {
inputFileMutexReleaser()
}
- await copyOrRegenerateThumbnails({ liveVideo, replayVideo })
+ try {
+ await copyOrRegenerateThumbnails({ liveVideo, replayVideo })
+ } catch (err) {
+ logger.error(
+ `Cannot copy/regenerate thumbnails of ended live ${liveVideo.uuid} to external video ${replayVideo.uuid}`,
+ lTags(liveVideo.uuid, replayVideo.uuid)
+ )
+ }
await createStoryboardJob(replayVideo)
await createTranscriptionTaskIfNeeded(replayVideo)
@@ -280,7 +287,11 @@ async function replaceLiveByReplay (options: {
}
// Regenerate the thumbnail & preview?
- await regenerateMiniaturesIfNeeded(videoWithFiles, undefined)
+ try {
+ await regenerateMiniaturesIfNeeded(videoWithFiles, undefined)
+ } catch (err) {
+ logger.error(`Cannot regenerate thumbnails of ended live ${videoWithFiles.uuid}`, lTags(liveVideo.uuid))
+ }
// We consider this is a new video
await moveToNextState({ video: videoWithFiles, isNewVideo: true })
diff --git a/server/core/models/video/formatter/video-activity-pub-format.ts b/server/core/models/video/formatter/video-activity-pub-format.ts
index 0446b708f..efdbf0526 100644
--- a/server/core/models/video/formatter/video-activity-pub-format.ts
+++ b/server/core/models/video/formatter/video-activity-pub-format.ts
@@ -284,6 +284,7 @@ function buildTags (video: MVideoAP) {
function buildIcon (video: MVideoAP): ActivityIconObject[] {
return [ video.getMiniature(), video.getPreview() ]
+ .filter(i => !!i)
.map(i => i.toActivityPubObject(video))
}