概要
FastAPIを使用して動画リンクをリクエストボディに受け取りそのリンク先の動画を保存するというAPIを作成してみました
本題
FastAPIでリクエストボディを受け取る方法
今回はAPI実行時にリクエストボディ受け取るようにしたいので、PydanticのBaseModelをインポートしました
データモデルとしてはget_yt
としてリクエストボディにstr型を受け取れるように定義しています
また、リクエストパスとしては/yt_download
というパスを宣言し、get_ytで宣言したモデルに沿ったリクエストボディを受け取って処理するようにします
以下のサンプルコードを実行すると、リクエストボディに指定したurlがそのままレスポンスされます
import uvicorn
from fastapi import FastAPI # FastAPIを使うために必要
from pydantic import BaseModel # リクエストbodyを定義するために必要
app = FastAPI()
# 今回実施したいことのモデルをここで定義
class get_yt(BaseModel):
url: str
@app.post("/yt_download")
# 上で定義したモデルをAPI実行時に受け取るように設定
def download_yt_video(jsonbody: get_yt):
download_link = jsonbody.url
return download_link
if __name__ == "__main__":
uvicorn.run("main:app", reload=True)
出力結果
curl -sX "POST" "http://localhost:8080/yt_download" \
-d "{\"url\": \"https://www.example.com\"}" -H 'Content-Type: application/json'
"https://www.example.com"
ということで無事にリクエストボディの中身を受け取ってAPIの処理内で扱えるようになりました
URLから動画ファイルをダウンロードする方法
以下の記事などを参考にして、今回はyt-dlp
を使用して実装しました
(1)https://qiita.com/kuro_8193/items/31706b620d69993afd90
(2)https://qiita.com/shinkai_/items/7175215d7433b4cf150c
ダウンロード処理も記載したコードが以下になります
先ほどリクエストボディで受け取ってurlの内容をそのまま返却していた部分をダウンロード処理に変更しました
import uvicorn
import re
from fastapi import FastAPI # FastAPIを使うために必要
from pydantic import BaseModel # リクエストbodyを定義するために必要
from yt_dlp import YoutubeDL
URL_PATTERN = re.compile(r'http.*')
ytdlp_opts = {"format": "mp4"}
app = FastAPI()
class get_yt(BaseModel):
url: str
@app.post("/yt_download")
def download_yt_video(jsonbody: get_yt):
try:
download_link = jsonbody.url
with YoutubeDL(ytdlp_opts) as ydl:
if re.match(URL_PATTERN, download_link):
ydl.download(download_link)
else:
raise Exception
except Exception as e:
print(e)
if __name__ == "__main__":
uvicorn.run("main:app", reload=True)
おわりに
こんな感じで初めてのFastAPIによるAPI作成はこんな感じになりました
FastAPIの名前に違わず、APIの作成が素早く完了してしまいました
これはいろいろなAPI作ってしまう理由もわかります
また何かしら思い浮かび次第、記事にしていければと思いますのでまた見に来てください
(Dockerファイルなど一連のリソースを確認されたい方、試したい方はgithubの方もご覧ください)
(また、参考にした記事にもありますが、YouTubeなどの動画は当然 「複製して配布」 はNGですので取り扱いにはご注意ください、一切の責任を負いません)