-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.py
More file actions
98 lines (79 loc) · 3.24 KB
/
main.py
File metadata and controls
98 lines (79 loc) · 3.24 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import os
import secrets
from typing import Dict
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from livekit import api
load_dotenv()
app = FastAPI(title="LiveKit Viewer Token API")
# CORS 設定
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
API_KEY = os.getenv("LIVEKIT_API_KEY", "")
API_SECRET = os.getenv("LIVEKIT_API_SECRET", "")
SERVER_URL = os.getenv("LIVEKIT_SERVER_URL", "wss://your-project.livekit.cloud")
if not API_KEY or not API_SECRET:
raise ValueError("請在 .env 文件中設置 LIVEKIT_API_KEY 和 LIVEKIT_API_SECRET")
# 掛載靜態文件
app.mount("/static", StaticFiles(directory="static"), name="static")
@app.get("/", response_class=HTMLResponse)
async def root():
"""提供觀看者前端頁面"""
try:
with open("static/index.html", "r", encoding="utf-8") as f:
return HTMLResponse(content=f.read())
except FileNotFoundError:
return HTMLResponse(content="<h1>前端頁面未找到</h1><p>請確保 static/index.html 存在</p>")
@app.get("/mobile", response_class=HTMLResponse)
async def mobile_publisher():
"""提供手機直播發布者頁面"""
try:
with open("static/index2.html", "r", encoding="utf-8") as f:
return HTMLResponse(content=f.read())
except FileNotFoundError:
return HTMLResponse(content="<h1>手機直播頁面未找到</h1><p>請確保 static/index2.html 存在</p>")
@app.get("/api/token")
async def get_token(room: str = "Drone-RTC-01") -> Dict[str, str]:
"""生成 LiveKit viewer token"""
try:
identity = f"viewer-{secrets.token_hex(4)}"
at = (
api.AccessToken(API_KEY, API_SECRET)
.with_identity(identity)
.with_grants(api.VideoGrants(room=room, room_join=True, can_subscribe=True, can_publish=False))
)
return {"identity": identity, "token": at.to_jwt(), "server_url": SERVER_URL, "room": room}
except Exception as e:
raise HTTPException(status_code=500, detail=f"生成 token 失敗: {str(e)}")
@app.get("/api/publisher-token")
async def get_publisher_token(room: str = "Drone-RTC-01", identity: str = None) -> Dict[str, str]:
"""生成 LiveKit publisher token(用於手機直播)"""
try:
# 如果沒有提供身份,自動生成一個
if not identity:
identity = f"mobile-publisher-{secrets.token_hex(4)}"
at = (
api.AccessToken(API_KEY, API_SECRET)
.with_identity(identity)
.with_grants(api.VideoGrants(
room=room,
room_join=True,
can_subscribe=True,
can_publish=True,
can_publish_data=True
))
)
return {"identity": identity, "token": at.to_jwt(), "server_url": SERVER_URL, "room": room}
except Exception as e:
raise HTTPException(status_code=500, detail=f"生成發布者 token 失敗: {str(e)}")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)