iT邦幫忙

2025 iThome 鐵人賽

DAY 17
0

前情提要

看著慢慢成形的頁面,發現缺少了刪除影片的功能外,還希望這些影片連結,可以用 Grid 的方式排列,顯示一下縮圖吧! 以下繼續開發缺少功能。

已完成

  1. ANY /generate-url

    一旦確立身份,用來產生上傳影片到 S3 的臨時網址

  2. POST /login

    使用者在登入頁面打完帳號密碼,透過此 API 送給後端程式進行 登入程序

  3. GET /login

    將請求轉導到 網站的 login.html 頁面

  4. ANY /register

    使用者在登入頁面打完帳號密碼,透過此 API 送給後端程式進行 註冊程序

  5. GET /validate

    用來檢查使用者瀏覽器中的 jwt 是否有效,藉此 驗證登入狀態

  6. ANY /list-videos

    用來檢視之前上傳過的影片、

待開發

  1. 指定影片,進行 逐字稿(字幕)產生/generate-subtitle
  2. 指定影片,進行 逐字稿翻譯/translate-url
  3. 增加 S3 Event Trigger,當檔案被新增到 S3 影片收容 Bucket 後,透過指令去產出縮圖。
  4. 顯示刪除影片的按鈕。

縮圖產生機制

  1. 使用者上傳影片 到 exsky-backup-media
  2. S3 Event 觸發 Lambda(ObjectCreated:*)
  3. Lambda:
    • 下載 S3 上傳的檔案到 /tmp/。
    • 用 ffmpeg 擷取一張圖片(封面 / 第一秒畫面)。
    • 將圖片(JPEG/PNG)上傳回 S3(例如 covers/xxx.jpg)。
  4. 前端就能在 list-videos API 回傳 cover URL。

製作 ffmpeg Lambda Layer

  • 在 Linux 環境中,下載 ffmpeg
mkdir -p layer/bin
cd layer

curl -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz -o ffmpeg.tar.xz
tar -xJf ffmpeg.tar.xz
mv ffmpeg-*-amd64-static/ffmpeg bin/
mv ffmpeg-*-amd64-static/ffprobe bin/

zip -r ffmpeg-layer.zip bin/

  • 如果 zip file 超過了 50MB 限制,那就必須先手動上傳到 S3 再進行匯入
aws s3 cp layer/ffmpeg-layer.zip s3://exsky-vlog-web/ffmpeg-layer.zip

aws lambda publish-layer-version \                                                 
  --layer-name ffmpeg \
  --content S3Bucket=exsky-vlog-web,S3Key=ffmpeg-layer.zip \
  --compatible-runtimes python3.9 python3.10 python3.11 python3.12 python3.13

Lambda Function / 產生 Cover

import os
import boto3
import subprocess

s3 = boto3.client("s3")
BUCKET_NAME = os.environ.get("BUCKET_NAME", "exsky-backup-media")

def lambda_handler(event, context):
    print("🔎 event:", event)

    # 從 S3 事件取出檔案資訊
    record = event["Records"][0]
    bucket = record["s3"]["bucket"]["name"]
    key = record["s3"]["object"]["key"]

    if not key.lower().endswith((".mp4", ".mov", ".mkv")):
        print("⚠️ Not a video file, skip")
        return

    # 下載影片到 Lambda 的 /tmp
    local_video = f"/tmp/{os.path.basename(key)}"
    local_cover = f"/tmp/{os.path.basename(key)}.jpg"

    s3.download_file(bucket, key, local_video)

    # 用 ffmpeg 擷取 1 秒的畫面作為封面
    cmd = [
        "/opt/ffmpeg/ffmpeg",   # ffmpeg Layer 的路徑(不同 Layer 可能略有不同)
        "-i", local_video,
        "-ss", "00:00:01",     # 擷取 1 秒畫面
        "-vframes", "1",
        "-vf", "scale=320:-1", # 等比例縮小到寬 320px
        local_cover
    ]
    subprocess.run(cmd, check=True)

    # 上傳回 S3 → 放在 covers/ 底下
    cover_key = f"covers/{os.path.splitext(os.path.basename(key))[0]}.jpg"
    s3.upload_file(local_cover, bucket, cover_key, ExtraArgs={"ContentType": "image/jpeg"})

    print(f"✅ Cover generated: s3://{bucket}/{cover_key}")

    return {
        "statusCode": 200,
        "body": f"Cover generated at s3://{bucket}/{cover_key}"
    }

綁定 S3 Event

  • 在 S3 Bucket → Properties → Event Notifications
    https://ithelp.ithome.com.tw/upload/images/20250928/20130149KlJMFhPkPN.png
  • 新增 event,設定觸發 ObjectCreated:*
    https://ithelp.ithome.com.tw/upload/images/20250928/20130149IijvgWK2xl.png
  • 綁定 Lambda
    https://ithelp.ithome.com.tw/upload/images/20250928/20130149WPXs8pIRsb.png

結論

  • 透過 S3 Event Trigger 可以完美精準的在適當時間,觸發縮圖產生。
  • 顯示影片縮圖是為了使用者體驗,只看檔名有時候真的不知道裡面是什麼影片。

Ref


上一篇
【Day 16】 修正:支援多種影音格式上傳 / 開發:顯示 S3 已儲存內容
系列文
無法成為片師也想拍 Vlog?!個人影音小工具的誕生!17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言