Files
live/frontend/src/api/streams.ts
T
2026-08-30 15:35:28 +08:00

206 lines
5.4 KiB
TypeScript

import api from './client'
export interface RenditionConfig {
label: string
enabled: boolean
width: number
height: number
fps: number
codec: 'libx264' | 'libx265'
bitrate: string
crf: number
preset: 'ultrafast' | 'superfast' | 'veryfast' | 'faster' | 'fast' | 'medium' | 'slow'
audio_bitrate: string
keyframe_seconds: number
}
export interface StreamInfo {
id: number
title: string
description?: string
cover_url?: string
stream_key?: string
status: string
scheduled_at?: string
started_at?: string
ended_at?: string
multicast_enabled: boolean
created_at: string
replay_file?: string
replay_url?: string
chapters: Chapter[]
transcode_profile: string
renditions?: RenditionConfig[] | null
homepage_visible: boolean
remote_control_enabled: boolean
}
export interface Chapter {
title: string
time: number
}
export interface StreamCreateReq {
title: string
description?: string
cover_url?: string
scheduled_at?: string
replay_file?: string | null
replay_url?: string | null
chapters?: Chapter[]
transcode_profile?: string
renditions?: RenditionConfig[]
homepage_visible?: boolean
remote_control_enabled?: boolean
}
export interface WatchInfo {
stream_id: number
title: string
status: string
multicast_available: boolean
selected_node?: { id: string; name: string } | null
lines: LineInfo[]
qualities: QualityInfo[]
description?: string
scheduled_at?: string
replay_url?: string
replay_local_url?: string
chapters: Chapter[]
remote_control_enabled: boolean
}
export interface LineInfo {
node_id: string
node_name: string
weight: number
type: string
url: string
unicast_fallback?: string
qualities: QualityUrl[]
}
export interface QualityUrl {
label: string
width: number
height: number
url: string
}
export interface QualityInfo {
label: string
width: number
height: number
}
export interface ViewerSessionInfo {
session_id: string
node_id?: string
node_name?: string
quality?: string
playback_state: string
buffered_seconds?: number
error?: string
remote_adjusted: boolean
last_heartbeat: string
}
export interface ControlAuditInfo {
id: number
operator: string
target_session_id: string
action: string
value?: string
status: string
result?: string
created_at: string
claimed_at?: string
}
export interface RemoteCommandInfo {
id: number
action: 'switch_node' | 'switch_quality' | 'restore_auto'
value?: string
created_at: string
}
export async function fetchStreams(admin = false): Promise<StreamInfo[]> {
const { data } = await api.get('/streams', { params: admin ? { admin: true } : undefined })
return data
}
export async function fetchMediaFiles(): Promise<string[]> {
const { data } = await api.get('/streams/media-files')
return data
}
export async function createStream(req: StreamCreateReq): Promise<{
id: number; stream_key: string; rtmp_url: string; status: string
}> {
const { data } = await api.post('/streams', req)
return data
}
export async function getStream(streamId: number): Promise<StreamInfo> {
const { data } = await api.get(`/streams/${streamId}`)
return data
}
export async function updateStream(streamId: number, req: Partial<StreamCreateReq>): Promise<void> {
await api.put(`/streams/${streamId}`, req)
}
export async function deleteStream(streamId: number): Promise<void> {
await api.delete(`/streams/${streamId}`)
}
export async function goLive(streamId: number): Promise<void> {
await api.post(`/streams/${streamId}/go-live`)
}
export async function endStream(streamId: number): Promise<void> {
await api.post(`/streams/${streamId}/end`)
}
export async function getWatchUrls(streamId: number): Promise<WatchInfo> {
const { data } = await api.get(`/streams/${streamId}/watch`)
return data
}
export function getStreamStatusUrl(streamId: number): string {
return `/api/streams/${streamId}/events`
}
export async function sendViewerHeartbeat(streamId: number, payload: Record<string, unknown>): Promise<{ remote_adjusted: boolean }> {
const { data } = await api.post(`/streams/${streamId}/viewer-heartbeat`, payload)
return data
}
export async function pollRemoteCommand(streamId: number, sessionId: string): Promise<RemoteCommandInfo | null> {
const { data } = await api.get(`/streams/${streamId}/remote-command`, { params: { session_id: sessionId } })
return data
}
export async function reportRemoteCommandResult(streamId: number, commandId: number, sessionId: string, result: string): Promise<void> {
await api.post(`/streams/${streamId}/remote-command/${commandId}/result`, { result }, { params: { session_id: sessionId } })
}
export async function fetchViewerSessions(streamId: number): Promise<ViewerSessionInfo[]> {
const { data } = await api.get(`/streams/${streamId}/viewer-sessions`)
return data
}
export async function fetchControlAudit(streamId: number): Promise<ControlAuditInfo[]> {
const { data } = await api.get(`/streams/${streamId}/control-audit`)
return data
}
export async function createRemoteSession(streamId: number, expiresIn = 300): Promise<{ token: string; expires_in: number }> {
const { data } = await api.post(`/streams/${streamId}/remote-session`, { expires_in: expiresIn })
return data
}
export async function sendRemoteCommand(streamId: number, token: string, action: string, targets: string[], value?: string): Promise<void> {
await api.post(`/streams/${streamId}/remote-command`, { token, action, targets, value })
}