From 92b5a30df570164244442398a1e754b16bcb5221 Mon Sep 17 00:00:00 2001 From: ForgQi <34411314+ForgQi@users.noreply.github.com> Date: Mon, 29 Sep 2025 03:18:21 +0800 Subject: [PATCH] Add streamer pause/resume feature and UI updates Introduces a pause/resume button for streamers in the UI and backend, including API endpoint and status handling. Refactors streamer status display, updates related TypeScript interfaces, and improves modal forms. Also updates @douyinfe/semi-ui and related dependencies to v2.86.0, and bumps workspace version to 1.1.10. Minor logging and trait changes in Rust backend for improved clarity and error handling. --- Cargo.lock | 4 +- Cargo.toml | 2 +- app/(app)/streamers/page.tsx | 66 +++++--- app/lib/api-streamer.ts | 3 +- app/ui/OverrideModal.tsx | 6 - app/ui/StreamerActions/PauseButton.tsx | 52 ++++++ app/ui/TemplateModal.tsx | 6 + crates/biliup-cli/src/server/api/endpoints.rs | 59 ++++++- .../biliup-cli/src/server/common/download.rs | 14 +- crates/biliup-cli/src/server/common/upload.rs | 10 +- .../biliup-cli/src/server/core/downloader.rs | 2 +- .../core/downloader/ffmpeg_downloader.rs | 4 +- .../server/core/downloader/stream_gears.rs | 2 +- crates/biliup-cli/src/server/core/monitor.rs | 5 +- .../src/server/infrastructure/context.rs | 5 +- crates/biliup-cli/src/server/router.rs | 11 +- crates/biliup/src/uploader/credential.rs | 8 +- crates/stream-gears/src/danmaku.rs | 4 +- crates/stream-gears/src/server.rs | 3 +- package-lock.json | 150 +++++++++--------- package.json | 2 +- 21 files changed, 270 insertions(+), 148 deletions(-) create mode 100644 app/ui/StreamerActions/PauseButton.tsx diff --git a/Cargo.lock b/Cargo.lock index 55ca2f7..a44839e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -395,7 +395,7 @@ dependencies = [ [[package]] name = "biliup-cli" -version = "1.1.9" +version = "1.1.10" dependencies = [ "async-channel", "async-trait", @@ -3641,7 +3641,7 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stream-gears" -version = "1.1.9" +version = "1.1.10" dependencies = [ "async-channel", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index 30c2188..77e7727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ resolver = "3" [workspace.package] -version = "1.1.9" +version = "1.1.10" [workspace.dependencies] serde = { version = "1.0", features = ["derive"] } diff --git a/app/(app)/streamers/page.tsx b/app/(app)/streamers/page.tsx index 4970889..54bda31 100644 --- a/app/(app)/streamers/page.tsx +++ b/app/(app)/streamers/page.tsx @@ -1,21 +1,21 @@ 'use client' import { - Layout, - Nav, - Button, - Tag, - Typography, - Popconfirm, - Notification, - Card, + Layout, + Nav, + Button, + Tag, + Typography, + Popconfirm, + Notification, + Card, Dropdown, } from '@douyinfe/semi-ui' import { - IconHelpCircle, - IconPlusCircle, - IconVideoListStroked, - IconEdit2Stroked, - IconDeleteStroked, - IconWrench, + IconHelpCircle, + IconPlusCircle, + IconVideoListStroked, + IconEdit2Stroked, + IconDeleteStroked, + IconWrench, IconTreeTriangleDown, IconPause, IconPlay, } from '@douyinfe/semi-icons' import { List, ButtonGroup } from '@douyinfe/semi-ui' import React, { useState } from 'react' @@ -24,6 +24,7 @@ import TemplateModal from '../../ui/TemplateModal' import OverrideModal from '../../ui/OverrideModal' import { LiveStreamerEntity, put, requestDelete, sendRequest } from '../../lib/api-streamer' import useSWRMutation from 'swr/mutation' +import {PauseButton} from "@/app/ui/StreamerActions/PauseButton"; export default function Home() { const { Header, Content } = Layout @@ -54,25 +55,28 @@ export default function Home() { return values } const data: LiveStreamerEntity[] | undefined = streamers?.map(live => { - let status + let statusTag switch (live.status) { case 'Working': - status = 直播中 + statusTag = 直播中 break case 'Idle': - status = 空闲 + statusTag = 空闲 break case 'Pending': - status = 未知 + statusTag = 等待下载 break case 'Inspecting': - status = 检测/上传中 + statusTag = 检测/上传中 break case 'OutOfSchedule': - status = 非录播时间 + statusTag = 非录播时间 + break + case 'Pause': + statusTag = 暂停中 break } - return { ...handleEntityPostprocessor(live), status } + return { ...handleEntityPostprocessor(live), statusTag } }) const handleOk = async (values: any) => { @@ -96,6 +100,7 @@ export default function Home() { const handleUpdate = async (values: any) => { console.log(values); delete values.status + delete values.statusTag if (values?.postprocessor) { values.postprocessor = values.postprocessor.map( ({ cmd, value }: { cmd: string; value: string }) => (cmd === 'rm' ? 'rm' : { [cmd]: value }) @@ -112,6 +117,7 @@ export default function Home() { throw e } } + return ( <>
-
{item.status}
+
{item.statusTag}

}> - - - + + + + + + + + + + } trigger="click" position="bottomRight"> + +

diff --git a/app/lib/api-streamer.ts b/app/lib/api-streamer.ts index aeed2ee..7961926 100644 --- a/app/lib/api-streamer.ts +++ b/app/lib/api-streamer.ts @@ -100,7 +100,8 @@ export interface LiveStreamerEntity { split_time?: number; split_size?: number; upload_id?: number; - status?: string | React.ReactNode; + status?: string; + statusTag?: React.ReactNode; format?: string; time_range?: string | Date[]; excluded_keywords?: string[]; diff --git a/app/ui/OverrideModal.tsx b/app/ui/OverrideModal.tsx index 3a5e804..8aaee1c 100644 --- a/app/ui/OverrideModal.tsx +++ b/app/ui/OverrideModal.tsx @@ -222,12 +222,6 @@ const OverrideModal: React.FC = ({ children, entity, onOk }) stopValidateWithError={true} /> - - void; + onError?: (error: Error) => void; +} + +// 暂停主播 +export const pauseStreamer = async (url: string, ) => { + const response = await fetch(API_BASE + url, + { + method: 'PUT', + // headers: {'Content-Type': 'application/json'}, + } +); + return response; +}; + +export const PauseButton: React.FC = ({ + streamer, + onSuccess, + onError + }) => { + const { mutate } = useSWRConfig(); + + const { trigger: pauseTrigger } = useSWRMutation( + `/v1/streamers/${streamer.id}/pause`, + pauseStreamer + ); + + const handlePause = async () => { + try { + await pauseTrigger(); + // 重新加载列表数据 + await mutate('/v1/streamers'); + onSuccess?.(); + } catch (error) { + console.error('暂停失败:', error); + onError?.(error as Error); + } + }; + console.log("????????????", streamer.status) + return ( +