はじめに
こちらの記事は過去に作成した記事に機能を追加してみたものになります
過去の記事に目を通してからみていただくと良いかもしれません
何をしたかったか
元々の機能としてはFast APIで作成したエンドポイントにURLを渡した時に、動画ファイルがダウンロードできるようにするという名目で作成しました
そして、作成できたものとしてはdocker経由でコンテナを立てた後に、ローカル内でファイルをダウンロードして保存するという機能でした
これでは、保存した後に一旦ファイルが保存された場所まで確認しにいかなければいけません
今回の修正では、エンドポイントにリクエストを送った際に実際に動画ファイルが返却される(=保存される)という内容に変更してみたいと思います
やったこと
Fast APIでファイルをレスポンスする際に使用できるものといえば「FileResponse」・「StreamResponse」の2つくらいがあると思います
自分の理解では
FileResponseがファイルの準備が完璧になってからレスポンスを返すもの
StreamResponseが逐次レスポンスを返すもの
というような認識です
フロントと結合する際、ダウンロード中に動作ができなくなるのが個人的に好きではないので「StreamResponse」を使って動画ファイルを返却できるようにしてみました
これまでは以下のようにファイルをただローカルに保存していました
with YoutubeDL(ytdlp_opts) as ydl:
ydl.download(target_url)
そこから以下のように処理を加えました(importなど省略しているものはあります)
def generate_unique_filename():
return str(uuid.uuid4()) + ".mp4"
@app.post("/yt_download")
async def download_yt_video(jsonbody: get_yt):
try:
filename = generate_unique_filename()
ytdlp_opts = {
"format": "best[ext=mp4]",
"outtmpl": filename
}
with YoutubeDL(ytdlp_opts) as ydl:
ydl.download(target_url)
return StreamingResponse(
open(filename, "rb"),
media_type="video/mp4",
headers={"Content-Disposition": "attachment; filename=video.mp4"}
)
except:......
<省略>
変更点
-
これまでは動画ファイルの名称が「URL先の動画のタイトル.mp4」という形で保存するようにしていました
- この問題点は、同じ動画を保存しようとした場合にダウンロード処理がされないというところが問題でした
- なので「uuid.mp4」という形式で動画ファイルを保存できるようにしました
- (今考えると、ダウンロード処理をスキップできるようにすれば、同じものをダウンロードしたい人がいた時に時間が省略ができたかもしれないとも思います)
-
ytdlp_optsのオプション追加
- outtmpl
- 出力先の指定
- 名前の付け方変えたので、ここを変えないとダメですね
- outtmpl
-
return StreamingResponse
- ここが今回の肝になります
- 一時的にファイルを保存してその内容をopenで読み込み、StreamingResponseの処理に乗っけるような形にしています
結果
この状態で以下のような形でcurlを実行してみると、実行したディレクトリ内にファイルがダウンロードされるようになりました
curl -vX "POST" "http://localhost:xxxx/yt_download" -d "{\"url\": \"https://www.youtube.com/watch?v=xxxxxxx\"}" -H 'Content-Type: application/json' -o video.mp4
おわりに
ということで今回はStreaminResponseを使ってみたというところでした
これができるようになったということは、フロントエンドにこの情報を渡して画面からファイルがダウンロードできるようになるのかなとイメージしております
次回はその内容で記事が書ければと思います