Upload files to "src"
This commit is contained in:
96
src/video.ts
Normal file
96
src/video.ts
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
import ffmpeg from 'fluent-ffmpeg';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
const MAX_SIZE = 100 * 1024 * 1024
|
||||||
|
const MAX_DURATION = 180
|
||||||
|
|
||||||
|
export async function compressVideo(inputUrl: string, outputPath: string): Promise<string> {
|
||||||
|
const axios = (await import('axios')).default
|
||||||
|
const response = await axios.get(inputUrl, {
|
||||||
|
responseType: 'arraybuffer',
|
||||||
|
headers: {
|
||||||
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
||||||
|
},
|
||||||
|
timeout: 60000
|
||||||
|
})
|
||||||
|
const tempInput = outputPath + '.input.mp4'
|
||||||
|
fs.writeFileSync(tempInput, new Uint8Array(response.data))
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
ffmpeg.ffprobe(tempInput, (err, metadata) => {
|
||||||
|
if (err) {
|
||||||
|
try { fs.unlinkSync(tempInput) } catch {}
|
||||||
|
return reject(err)
|
||||||
|
}
|
||||||
|
const duration = metadata.format.duration || 0
|
||||||
|
const trimDuration = Math.min(duration, MAX_DURATION)
|
||||||
|
ffmpeg(tempInput)
|
||||||
|
.outputOptions([
|
||||||
|
'-c:v libx264',
|
||||||
|
'-profile:v main',
|
||||||
|
'-level:v 4.0',
|
||||||
|
'-crf 23',
|
||||||
|
'-preset medium',
|
||||||
|
'-c:a aac',
|
||||||
|
'-b:a 128k',
|
||||||
|
'-ar 48000',
|
||||||
|
'-ac 2',
|
||||||
|
'-vf scale=\'min(1920,iw)\':\'min(1080,ih)\':force_original_aspect_ratio=decrease,format=yuv420p',
|
||||||
|
'-movflags +faststart',
|
||||||
|
'-max_muxing_queue_size 1024',
|
||||||
|
`-t ${trimDuration}`
|
||||||
|
])
|
||||||
|
.output(outputPath)
|
||||||
|
.on('end', () => {
|
||||||
|
try { fs.unlinkSync(tempInput) } catch {}
|
||||||
|
const stats = fs.statSync(outputPath)
|
||||||
|
if (stats.size > MAX_SIZE) {
|
||||||
|
fs.unlinkSync(outputPath)
|
||||||
|
fs.writeFileSync(tempInput, new Uint8Array(response.data))
|
||||||
|
ffmpeg(tempInput)
|
||||||
|
.outputOptions([
|
||||||
|
'-c:v libx264',
|
||||||
|
'-profile:v main',
|
||||||
|
'-crf 28',
|
||||||
|
'-preset fast',
|
||||||
|
'-c:a aac',
|
||||||
|
'-b:a 96k',
|
||||||
|
'-ar 48000',
|
||||||
|
'-ac 2',
|
||||||
|
'-vf scale=\'min(1280,iw)\':\'min(720,ih)\':force_original_aspect_ratio=decrease,format=yuv420p',
|
||||||
|
'-movflags +faststart',
|
||||||
|
`-t ${trimDuration}`
|
||||||
|
])
|
||||||
|
.output(outputPath)
|
||||||
|
.on('end', () => {
|
||||||
|
try { fs.unlinkSync(tempInput) } catch {}
|
||||||
|
resolve(outputPath)
|
||||||
|
})
|
||||||
|
.on('error', (err) => {
|
||||||
|
try { fs.unlinkSync(tempInput) } catch {}
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
} else {
|
||||||
|
resolve(outputPath)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on('error', (err) => {
|
||||||
|
try { fs.unlinkSync(tempInput) } catch {}
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
.run()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function cleanupTempFiles(dir: string = './temp') {
|
||||||
|
if (fs.existsSync(dir)) {
|
||||||
|
const files = fs.readdirSync(dir);
|
||||||
|
for (const file of files) {
|
||||||
|
try {
|
||||||
|
fs.unlinkSync(path.join(dir, file));
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user