v6.3.3
-----BEGIN PGP SIGNATURE----- iQEzBAABCAAdFiEExEqtY4NnkSypPt1XWDphLYkBWb4FAmch2CoACgkQWDphLYkB Wb4cCwgAzwpZMgS5Vi/eFFjv4TgP3nBWGE7YsMXld17uwbpsvj4tuo8ySVcNtCnc GDMD028xQWcjNc1Bo2cs6RFoPSrLOXee5hv7SV+/s9TTRqMVRvZ/hwGxMs6AdmYO Ev21Z+Fofw1VZuRo5lrHDeEd9tQOGYgyP7B68fudl65eQL3oncfavrJ/gRp/CFSB A3W0+ftJ8OSf66ZgTLXzKaIHf7a/iWNnSAR6NyoO+gh5aXeJ2d0KG4z3LYPXPP9+ c90ite9tV+I1JHIpFUYBBpCRHhPSRGZMZfahGBdK6d+F6UWyDMRo+AGk50FJUBKk YqXDx4l5zK7YbDFr1aHOHUjtBrZTyw== =LRS/ -----END PGP SIGNATURE----- gpgsig -----BEGIN PGP SIGNATURE----- iQJLBAABCAA1FiEEGCBYi9NGimfngx9dVTwOu+tdXwgFAmeSn8AXHGdpdEBrb3Rv dmFsZXhhcmlhbi5jb20ACgkQVTwOu+tdXwg8XhAAp/O47aPcUi9EW2Yy/c6C6G+O 4aOQASagjVMsUY4LgUC55gmn6rLicdsAf+G3ewquHoy3etLqGH+rBRh/QrW4q8sd HM9kAVSFQWvOelpe2iudA9Jv4KGZbuaJQStshHaSPDgJw+y7heib44Qz9AZpn5Hh 3/V5CHCtKzcfoAak2Qtn+0DubaYyPE0xEHle/I8OobaHdVpciPqujs9Y7S9+oTbG L4BYFRKmGjKqKazy6F3iy3KtqIofzgCT0C3byNLosr905Ez/DI0rMJjgPm+JEf00 qmL4qqnEbtiGgydE2Xz2axVTovY40YR1i+sdLcdoaCAfYLdEH3Wkt/W5ZmNrJqI6 qgAjebTKrpeurHjQ45c4MhrNTm8ZLVhtiNwZfGCskDUS6RQQeM7NrGxC2yv5AKiX T6r8iIFHGOfptQCqh7Vi4AQ7X0yOrTT65B9Z4yEdFzvdiq/U8sJ8HrDk8M18VMpm xNsVUYX8lpRmvstNYlLp5eSmN4Kjv1VNQ18uXVPIqST/vuNCGsgr+2jcURx1itYV 0muJ9KBx5wIUx41kEoMcqtwY53FftXMBY/QS1PYzauV+ThC/I9lQc+BRA1c8DQya zlCo1DjjB5DFVshoRDLkaDZA1tANuaVPQd0UomkyRn09ekdCvL0tiwk4ZVmEYx05 BgXT/Yd9PuChoBnJHLI= =1oa5 -----END PGP SIGNATURE----- Merge tag 'v6.3.3' into changes v6.3.3
This commit is contained in:
commit
1f8c955fc5
16 changed files with 163 additions and 33 deletions
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -1,5 +1,18 @@
|
|||
# Changelog
|
||||
|
||||
## v6.3.3
|
||||
|
||||
### Bug fixes
|
||||
|
||||
* Fix broken thumbnails on live replay
|
||||
* Fix detecting portrait rotation of some video
|
||||
* Don't allow to select a frame from a live to set the thumbnail
|
||||
* Fix lost video stream with specific transcoding settings and video input
|
||||
* Fix creating playlist without thumbnail when using the REST API
|
||||
* Fix `.mov` video upload on some Windows versions
|
||||
* Fix `video-plugin-metadata.result` client plugin hook
|
||||
|
||||
|
||||
## v6.3.2
|
||||
|
||||
### Bug fixes
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "peertube-client",
|
||||
"version": "6.3.2",
|
||||
"version": "6.3.3",
|
||||
"private": true,
|
||||
"license": "AGPL-3.0",
|
||||
"author": {
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
[buttonTooltip]="getReactiveFileButtonTooltip()">
|
||||
</my-reactive-file>
|
||||
|
||||
@if (video) {
|
||||
@if (canSelectFromVideo()) {
|
||||
<button i18n type="button" class="peertube-button grey-button ms-2" (click)="selectFromVideo()">Select from video</button>
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import {
|
|||
import { ReactiveFileComponent } from '@app/shared/shared-forms/reactive-file.component'
|
||||
import { BytesPipe } from '@app/shared/shared-main/angular/bytes.pipe'
|
||||
import { EmbedComponent, EmbedVideoInput } from '@app/shared/shared-main/video/embed.component'
|
||||
import { HTMLServerConfig } from '@peertube/peertube-models'
|
||||
import { HTMLServerConfig, Video, VideoState } from '@peertube/peertube-models'
|
||||
import { imageToDataURL } from '@root-helpers/images'
|
||||
import { PeerTubePlayer } from '../../../../../standalone/embed-player-api/player'
|
||||
|
||||
|
@ -34,7 +34,7 @@ import { PeerTubePlayer } from '../../../../../standalone/embed-player-api/playe
|
|||
export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
||||
@ViewChild('embed') embed: EmbedComponent
|
||||
|
||||
@Input() video: EmbedVideoInput
|
||||
@Input() video: EmbedVideoInput & Pick<Video, 'isLive' | 'state'>
|
||||
|
||||
imageSrc: string
|
||||
allowedExtensionsMessage = ''
|
||||
|
@ -71,6 +71,10 @@ export class ThumbnailManagerComponent implements OnInit, ControlValueAccessor {
|
|||
return this.bytesPipe.transform(this.maxVideoImageSize)
|
||||
}
|
||||
|
||||
canSelectFromVideo () {
|
||||
return this.video && !this.video.isLive && this.video.state.id === VideoState.PUBLISHED
|
||||
}
|
||||
|
||||
getReactiveFileButtonTooltip () {
|
||||
return $localize`(extensions: ${this.videoImageExtensions}, ${this.maxSizeText}\: ${this.maxVideoImageSizeInBytes})`
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { Component, Input, OnInit } from '@angular/core'
|
||||
import { DatePipe, NgFor, NgIf } from '@angular/common'
|
||||
import { Component, Input, OnChanges } from '@angular/core'
|
||||
import { RouterLink } from '@angular/router'
|
||||
import { HooksService } from '@app/core'
|
||||
import { VideoDetails } from '@app/shared/shared-main/video/video-details.model'
|
||||
import { TimeDurationFormatterPipe } from '../../../../shared/shared-main/angular/time-duration-formatter.pipe'
|
||||
import { GlobalIconComponent } from '../../../../shared/shared-icons/global-icon.component'
|
||||
import { RouterLink } from '@angular/router'
|
||||
import { NgIf, NgFor, DatePipe } from '@angular/common'
|
||||
import { TimeDurationFormatterPipe } from '../../../../shared/shared-main/angular/time-duration-formatter.pipe'
|
||||
|
||||
type PluginMetadata = {
|
||||
label: string
|
||||
|
@ -20,14 +20,14 @@ type PluginMetadata = {
|
|||
standalone: true,
|
||||
imports: [ NgIf, RouterLink, GlobalIconComponent, NgFor, DatePipe, TimeDurationFormatterPipe ]
|
||||
})
|
||||
export class VideoAttributesComponent implements OnInit {
|
||||
export class VideoAttributesComponent implements OnChanges {
|
||||
@Input() video: VideoDetails
|
||||
|
||||
pluginMetadata: PluginMetadata[] = []
|
||||
|
||||
constructor (private hooks: HooksService) { }
|
||||
|
||||
async ngOnInit () {
|
||||
async ngOnChanges () {
|
||||
this.pluginMetadata = await this.hooks.wrapObject(
|
||||
this.pluginMetadata,
|
||||
'video-watch',
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "peertube",
|
||||
"description": "PeerTube, an ActivityPub-federated video streaming platform using P2P directly in your web browser.",
|
||||
"version": "6.3.2",
|
||||
"version": "6.3.3",
|
||||
"private": true,
|
||||
"licence": "AGPL-3.0",
|
||||
"engines": {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import ffmpeg, { FfprobeData } from 'fluent-ffmpeg'
|
||||
import { buildAspectRatio, forceNumber } from '@peertube/peertube-core-utils'
|
||||
import { VideoResolution } from '@peertube/peertube-models'
|
||||
import ffmpeg, { FfprobeData } from 'fluent-ffmpeg'
|
||||
|
||||
/**
|
||||
*
|
||||
|
@ -114,7 +114,11 @@ async function getVideoStreamDimensionsInfo (path: string, existingProbe?: Ffpro
|
|||
}
|
||||
}
|
||||
|
||||
if (videoStream.rotation === '90' || videoStream.rotation === '-90') {
|
||||
const rotation = videoStream.rotation
|
||||
? videoStream.rotation + ''
|
||||
: undefined
|
||||
|
||||
if (rotation === '90' || rotation === '-90') {
|
||||
const width = videoStream.width
|
||||
videoStream.width = videoStream.height
|
||||
videoStream.height = width
|
||||
|
@ -205,16 +209,19 @@ async function getChaptersFromContainer (options: {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
export {
|
||||
getVideoStreamDimensionsInfo,
|
||||
getChaptersFromContainer,
|
||||
getMaxAudioBitrate,
|
||||
getVideoStream,
|
||||
getVideoStreamDuration,
|
||||
getAudioStream,
|
||||
getVideoStreamFPS,
|
||||
isAudioFile,
|
||||
ffprobePromise,
|
||||
getAudioStream,
|
||||
getChaptersFromContainer,
|
||||
|
||||
getMaxAudioBitrate,
|
||||
|
||||
getVideoStream,
|
||||
getVideoStreamBitrate,
|
||||
getVideoStreamDimensionsInfo,
|
||||
getVideoStreamDuration,
|
||||
getVideoStreamFPS,
|
||||
hasAudioStream,
|
||||
hasVideoStream
|
||||
|
||||
hasVideoStream,
|
||||
isAudioFile
|
||||
}
|
||||
|
|
BIN
packages/tests/fixtures/custom-thumbnail-2.jpg
vendored
Normal file
BIN
packages/tests/fixtures/custom-thumbnail-2.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
packages/tests/fixtures/default-live-preview.jpg
vendored
Normal file
BIN
packages/tests/fixtures/default-live-preview.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 59 KiB |
BIN
packages/tests/fixtures/default-live-thumbnail.jpg
vendored
Normal file
BIN
packages/tests/fixtures/default-live-thumbnail.jpg
vendored
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
|
@ -27,6 +27,7 @@ import {
|
|||
waitUntilLiveReplacedByReplayOnAllServers,
|
||||
waitUntilLiveWaitingOnAllServers
|
||||
} from '@peertube/peertube-server-commands'
|
||||
import { testImageGeneratedByFFmpeg } from '@tests/shared/checks.js'
|
||||
import { checkLiveCleanup } from '@tests/shared/live.js'
|
||||
import { expect } from 'chai'
|
||||
import { FfmpegCommand } from 'fluent-ffmpeg'
|
||||
|
@ -36,7 +37,13 @@ describe('Save replay setting', function () {
|
|||
let liveVideoUUID: string
|
||||
let ffmpegCommand: FfmpegCommand
|
||||
|
||||
async function createLiveWrapper (options: { permanent: boolean, replay: boolean, replaySettings?: { privacy: VideoPrivacyType } }) {
|
||||
async function createLiveWrapper (options: {
|
||||
permanent: boolean
|
||||
replay: boolean
|
||||
replaySettings?: { privacy: VideoPrivacyType }
|
||||
thumbnailfile?: string
|
||||
previewfile?: string
|
||||
}) {
|
||||
if (liveVideoUUID) {
|
||||
try {
|
||||
await servers[0].videos.remove({ id: liveVideoUUID })
|
||||
|
@ -51,7 +58,9 @@ describe('Save replay setting', function () {
|
|||
tags: [ 'tag1', 'tag2' ],
|
||||
saveReplay: options.replay,
|
||||
replaySettings: options.replaySettings,
|
||||
permanentLive: options.permanent
|
||||
permanentLive: options.permanent,
|
||||
thumbnailfile: options.thumbnailfile,
|
||||
previewfile: options.previewfile
|
||||
}
|
||||
|
||||
const { uuid } = await servers[0].live.create({ fields: attributes })
|
||||
|
@ -142,6 +151,15 @@ describe('Save replay setting', function () {
|
|||
}
|
||||
}
|
||||
|
||||
async function checkVideoThumbnail (videoId: string, thumbnailfile: string, previewfile?: string) {
|
||||
for (const server of servers) {
|
||||
const video = await server.videos.get({ id: videoId })
|
||||
await testImageGeneratedByFFmpeg(server.url, thumbnailfile, video.thumbnailPath, '')
|
||||
|
||||
if (previewfile) await testImageGeneratedByFFmpeg(server.url, previewfile, video.previewPath, '')
|
||||
}
|
||||
}
|
||||
|
||||
before(async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
|
@ -285,6 +303,7 @@ describe('Save replay setting', function () {
|
|||
await checkVideosExist(liveVideoUUID, 0, HttpStatusCode.OK_200)
|
||||
await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE)
|
||||
await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC)
|
||||
await checkVideoThumbnail(liveVideoUUID, 'default-live-thumbnail.jpg', 'default-live-preview.jpg')
|
||||
})
|
||||
|
||||
it('Should correctly have updated the live and federated it when streaming in the live', async function () {
|
||||
|
@ -298,6 +317,7 @@ describe('Save replay setting', function () {
|
|||
await checkVideosExist(liveVideoUUID, 1, HttpStatusCode.OK_200)
|
||||
await checkVideoState(liveVideoUUID, VideoState.PUBLISHED)
|
||||
await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC)
|
||||
await checkVideoThumbnail(liveVideoUUID, 'default-live-thumbnail.jpg', 'default-live-preview.jpg')
|
||||
})
|
||||
|
||||
it('Should correctly have saved the live and federated it after the streaming', async function () {
|
||||
|
@ -345,7 +365,15 @@ describe('Save replay setting', function () {
|
|||
it('Should update the saved live and correctly federate the updated attributes', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
await servers[0].videos.update({ id: liveVideoUUID, attributes: { name: 'video updated', privacy: VideoPrivacy.PUBLIC } })
|
||||
await servers[0].videos.update({
|
||||
id: liveVideoUUID,
|
||||
attributes: {
|
||||
name: 'video updated',
|
||||
privacy: VideoPrivacy.PUBLIC,
|
||||
thumbnailfile: 'custom-thumbnail.jpg',
|
||||
previewfile: 'custom-preview.jpg'
|
||||
}
|
||||
})
|
||||
await waitJobs(servers)
|
||||
|
||||
for (const server of servers) {
|
||||
|
@ -353,6 +381,8 @@ describe('Save replay setting', function () {
|
|||
expect(video.name).to.equal('video updated')
|
||||
expect(video.isLive).to.be.false
|
||||
expect(video.privacy.id).to.equal(VideoPrivacy.PUBLIC)
|
||||
|
||||
await checkVideoThumbnail(liveVideoUUID, 'custom-thumbnail.jpg', 'custom-preview.jpg')
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -406,13 +436,20 @@ describe('Save replay setting', function () {
|
|||
it('Should correctly create and federate the "waiting for stream" live', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
liveVideoUUID = await createLiveWrapper({ permanent: true, replay: true, replaySettings: { privacy: VideoPrivacy.UNLISTED } })
|
||||
liveVideoUUID = await createLiveWrapper({
|
||||
permanent: true,
|
||||
replay: true,
|
||||
replaySettings: { privacy: VideoPrivacy.UNLISTED },
|
||||
thumbnailfile: 'custom-thumbnail.jpg',
|
||||
previewfile: 'custom-preview.jpg'
|
||||
})
|
||||
|
||||
await waitJobs(servers)
|
||||
|
||||
await checkVideosExist(liveVideoUUID, 0, HttpStatusCode.OK_200)
|
||||
await checkVideoState(liveVideoUUID, VideoState.WAITING_FOR_LIVE)
|
||||
await checkVideoPrivacy(liveVideoUUID, VideoPrivacy.PUBLIC)
|
||||
await checkVideoThumbnail(liveVideoUUID, 'custom-thumbnail.jpg', 'custom-preview.jpg')
|
||||
})
|
||||
|
||||
it('Should correctly have updated the live and federated it when streaming in the live', async function () {
|
||||
|
@ -484,10 +521,19 @@ describe('Save replay setting', function () {
|
|||
await checkVideosExist(lastReplayUUID, 1, HttpStatusCode.OK_200)
|
||||
await checkVideoState(lastReplayUUID, VideoState.PUBLISHED)
|
||||
await checkVideoPrivacy(lastReplayUUID, VideoPrivacy.PUBLIC)
|
||||
await checkVideoThumbnail(lastReplayUUID, 'custom-thumbnail-from-preview.jpg', 'custom-preview.jpg')
|
||||
})
|
||||
|
||||
it('Should update the live replay thumbnail', async function () {
|
||||
await servers[0].videos.update({ id: lastReplayUUID, attributes: { thumbnailfile: 'custom-thumbnail-2.jpg' } })
|
||||
await waitJobs(servers)
|
||||
|
||||
await checkVideoThumbnail(liveVideoUUID, 'custom-thumbnail.jpg', 'custom-preview.jpg')
|
||||
await checkVideoThumbnail(lastReplayUUID, 'custom-thumbnail-2.jpg')
|
||||
})
|
||||
})
|
||||
|
||||
describe('With a second live and its replay', function () {
|
||||
describe('With a second live session', function () {
|
||||
|
||||
it('Should update the replay settings', async function () {
|
||||
await servers[0].live.update({ videoId: liveVideoUUID, fields: { replaySettings: { privacy: VideoPrivacy.PUBLIC } } })
|
||||
|
@ -498,7 +544,6 @@ describe('Save replay setting', function () {
|
|||
expect(live.saveReplay).to.be.true
|
||||
expect(live.replaySettings).to.exist
|
||||
expect(live.replaySettings.privacy).to.equal(VideoPrivacy.PUBLIC)
|
||||
|
||||
})
|
||||
|
||||
it('Should correctly have updated the live and federated it when streaming in the live', async function () {
|
||||
|
@ -572,6 +617,9 @@ describe('Save replay setting', function () {
|
|||
|
||||
await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: true, deleted: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('With terminated sessions', function () {
|
||||
|
||||
it('Should correctly terminate the stream on blacklist and blacklist the saved replay video', async function () {
|
||||
this.timeout(120000)
|
||||
|
@ -612,6 +660,42 @@ describe('Save replay setting', function () {
|
|||
await checkLiveCleanup({ server: servers[0], videoUUID: liveVideoUUID, permanent: true, deleted: true })
|
||||
})
|
||||
})
|
||||
|
||||
describe('With a live without custom thumbnail', function () {
|
||||
|
||||
it('Should correctly set the default thumbnail to the live replay', async function () {
|
||||
this.timeout(120000)
|
||||
|
||||
liveVideoUUID = await createLiveWrapper({
|
||||
permanent: true,
|
||||
replay: true,
|
||||
replaySettings: { privacy: VideoPrivacy.PUBLIC }
|
||||
})
|
||||
|
||||
ffmpegCommand = await servers[0].live.sendRTMPStreamInVideo({ videoId: liveVideoUUID })
|
||||
await waitUntilLivePublishedOnAllServers(servers, liveVideoUUID)
|
||||
await stopFfmpeg(ffmpegCommand)
|
||||
|
||||
await waitUntilLiveWaitingOnAllServers(servers, liveVideoUUID)
|
||||
await waitJobs(servers)
|
||||
|
||||
const video = await findExternalSavedVideo(servers[0], liveVideoUUID)
|
||||
lastReplayUUID = video.uuid
|
||||
|
||||
await checkVideoThumbnail(liveVideoUUID, 'default-live-thumbnail.jpg', 'default-live-preview.jpg')
|
||||
})
|
||||
|
||||
it('Should update the live replay thumbnail', async function () {
|
||||
await servers[0].videos.update({
|
||||
id: lastReplayUUID,
|
||||
attributes: { thumbnailfile: 'custom-thumbnail.jpg', previewfile: 'custom-preview.jpg' }
|
||||
})
|
||||
await waitJobs(servers)
|
||||
|
||||
await checkVideoThumbnail(liveVideoUUID, 'default-live-thumbnail.jpg', 'default-live-preview.jpg')
|
||||
await checkVideoThumbnail(lastReplayUUID, 'custom-thumbnail.jpg', 'custom-preview.jpg')
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
|
|
|
@ -290,6 +290,23 @@ describe('Test video transcoding limits', function () {
|
|||
expect(video.files[0].resolution.id).to.equal(720)
|
||||
expect(hlsFiles[0].resolution.id).to.equal(720)
|
||||
})
|
||||
|
||||
it('Should keep input resolution if only upper resolutions are enabled', async function () {
|
||||
this.timeout(120_000)
|
||||
|
||||
await servers[0].config.enableTranscoding({ resolutions: [ 0, 1080 ], keepOriginal: false })
|
||||
|
||||
const { uuid } = await servers[0].videos.quickUpload({ name: 'video', fixture: 'video_short.webm' })
|
||||
await waitJobs(servers)
|
||||
|
||||
const video = await servers[0].videos.get({ id: uuid })
|
||||
const hlsFiles = video.streamingPlaylists[0].files
|
||||
|
||||
expect(video.files).to.have.lengthOf(2)
|
||||
expect(hlsFiles).to.have.lengthOf(2)
|
||||
|
||||
expect(getAllFiles(video).map(f => f.resolution.id)).to.have.members([ 720, 720, 0, 0 ])
|
||||
})
|
||||
})
|
||||
|
||||
after(async function () {
|
||||
|
|
|
@ -179,7 +179,7 @@ async function createVideoPlaylist (req: express.Request, res: express.Response)
|
|||
videoPlaylist.VideoChannel = videoChannel
|
||||
}
|
||||
|
||||
const thumbnailField = req.files['thumbnailfile']
|
||||
const thumbnailField = req.files?.['thumbnailfile']
|
||||
const thumbnailModel = thumbnailField
|
||||
? await updateLocalPlaylistMiniatureFromExisting({
|
||||
inputPath: thumbnailField[0].path,
|
||||
|
@ -220,7 +220,7 @@ async function updateVideoPlaylist (req: express.Request, res: express.Response)
|
|||
const wasPrivatePlaylist = videoPlaylistInstance.privacy === VideoPlaylistPrivacy.PRIVATE
|
||||
const wasNotPrivatePlaylist = videoPlaylistInstance.privacy !== VideoPlaylistPrivacy.PRIVATE
|
||||
|
||||
const thumbnailField = req.files['thumbnailfile']
|
||||
const thumbnailField = req.files?.['thumbnailfile']
|
||||
const thumbnailModel = thumbnailField
|
||||
? await updateLocalPlaylistMiniatureFromExisting({
|
||||
inputPath: thumbnailField[0].path,
|
||||
|
|
|
@ -1337,6 +1337,7 @@ function buildVideoMimetypeExt () {
|
|||
|
||||
// Developed by Apple
|
||||
'video/quicktime': [ '.mov', '.qt', '.mqv' ], // often used as output format by editing software
|
||||
'video/mov': '.mov', // Windows: https://github.com/Chocobozzz/PeerTube/issues/6669
|
||||
'video/x-m4v': '.m4v',
|
||||
'video/m4v': '.m4v',
|
||||
|
||||
|
|
|
@ -209,7 +209,8 @@ async function copyOrRegenerateThumbnails (options: {
|
|||
inputPath: preview.getPath(),
|
||||
video: replayVideo,
|
||||
type,
|
||||
automaticallyGenerated: false
|
||||
automaticallyGenerated: false,
|
||||
keepOriginal: true
|
||||
})
|
||||
})
|
||||
)
|
||||
|
|
|
@ -16,7 +16,10 @@ export function buildOriginalFileResolution (inputResolution: number) {
|
|||
hasAudio: true
|
||||
})
|
||||
|
||||
if (resolutions.length === 0) {
|
||||
if (
|
||||
resolutions.length === 0 ||
|
||||
(resolutions.length === 1 && resolutions[0] === VideoResolution.H_NOVIDEO)
|
||||
) {
|
||||
return toEven(inputResolution)
|
||||
}
|
||||
|
||||
|
@ -58,7 +61,7 @@ export function computeResolutionsToTranscode (options: {
|
|||
if (input < resolution) continue
|
||||
// We only want lower resolutions than input file
|
||||
if (strictLower && input === resolution) continue
|
||||
// Audio resolutio but no audio in the video
|
||||
// Audio resolution but no audio in the video
|
||||
if (resolution === VideoResolution.H_NOVIDEO && !hasAudio) continue
|
||||
|
||||
resolutionsEnabled.add(resolution)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue