from flask import Flask, request, send_file, abort
import ffmpeg
import os
import tempfile
import time
app = Flask(__name__)
@app.route('/audio_appledevices/<name>.m4a', methods=['GET'])
def convert_audio(name):
ogg_path = f'./audio/{name}.ogg'
if not os.path.exists(ogg_path):
abort(404)
with tempfile.NamedTemporaryFile(delete=False, suffix='.m4a') as temp_file:
m4a_path = temp_file.name
try:
ffmpeg.input(ogg_path).output(m4a_path, codec='alac').run(overwrite_output=True)
response = send_file(m4a_path, as_attachment=True, download_name=f'{name}.m4a', mimetype='audio/mp4')
@response.call_on_close
def cleanup():
time.sleep(1)
if os.path.exists(m4a_path):
os.remove(m4a_path)
return response
except ffmpeg.Error as e:
abort(500)
if __name__ == '__main__':
app.run(host='127.0.0.1', port=3389)
除非另开一个线程,不管怎么写临时文件都不能被自动删掉,要不就是 ffmpeg 写不进文件,因为临时文件被占用。 因为 ffmpeg 需要 seekable 的流,所以输出到 IO 流不可行。
1
esile 115 天前 via Android
当然异步队列处理+定时删除
|
2
expy 115 天前
try except 一般在 finally 里清理吧。
偏题一下,你这 ogg 转 alac ,ogg 是无损吗? |
3
ho121 115 天前 via Android
用临时目录 tempfile.TemporaryDirectory ,所有临时文件写到这个目录里,任务结束后删掉整个目录
|
4
sunnysab 115 天前 via Android
猜想:tempfile 是基于操作系统临时文件功能实现的(原理是,Windows 下 CreateFile 有个参数指示,Linux 下有 open )。尝试把 delete 参数置为 True (默认值)。
另外,有没有可能是共享写的问题,把打开方式设为 'r+b'。ffmpeg 需要处于同一用户中,这点是应该满足的,实在不行 strace 一下看看是哪一步无权限。 捉个虫,标题中应该是“最佳实践”,而不是“最佳实际”。 |
5
sazima 115 天前
bytesio:
```python process = ( ffmpeg .input(ogg_path) .output('pipe:', format='wav') .run_async(pipe_stdout=True, pipe_stderr=True) ) out, err = process.communicate() io = BytesIO(out) # 创建响应并设置合适的头信息 response = make_response(send_file(io, mimetype='application/octet-stream', as_attachment=True, download_name='example.mp3')) response.headers['Content-Disposition'] = 'attachment; filename=example.bin' return response ``` |
6
sazima 115 天前
更正:
response.headers['Content-Disposition'] = 'attachment; filename=example.mp3' |
7
Haku 115 天前
定时任务删除转换完后超过 x 天的文件。
|
8
rsyjjsn 115 天前 4
网友只是提供一个解决问题的思路给你,你咋老想着网友写好代码,测试通过,原封不动的回复给你呢?
|
9
justNoBody 115 天前 3
> 请先测试再回复!我让 GPT-4 写了几十个版本,没有一个能用。
???测试再回复???你给我 3000 美金我考虑一下 |
10
0o0O0o0O0o 115 天前
你这天天提上班遇到的问题面向 V2EX 上班已经不满足了,还要回答的人自行测试。。。工资给大伙分一下吧
|
11
lsk569937453 115 天前
笑死。。。。这是面向 V2EX 编程的社会实践吗?
|
12
Hopetree 115 天前
既然是临时文件,当然是规定好清理规则,定时任务定时清理 N 天前生成的文件啊,又简单又快速
|
13
djasdjds 115 天前
😅很难想象这是求问的态度
|
14
Wh1t3zZ 115 天前 1
伸手党还这么理直气壮?
|
15
gwy15 115 天前
我欠你的
|
16
deplives 115 天前
原来 op 就是那个 CORS 和 CSRF 都分不清的人 https://v2ex.com/t/1057881
|
17
deplives 115 天前
|
18
drymonfidelia OP @expy 不是,所以要定时删除,ogg 源文件有几 TB
@ho121 @sunnysab 这两种方案我都尝试了,执行到 return 那边就会因为文件被 flask 占用无法删除报 500 错误 @sazima 需要 alac 的输出,alac 需要 seekable 的流 @rsyjjsn @justNoBody @0o0O0o0O0o @lsk569937453 @djasdjds @gwy15 这个问题远没有那么容易解决,我已经想到会有大量无效答案了,写一下试试能不能减少一些 |
19
vituralfuture 115 天前 via Android 1
没能把答案喂给你真是抱歉
|
20
drymonfidelia OP @rsyjjsn
@justNoBody @0o0O0o0O0o @lsk569937453 @djasdjds @gwy15 只是讨论最佳实践,我已经用脏实现写了个 cron 定时 rm * 来交差了,知道最佳实践也不会比别人得到更多好处 不会可以不回答,没必要只会阴阳怪气 |
21
amlee 115 天前
@drymonfidelia 不会可以不要问,没必要理直气壮
|
22
tomczhen 115 天前
写了,测了,但是不想发了。( doge
|
23
tangtang369 115 天前
这样好像可以删除掉
``` from flask import Flask, request, send_file, abort,after_this_request import ffmpeg import os import tempfile import time app = Flask(__name__) @app.route('/audio_appledevices/<name>.m4a', methods=['GET']) def convert_audio(name): ogg_path = f'./audio/{name}.ogg' if not os.path.exists(ogg_path): abort(404) with tempfile.NamedTemporaryFile(delete=False, suffix='.m4a') as temp_file: m4a_path = temp_file.name try: ffmpeg.input(ogg_path).output(m4a_path, codec='alac').run(overwrite_output=True) response = send_file(m4a_path, as_attachment=True, download_name=f'{name}.m4a', mimetype='audio/mp4') print("run m4a_path",m4a_path) @after_this_request def cleanup(response): print("run cleanup") time.sleep(1) if os.path.exists(m4a_path): os.remove(m4a_path) return response return response except ffmpeg.Error as e: abort(500) if __name__ == '__main__': app.run(host='127.0.0.1', port=3389) ``` |
24
djasdjds 115 天前
@drymonfidelia #20 牛皮
|
25
drymonfidelia OP @tangtang369 还是没有删除掉,in cleanup
os.remove(m4a_path) PermissionError: [WinError 32] The process cannot access the file because it is being used by another process |
26
tangtang369 114 天前
@drymonfidelia #25 你是 windows 吗 这个我 mac 和 linux 测了没啥问题
|
27
drymonfidelia OP @tangtang369 是的,可能是因为 Windows 的问题
|