-
RTMP 推流地址:
+
RTMP Push URL:
@@ -72,15 +72,15 @@ export default function StreamForm() {
icon={}
onClick={() => {
navigator.clipboard.writeText(
- `推流码: ${result.stream_key}\nRTMP 地址: ${result.rtmp_url}`
+ `Stream Key: ${result.stream_key}\nRTMP URL: ${result.rtmp_url}`
)
- message.success('已复制到剪贴板')
+ message.success('Copied')
}}
>
- 复制全部
+ Copy All
@@ -95,30 +95,30 @@ export default function StreamForm() {
onClick={() => navigate('/admin/streams')}
style={{ marginBottom: 16 }}
>
- 返回
+ Back
-
- 创建直播
+
+ New Stream
-
+
-
-
+
+
-
+
-
-
+
+
diff --git a/frontend/src/admin/pages/StreamList.tsx b/frontend/src/admin/pages/StreamList.tsx
index a632f3c..3a2576d 100644
--- a/frontend/src/admin/pages/StreamList.tsx
+++ b/frontend/src/admin/pages/StreamList.tsx
@@ -9,10 +9,10 @@ import { fetchStreams, deleteStream, goLive, endStream, type StreamInfo } from '
const { Title, Text } = Typography
const statusMap: Record = {
- pending: { color: 'blue', label: '待开播' },
- live: { color: 'green', label: '直播中' },
- ended: { color: 'default', label: '已结束' },
- cancelled: { color: 'red', label: '已取消' },
+ pending: { color: 'blue', label: 'Scheduled' },
+ live: { color: 'green', label: 'Live' },
+ ended: { color: 'default', label: 'Ended' },
+ cancelled: { color: 'red', label: 'Cancelled' },
}
export default function StreamList() {
@@ -27,47 +27,50 @@ export default function StreamList() {
try {
const data = await fetchStreams()
setStreams(data)
- } catch { message.error('加载失败') }
+ } catch { message.error('Failed to load streams') }
setLoading(false)
}
async function handleDelete(id: number) {
try {
await deleteStream(id)
- message.success('已删除')
+ message.success('Deleted')
loadData()
- } catch { message.error('删除失败') }
+ } catch { message.error('Failed to delete') }
}
async function handleGoLive(id: number) {
try {
await goLive(id)
- message.success('已设置为直播中')
+ message.success('Stream is now live')
loadData()
- } catch { message.error('操作失败') }
+ } catch { message.error('Operation failed') }
}
async function handleEnd(id: number) {
try {
await endStream(id)
- message.success('已结束直播')
+ message.success('Stream ended')
loadData()
- } catch { message.error('操作失败') }
+ } catch { message.error('Operation failed') }
}
const columns = [
{ title: 'ID', dataIndex: 'id', key: 'id', width: 80 },
- { title: '标题', dataIndex: 'title', key: 'title', ellipsis: true },
+ { title: 'Title', dataIndex: 'title', key: 'title', ellipsis: true },
{
- title: '状态', dataIndex: 'status', key: 'status', width: 100,
+ title: 'Status', dataIndex: 'status', key: 'status', width: 110,
render: (s: string) => {
const info = statusMap[s] || { color: 'default', label: s }
return {info.label}
},
},
- { title: '创建时间', dataIndex: 'created_at', key: 'created_at', render: (v: string) => v?.slice(0, 16), width: 170 },
{
- title: '操作', key: 'actions', width: 280,
+ title: 'Created', dataIndex: 'created_at', key: 'created_at',
+ render: (v: string) => v?.slice(0, 16), width: 170,
+ },
+ {
+ title: 'Actions', key: 'actions', width: 280,
render: (_: any, record: StreamInfo) => (
}
onClick={() => {
navigator.clipboard.writeText(record.stream_key)
- message.success('推流码已复制')
+ message.success('Stream key copied')
}}
>
- 复制推流码
+ Copy Key
{record.status !== 'live' ? (
-
+
}
onClick={() => handleGoLive(record.id)} ghost />
) : (
-
+
}
onClick={() => handleEnd(record.id)} danger />
)}
- handleDelete(record.id)}>
+ handleDelete(record.id)}>
} danger />
@@ -105,9 +108,9 @@ export default function StreamList() {
return (
-
直播列表
+ Streams
} onClick={() => navigate('/admin/streams/new')}>
- 创建直播
+ New Stream
= {
- live: { color: 'red', label: '直播中', icon: },
- pending: { color: 'blue', label: '待开播', icon: },
- ended: { color: 'default', label: '已结束', icon: null },
- cancelled: { color: 'default', label: '已取消', icon: null },
+ live: { color: 'red', label: 'LIVE', icon: },
+ pending: { color: 'blue', label: 'SCHEDULED', icon: },
+ ended: { color: 'default', label: 'ENDED', icon: null },
+ cancelled: { color: 'default', label: 'CANCELLED', icon: null },
}
export default function HomePage() {
@@ -33,43 +33,34 @@ export default function HomePage() {
})
return (
-
+
-
- LiveStream
-
- 简易直播平台
+
+
+ StreamCore
+
+
+ Enterprise Streaming Platform
-
- }
- onClick={() => navigate('/admin')}
- >
- 管理后台
-
+
-
全部直播
+
Live Channels
{loading ? (
{[1, 2, 3, 4, 5, 6].map((i) => (
-
+
))}
) : sorted.length === 0 ? (
-
+
) : (
{sorted.map((s) => {
@@ -78,39 +69,43 @@ export default function HomePage() {
{!s.cover_url && (
-
- {s.status === 'live' ? : '🎬'}
-
+
)}
+
+
+ {meta.icon} {meta.label}
+
+
}
+ bodyStyle={{ padding: '16px 20px' }}
onClick={() => navigate(`/watch/${s.id}`)}
>
-
- {meta.icon} {meta.label}
-
- {s.title}
-
+
+ {s.title}
+
}
description={
- s.description
- ? {s.description}
- : 暂无简介
+
+ {s.description || 'No description'}
+
}
/>
@@ -120,6 +115,14 @@ export default function HomePage() {
)}
+
+
+ StreamCore © {new Date().getFullYear()}
+
+
)
}
diff --git a/frontend/src/viewer/pages/WatchPage.tsx b/frontend/src/viewer/pages/WatchPage.tsx
index 0486d29..a1f94cc 100644
--- a/frontend/src/viewer/pages/WatchPage.tsx
+++ b/frontend/src/viewer/pages/WatchPage.tsx
@@ -79,7 +79,7 @@ export default function WatchPage() {
})
hlsInstance.on(Hls.Events.ERROR, (_event, data) => {
if (data.fatal) {
- message.warning('播放异常,尝试切换线路...')
+ message.warning('Playback error, try switching line...')
}
})
setHls(hlsInstance)
@@ -103,50 +103,50 @@ export default function WatchPage() {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
- background: '#FAF8F5',
+ background: '#F5F6FA',
}}>
-
+
)
}
- const statusLabel = info.status === 'live' ? '直播中' : info.status === 'pending' ? '待开播' : info.status === 'ended' ? '已结束' : info.status
+ const statusLabel = info.status === 'live' ? 'LIVE' : info.status === 'pending' ? 'SCHEDULED' : info.status === 'ended' ? 'ENDED' : info.status.toUpperCase()
return (
- } style={{ color: '#fff' }}
+ } style={{ color: '#A0AEC0' }}
onClick={() => navigate('/')}>
- 返回
+ Back
-
+
{info.title}
-
+
{statusLabel}
-
-
- {info.multicast_available ? '组播' : '单播'}
+
+
+ {info.multicast_available ? 'Multicast' : 'Unicast'}
@@ -184,6 +184,8 @@ export default function WatchPage() {
maxHeight: 'calc(100vh - 56px - 48px)',
background: '#000',
position: 'relative',
+ borderRadius: 8,
+ overflow: 'hidden',
}}>
)}