我目前正在使用 Svelte-Kit 和 Node.js 适配器将我的 Python 后端与 Svelte 前端合并。我有一个媒体文件作为缓冲区,我试图找出如何将所有内容保留在内存中,类似于我在 Python 中使用 BytesIO 实现的方法。
这是我尝试将其转换为 TypeScript / Node.js 的 Python 函数:
def get_duration(input: BytesIO):
command = "ffmpeg -i -".split(" ")
output = subprocess.run(
command,
input=input.read(),
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
duration = None
lines = output.stderr.decode().split("\n")
print(lines)
for line in lines:
if "Duration:" in line:
match = re.search(r"Duration: (\d+):(\d+):(\d+.\d+)", line)
if match:
hours = int(match.group(1))
minutes = int(match.group(2))
seconds = float(match.group(3))
duration = hours * 3600 + minutes * 60 + seconds
break
input.seek(0)
print(duration)
return duration
这个函数在 Python 中运行良好,但我不确定如何将其转换为 Node.js,同时将所有内容保留在内存中。我需要将字节通过管道传输到标准输入,并将标准输出和标准错误通过管道传输到内存中的对象。
我怀疑这可能涉及 Node.js 的“fs”库,但我不确定是否使用流或缓冲区。
注意:我没有在持续时间内使用 ffprobe,因为它在持续时间内不断产生零(可能是由于我这边的错误)。
我尝试过使用 GPT-4,搜索 Node.js 文档,并浏览 StackOverflow 以获取有关内存管道传输的答案。然而,我对 Node.js 不像对 Python 那样熟悉,而 Python 对对象的更高层次的抽象让我可以避免学习流、缓冲区、字节等。
GPT-4 表明不可能使用 Node.js 在 Python 函数中完成我所做的事情,但我发现这很难相信。
我还研究了 createWriteStream(),但第一个参数似乎需要一个 FileLike 对象,并且我认为 Buffer 不适合该上下文。
我已经通过可读和可写弄清楚了。由于标准输入上的错误,我遇到了测试提前退出的问题。事实证明,这是由 Vitest 使用多个工作人员运行测试引起的。我还切换回了 FFProbe,它似乎没有出现与 Python 相同的问题。
以下是返回视频或音频文件的持续时间(以秒为单位),同时将所有内容保留在内存中的样子:
export async function getDuration(input: Buffer): Promise<number | undefined> {
if (!Buffer.isBuffer(input)) {
throw new Error('Input must be a buffer.')
}
if (input.length === 0) {
throw new Error('Input must have a length.')
}
return new Promise((resolve, reject) => {
const output = spawn(
'ffprobe',
['-i', '-', '-show_entries', 'format=duration', '-print_format', 'json'],
{
stdio: ['pipe', 'pipe', 'pipe']
}
)
let jsonOutput = ''
output.stdout.on('data', (data) => {
jsonOutput += data
})
output.on('exit', (code, signal) => {
console.log(`ffprobe exited with code ${code} and signal ${signal}`)
if (code !== 0) {
reject(new Error(`FFprobe exited with code ${code}`))
return
}
try {
const { format } = JSON.parse(jsonOutput)
resolve(Number(format.duration))
} catch (err) {
reject(err)
}
})
// Create a Readable stream from the input buffer
const stream = new Readable()
stream.push(input)
stream.push(null) // indicates end-of-file
// Pipe the stream to the stdin of the ffprobe process
stream.pipe(output.stdin)
// Handle EPIPE error
output.stdin.on('error', (error) => {
if (error.code !== 'EPIPE') {
reject(error)
}
})
})
}
绝对比 Python 更冗长......
我想转码的方式是相同的,只是将输出管道改为可写。