iT邦幫忙

2025 iThome 鐵人賽

DAY 16
0

前情提要

因為這兩週工作繁忙所以一直還沒更新架構圖,先來盤點一下已經實作的 API 和後續想到需要進行的 API。 今天在利用已經做好的網頁進行上傳備份手機影片時,發現第一點是,之前寫得匆忙,僅允許了 mp4 格式,忽略了其他常見的影音格式如 mov;缺少了查看已經上傳的影片的功能。 先列出已完成開發,和要開發的功能在下面。

影片連結: https://www.youtube.com/shorts/CsW2VxkFGIw

已完成

https://ithelp.ithome.com.tw/upload/images/20250927/20130149IH2hPDW3CE.png

  1. ANY /generate-url

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

  2. POST /login

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

  3. GET /login

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

  4. ANY /register

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

  5. GET /validate

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

待開發

  1. 使用者上傳完影片,需要在前端呈現。 顯示已經放在 S3 中的媒體 list-video

    看不到自己有哪些放在 S3 的資料,每次都要從 AWS console 或是指令查看,也說不過去。

  2. 指定影片,進行 逐字稿(字幕)產生/generate-subtitle
  3. 指定影片,進行 逐字稿翻譯/translate-url

修正:支援多種影音格式上傳

  • 這邊我後面會更新 gitHub commit。

開發:顯示 S3 已儲存影片

共四處需更動:

  • Lambda Function
  • API GW 加入新路徑
  • 前端頁面多新的區塊
  • 前端使用 javascript 加入新邏輯

Lambda / list-videos

import os
import json
import boto3
import jwt
import urllib.parse

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

def lambda_handler(event, context):
    method = event.get("requestContext", {}).get("http", {}).get("method")
    print("🔎 method:", method)
    print("🔎 event:", json.dumps(event))

    # --- CORS 預檢請求 (OPTIONS) ---
    if method == "OPTIONS":
        return {
            "statusCode": 200,
            "headers": {
                "Access-Control-Allow-Origin": "https://vlog.nipapa.tw",
                "Access-Control-Allow-Methods": "GET,OPTIONS",
                "Access-Control-Allow-Headers": "Authorization,Content-Type",
                "Access-Control-Max-Age": "3600"
            },
            "body": ""
        }

    # --- 驗證 JWT ---
    headers = event.get("headers", {}) or {}
    auth = headers.get("authorization") or headers.get("Authorization") or ""
    if not auth.startswith("Bearer "):
        return _unauthorized("Missing token")

    token = auth.split(" ")[1]

    try:
        decoded = jwt.decode(token, SECRET, algorithms=["HS256"])
        username = decoded.get("username", "unknown")
    except Exception as e:
        return _unauthorized("Invalid token")

    # --- GET: 列出影片 ---
    if method == "GET":
        try:
            resp = s3.list_objects_v2(
                Bucket=BUCKET_NAME,
                Prefix=f"{username}/"
            )
            items = []
            for obj in resp.get("Contents", []):
                key = obj["Key"]
                decoded_name = urllib.parse.unquote(key.split("/")[-1])
                url = s3.generate_presigned_url(
                    "get_object",
                    Params={"Bucket": BUCKET_NAME, "Key": key},
                    ExpiresIn=3600   # 1 小時有效
                )
                items.append({
                    "key": key,
                    "decodedName": decoded_name,
                    "url": url,
                    "size": obj["Size"]
                })
        except Exception as e:
            return _server_error(str(e))

        return {
            "statusCode": 200,
            "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
            "body": json.dumps(items, ensure_ascii=False)  # ✅ 確保中文不轉義
        }

    return {"statusCode": 405, "body": "Method not allowed"}


# ---- Helpers ----
def _unauthorized(msg):
    return {
        "statusCode": 401,
        "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
        "body": json.dumps({"error": msg}, ensure_ascii=False)
    }

def _server_error(msg):
    return {
        "statusCode": 500,
        "headers": {"Access-Control-Allow-Origin": "https://vlog.nipapa.tw"},
        "body": json.dumps({"error": msg}, ensure_ascii=False)
    }


結論

  • 可以顯示了,那好像缺少「刪除」功能。 下回待續

上一篇
【Day 15】 持續增加 API 一直卡住怎麼除錯? 快快去看 CloudWatch Log
下一篇
【Day 17】 利用 S3 Event Trigger 捕捉事件,自動觸發 Amazon Lambda 產生縮圖
系列文
無法成為片師也想拍 Vlog?!個人影音小工具的誕生!17
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言