Thumbnails on video assets #883
Replies: 3 comments 1 reply
-
I have similar case but with lottie animations which are jsons, i think good idea would be to allow to pass custom component into admin thumbnail config so you could render whatever you want for any file type |
Beta Was this translation helpful? Give feedback.
-
We are trying to work on it now on latest beta ffmpeg is not trivial to work with next.js here few things we managed so far: serverExternalPackages: ["ffmpeg-static"], We started hook beforeChange on Media: import ffmpeg from 'fluent-ffmpeg'
import ffmpegStatic from 'ffmpeg-static'
import fs from 'fs'
ffmpeg.setFfmpegPath(ffmpegStatic)
export const videoCoverImage: CollectionBeforeChangeHook = async ({ data, req }) => {
'use server'
try {
if (req.file) {
const tempFilePath = 'TBD/temp.mp4'
const outputPath="TBD/cover.jpg"
fs.writeFileSync(tempFilePath, req.file.data)
// Extract the first frame
await ffmpeg()
.input(tempFilePath)
.videoFilters('select=eq(n\\,0)') // Select first frame
.output(outputPath)
.run()
// Remove the temporary file
//fs.unlinkSync(tempFilePath)
}
console.log(data)
return data
} catch (error) {
console.error('<<<<<<<<<< Error processing video cover image:', (error as Error).message)
throw new Error('Video cover image processing failed.')
}
} There are few things we need to resolve like:
|
Beta Was this translation helpful? Give feedback.
-
I've implemented it successfully. In my async ({ args, operation, req }) => {
const TMP_PATH = "media/tmp";
if (
['create', 'update'].includes(operation) &&
req.file &&
!req.data.placeholder
) {
let tempFilePath = `${TMP_PATH}/${uuidv4().replaceAll('-', '')}.${
req.file.name.split('.').pop() || 'webp'
}`
const outputPath = `${TMP_PATH}/${uuidv4()}.webp`
if (req.file?.tempFilePath) {
tempFilePath = req.file.tempFilePath
} else {
fs.writeFileSync(tempFilePath, req.file!.data)
}
try {
await extractFirstFrame(tempFilePath, outputPath)
const fileData = fs.readFileSync(outputPath)
const filename = req.file!.name.split('.').shift()
const mimeType = 'image/webp'
const filesize = fs.statSync(outputPath).size
const mediaDoc = await req.payload.create({
collection: 'media',
data: {
filename,
mimeType,
filesize,
},
file: {
data: fileData,
name: filename,
mimetype: mimeType,
size: filesize,
},
})
req.data!.placeholder = mediaDoc.id
} catch (error) {
req.payload.logger.error('Error in beforeOperation hook:', error)
}
if (!req.file?.tempFilePath && fs.existsSync(tempFilePath)) {
fs.unlinkSync(tempFilePath)
}
if (fs.existsSync(outputPath)) {
fs.unlinkSync(outputPath)
}
}
return args
} with also this function async function extractFirstFrame(inputPath: string, outputPath: string): Promise<void> {
return new Promise<void>((resolve, reject) => {
ffmpeg()
.input(inputPath)
.videoFilters('select=eq(n\\,0)') // Select first frame
.output(outputPath)
.on('end', () => {
resolve()
})
.on('error', (err) => {
console.log('Error:', err)
reject(err)
})
.run()
})
} Some notes
|
Beta Was this translation helpful? Give feedback.
-
The title is pretty much self explanatory. I have a large video database on my site, and was wondering if I could achieve a way to display a thumbnail to quickly identify files. I was planning on using some npm library to generate the image file and then use adminThumbnail to point to that file. But the docs specify if the file is not an image this function is disregarded.
Any ideas are welcome. Thanks in advance.
Beta Was this translation helpful? Give feedback.
All reactions