- 新增直播评论/上下文/礼物等 API 与回放组件 - 主播开播、云端推流配置与 streamer 校验 - 依赖与 Mongo 集合/种子更新 - 需求与调研文档补充 Made-with: Cursor
117 lines
3.6 KiB
TypeScript
117 lines
3.6 KiB
TypeScript
/**
|
|
* 直播上下文 API 客户端(房间、橱窗、风控词、公会分成提示)
|
|
*/
|
|
|
|
export interface LiveShowcaseItemDTO {
|
|
id: string
|
|
title: string
|
|
subtitle?: string
|
|
landingPath: string
|
|
refQuery: string
|
|
}
|
|
|
|
export interface LiveContextData {
|
|
streamer: {
|
|
id: string
|
|
name: string
|
|
isLive: boolean
|
|
commissionRate: number
|
|
guildId: string | null
|
|
}
|
|
guild: { id: string; name: string; commissionRate: number } | null
|
|
room: {
|
|
id: string
|
|
title: string
|
|
status: string
|
|
game: string
|
|
viewerCount: number
|
|
pullPlaybackUrl: string
|
|
roomMode: string
|
|
} | null
|
|
showcase: LiveShowcaseItemDTO[]
|
|
forbiddenWords: string[]
|
|
revenueHint: string
|
|
}
|
|
|
|
export function buildShowcaseHref(origin: string, item: LiveShowcaseItemDTO): string {
|
|
const path = item.landingPath.startsWith("/") ? item.landingPath : `/${item.landingPath}`
|
|
const q = item.refQuery.startsWith("?") ? item.refQuery.slice(1) : item.refQuery
|
|
return `${origin.replace(/\/$/, "")}${path}?${q}`
|
|
}
|
|
|
|
export async function getLiveContext(streamerId: string): Promise<LiveContextData | null> {
|
|
const res = await fetch(`/api/live/context/${streamerId}`, { cache: "no-store" })
|
|
const json = (await res.json().catch(() => ({}))) as {
|
|
success?: boolean
|
|
data?: LiveContextData
|
|
message?: string
|
|
}
|
|
if (!res.ok || !json.success || !json.data) return null
|
|
return json.data
|
|
}
|
|
|
|
export interface LiveCommentDTO {
|
|
id: string
|
|
userId: string
|
|
userName: string
|
|
content: string
|
|
type: "normal" | "enter" | "gift" | "system"
|
|
level: number
|
|
createdAt: string
|
|
}
|
|
|
|
export async function getLiveComments(streamerId: string): Promise<LiveCommentDTO[]> {
|
|
const res = await fetch(`/api/live/comments/${streamerId}`, { cache: "no-store" })
|
|
const json = (await res.json().catch(() => ({}))) as {
|
|
success?: boolean
|
|
data?: { comments?: LiveCommentDTO[] }
|
|
}
|
|
if (!res.ok || !json.success || !json.data?.comments) return []
|
|
return json.data.comments
|
|
}
|
|
|
|
export async function postLiveComment(
|
|
streamerId: string,
|
|
body: { content: string; type?: "normal" },
|
|
): Promise<{ ok: boolean; message?: string }> {
|
|
const res = await fetch(`/api/live/comments/${streamerId}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ content: body.content, type: body.type ?? "normal" }),
|
|
})
|
|
const json = (await res.json().catch(() => ({}))) as { success?: boolean; message?: string }
|
|
if (!res.ok || !json.success) {
|
|
return { ok: false, message: json.message ?? "发送失败" }
|
|
}
|
|
return { ok: true }
|
|
}
|
|
|
|
/** 进房提示(需登录;失败静默) */
|
|
export async function postLiveEnter(streamerId: string): Promise<boolean> {
|
|
const res = await fetch(`/api/live/comments/${streamerId}`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
body: JSON.stringify({ type: "enter", content: "" }),
|
|
})
|
|
const json = (await res.json().catch(() => ({}))) as { success?: boolean }
|
|
return res.ok && !!json.success
|
|
}
|
|
|
|
/** 直播送礼:服务端扣币 + liveGifts + commissionLedger + 公屏 gift */
|
|
export async function postLiveGift(
|
|
streamerId: string,
|
|
giftId: number,
|
|
): Promise<{ ok: boolean; message?: string }> {
|
|
const res = await fetch(`/api/live/gift`, {
|
|
method: "POST",
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "include",
|
|
body: JSON.stringify({ streamerId, giftId }),
|
|
})
|
|
const json = (await res.json().catch(() => ({}))) as { success?: boolean; message?: string }
|
|
if (!res.ok || !json.success) {
|
|
return { ok: false, message: json.message ?? "送礼失败" }
|
|
}
|
|
return { ok: true }
|
|
}
|