's'
This commit is contained in:
@@ -16,6 +16,8 @@ export type PipelineStep = {
|
||||
sub?: string;
|
||||
gradient: string;
|
||||
target?: PortalNavTarget;
|
||||
/** 若设置,点击时在新标签打开(优先于 target) */
|
||||
openUrl?: string;
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -34,10 +36,16 @@ export function LivePipelineStrip({ t, title, subtitle, steps, onNavigate }: Pro
|
||||
<div className="mt-6 flex flex-col items-center gap-4 sm:flex-row sm:flex-wrap sm:justify-center">
|
||||
{steps.map((step, i) => (
|
||||
<div key={step.label} className="flex items-center gap-4">
|
||||
{step.target && onNavigate ? (
|
||||
{step.openUrl || (step.target && onNavigate) ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onNavigate(step.target!)}
|
||||
onClick={() => {
|
||||
if (step.openUrl) {
|
||||
window.open(step.openUrl, "_blank", "noopener,noreferrer");
|
||||
return;
|
||||
}
|
||||
if (step.target && onNavigate) onNavigate(step.target);
|
||||
}}
|
||||
className={`flex min-h-[4rem] min-w-[7rem] flex-col items-center justify-center rounded-2xl bg-gradient-to-br px-4 py-2 text-center text-xs font-bold text-white shadow-lg ring-2 ring-white/10 transition hover:ring-violet-400/50 hover:brightness-110 ${step.gradient}`}
|
||||
>
|
||||
<span>{step.label}</span>
|
||||
|
||||
@@ -48,6 +48,9 @@ const CHECK_KEY = "live-hub-tiktok-hdmi-check-v1";
|
||||
const NOTES_KEY = "live-hub-tiktok-hdmi-notes-v1";
|
||||
const SOURCE_MODE_KEY = "live-hub-tiktok-source-mode-v1";
|
||||
|
||||
/** UI 仅展示 SRS 选项(ffmpeg/replay 的 option 保留 hidden,改 false 即可恢复) */
|
||||
const TIKTOK_SOURCE_UI_SRS_ONLY = true;
|
||||
|
||||
export type TiktokSourceMode = "ffmpeg" | "replay" | "srs";
|
||||
|
||||
type ReplayFileRow = { name: string; size: number; replay_url: string };
|
||||
@@ -92,7 +95,9 @@ export function LiveTiktokHdmiView({
|
||||
}: Props) {
|
||||
const tkEntries = useMemo(() => entries.filter(isTiktokProcess), [entries]);
|
||||
const processOptions = tkEntries.length ? tkEntries : entries;
|
||||
const [sourceMode, setSourceMode] = useState<TiktokSourceMode>("ffmpeg");
|
||||
const [sourceMode, setSourceMode] = useState<TiktokSourceMode>(
|
||||
TIKTOK_SOURCE_UI_SRS_ONLY ? "srs" : "ffmpeg",
|
||||
);
|
||||
const [replayFiles, setReplayFiles] = useState<ReplayFileRow[]>([]);
|
||||
const [replayLoading, setReplayLoading] = useState(false);
|
||||
const [uploadBusy, setUploadBusy] = useState(false);
|
||||
@@ -120,7 +125,10 @@ export function LiveTiktokHdmiView({
|
||||
useEffect(() => {
|
||||
try {
|
||||
const r = window.localStorage.getItem(SOURCE_MODE_KEY);
|
||||
if (r === "ffmpeg" || r === "replay" || r === "srs") setSourceMode(r);
|
||||
if (r === "ffmpeg" || r === "replay" || r === "srs") {
|
||||
if (TIKTOK_SOURCE_UI_SRS_ONLY && (r === "ffmpeg" || r === "replay")) setSourceMode("srs");
|
||||
else setSourceMode(r);
|
||||
}
|
||||
} catch {
|
||||
/* ignore */
|
||||
}
|
||||
@@ -374,8 +382,12 @@ export function LiveTiktokHdmiView({
|
||||
value={sourceMode}
|
||||
onChange={(e) => setSourceModePersist(e.target.value as TiktokSourceMode)}
|
||||
>
|
||||
<option value="ffmpeg">FFmpeg(抖音 / TikTok 等直播间 URL)</option>
|
||||
<option value="replay">{t("录播素材(本地上传)", "VOD upload")}</option>
|
||||
<option value="ffmpeg" hidden={TIKTOK_SOURCE_UI_SRS_ONLY}>
|
||||
FFmpeg(抖音 / TikTok 等直播间 URL)
|
||||
</option>
|
||||
<option value="replay" hidden={TIKTOK_SOURCE_UI_SRS_ONLY}>
|
||||
{t("录播素材(本地上传)", "VOD upload")}
|
||||
</option>
|
||||
<option value="srs">{t("SRS(OBS 推流)", "SRS (OBS)")}</option>
|
||||
</select>
|
||||
{sourceMode === "srs" ? (
|
||||
|
||||
@@ -35,6 +35,9 @@ function isYoutubeProcess(e: ProcessEntry) {
|
||||
|
||||
const MODE_KEY = "live-hub-youtube-mode-v1";
|
||||
|
||||
/** UI 暂时隐藏「多频道 Pro」切换(DOM 与逻辑保留,改 false 即可恢复) */
|
||||
const HIDE_YOUTUBE_MULTI_PRO_TOGGLE = true;
|
||||
|
||||
type LiveProcRow = { pm2: string; process_status?: string };
|
||||
|
||||
function pm2StatusOnline(st?: string) {
|
||||
@@ -260,6 +263,10 @@ export function LiveYoutubeUnmannedView({
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
if (HIDE_YOUTUBE_MULTI_PRO_TOGGLE) {
|
||||
setMode("single");
|
||||
return;
|
||||
}
|
||||
const m = window.localStorage.getItem(MODE_KEY);
|
||||
if (m === "pro" || m === "single") setMode(m);
|
||||
} catch {
|
||||
@@ -643,7 +650,7 @@ export function LiveYoutubeUnmannedView({
|
||||
label: "Neko",
|
||||
sub: t("Chromium 工作室", "Chromium"),
|
||||
gradient: "from-emerald-400 to-teal-500",
|
||||
target: "services",
|
||||
openUrl: "http://live.local:9200/",
|
||||
},
|
||||
]}
|
||||
/>
|
||||
@@ -666,7 +673,12 @@ export function LiveYoutubeUnmannedView({
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex rounded-xl border border-white/10 bg-black/30 p-1">
|
||||
<div
|
||||
className={`flex rounded-xl border border-white/10 bg-black/30 p-1 ${
|
||||
HIDE_YOUTUBE_MULTI_PRO_TOGGLE ? "hidden" : ""
|
||||
}`}
|
||||
aria-hidden={HIDE_YOUTUBE_MULTI_PRO_TOGGLE}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setModePersist("single")}
|
||||
|
||||
Reference in New Issue
Block a user