203 lines
5.3 KiB
TypeScript
203 lines
5.3 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
|
|
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
|
|
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
|
|
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 })
|
|
}
|