live-sfu-demo/internal/server/static/assets/publish-D-rS1-js.js

1 line
9.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import{A as e,C as t,E as n,H as r,J as i,K as a,M as o,P as s,R as c,W as l,Y as u,_ as d,a as ee,c as f,i as p,k as m,l as h,m as g,n as _,o as v,r as y,t as b,v as x,w as S,x as te}from"./ui-CzB-gjVP.js";import{t as C}from"./cloud-DZf51awA.js";import{a as ne,c as re,d as w,l as ie,o as ae,r as T,s as oe,t as se,u as ce}from"./webrtc-CWAdwVhe.js";import{t as E}from"./message-square-1ZGuav88.js";import{t as D}from"./server-eXVtBH0Y.js";import{t as O}from"./video-C1co3G53.js";import{i as le}from"./index-BTRwyDO1.js";var k=[[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}],[`rect`,{x:`9`,y:`9`,width:`6`,height:`6`,rx:`1`,key:`1ssd4o`}]],ue=e=>c(x,a(e,{iconNode:k,name:`circle-stop`})),de=m(`<div class="flex flex-wrap items-end justify-between gap-4"><div><p class="mono-label text-muted-foreground">publish / </p><h1 class="display mt-2 text-4xl sm:text-5xl">开始直播</h1><p class="mt-3 max-w-lg text-sm text-muted-foreground">选择分发后端,一路推流将扇出到所选 SFU。</p></div><div class="flex items-center gap-3 border border-line bg-card/60 px-4 py-2.5"><span class=mono-label>`),fe=m(`<div class="pointer-events-none absolute inset-0 flex flex-col items-center justify-center gap-2.5 text-white/60"><span class="flex size-12 items-center justify-center border border-white/20 bg-white/5"></span><span class="micro-label text-white/50">camera off`),pe=m(`<div class="relative h-full border border-line bg-card/50 p-4 sm:p-5"><div class="flex flex-wrap items-center justify-between gap-2"><div class="flex items-center gap-2"><h3 class=font-semibold>本地预览</h3><span class="micro-label text-muted-foreground">preview</span></div><div class="flex items-center gap-3"><span class="font-mono text-[11px] text-muted-foreground"></span></div></div><div class="relative mt-4 aspect-video overflow-hidden border border-line/70 bg-black"><video autoplay playsinline muted class=size-full></video><div class="pointer-events-none absolute top-3 left-3 flex flex-wrap items-center gap-1.5"></div></div><div class="mt-4 flex flex-wrap gap-2">`),me=m(`<div class="relative border border-line bg-card/50 p-4 sm:p-5"><div class="flex items-center justify-between gap-2"><div class="flex items-center gap-2"><h3 class=font-semibold>分发后端</h3><span class="micro-label text-muted-foreground">routing</span></div></div><div class="mt-4 space-y-2.5"></div><p class="mt-4 border-t border-line/70 pt-4 text-xs leading-relaxed text-muted-foreground">推流凭证仅在服务端会话中生效,浏览器端不会出现 SFU 密钥。`),he=m(`<div class="mt-4 grid gap-3 md:grid-cols-2">`),A=m(`<div class="relative border border-line bg-card/50 p-4 sm:p-5"><div class="flex items-center gap-2"><h3 class=font-semibold>分发状态</h3><span class="micro-label text-muted-foreground">fan-out status`),j=m(`<div class="relative border border-line bg-card/50 p-4 sm:p-5"><div class="flex items-center justify-between gap-2"><div class="flex items-center gap-2"><h3 class=font-semibold>房间弹幕 / 聊天</h3><span class="micro-label text-muted-foreground">danmaku</span></div></div><div class="mt-4 h-80 min-h-0">`),M=m(`<div class="mx-auto max-w-[1400px] space-y-5 px-4 py-8 sm:px-6 sm:py-10"><div class="grid gap-4 lg:grid-cols-[minmax(0,1.6fr)_minmax(0,1fr)]">`),N=m(`<p class="text-sm text-muted-foreground">正在读取后端配置…`),P=m(`<div><div class="flex min-w-0 items-center gap-3"><span class="flex size-9 shrink-0 items-center justify-center border border-line bg-background text-foreground/80"></span><div class=min-w-0><p class="micro-label mt-1.5 text-muted-foreground"> · `),F=m(`<div class="mt-4 border border-dashed border-line px-5 py-8 text-center text-sm text-muted-foreground">尚未开始推流`),I=m(`<div class="mt-3 flex flex-wrap gap-2"><a class=mono-chip target=_blank rel=noreferrer>HLS</a><a class=mono-chip target=_blank rel=noreferrer>FLV`),L=m(`<p class="mt-2 truncate font-mono text-[10px] text-muted-foreground">session · `),R=m(`<div class="relative border border-line/80 bg-background/40 p-4"><span class="absolute top-0 left-0 h-3 w-3 border-t-2 border-l-2 border-acid-lime"aria-hidden=true></span><div class="flex items-center justify-between gap-2"><span class="truncate text-sm font-medium">`);function z(e){return e===`BACKEND_KIND_CLOUDFLARE`?`Cloudflare Realtime`:e===`BACKEND_KIND_SRS`?`SRS`:e}function ge(e){return e===`BACKEND_KIND_CLOUDFLARE`?C:D}var B=()=>{let a=le({from:`/publish`}),m=()=>a().room,[x,C]=l([]),[k,B]=l({BACKEND_KIND_CLOUDFLARE:!0,BACKEND_KIND_SRS:!0}),[V,H]=l(null),[U,W]=l(!1),[G,K]=l([]),[q,J]=l(``),[Y,_e]=l([]),[X,ve]=l(!0),Z,Q={};u(()=>{d.getConfig().then(e=>C(e.backends||[])).catch(()=>{});let e=re(m(),e=>K(e.targets||[])),t=oe(m(),e=>_e(t=>[...t,e].slice(-100)));i(()=>{e(),t()})});let ye=(e,t)=>{ae(m(),e,t).catch(()=>{})},be=e=>B(t=>({...t,[e]:!t[e]})),xe=async()=>{if(!g.can(`room:publish`)){J(`当前角色无权发布(需要 room:publish)`);return}J(``),W(!0);try{if(!V()){let e=await navigator.mediaDevices.getUserMedia({video:!0,audio:!0});H(e),Z&&(Z.srcObject=e)}let e=V(),t=x().filter(e=>k()[e.kind]);for(let n of t){let t=await d.publish(m(),n.kind,``);n.kind===`BACKEND_KIND_SRS`?Q.srs=await ne({stream:t.stream,token:t.publish_token,local:e,iceServers:(t.ice_servers||[]).map(T)}):n.kind===`BACKEND_KIND_CLOUDFLARE`&&(Q.cloudflare=await se({sessionId:t.session_id,local:e,iceServers:(t.ice_servers||[]).map(T)}))}}catch(e){J(String(e?.message||e)),W(!1)}},$=async()=>{for(let e of Object.keys(Q)){try{Q[e].close()}catch{}delete Q[e]}for(let e of G())try{await d.stop(m(),e.backend)}catch{}V()&&(V().getTracks().forEach(e=>e.stop()),H(null)),K([]),W(!1)};return i($),(()=>{var i=M(),a=i.firstChild;return t(i,c(h,{get children(){var e=de(),n=e.firstChild,r=n.firstChild;r.firstChild;var i=n.nextSibling,a=i.firstChild;return t(r,m,null),t(i,c(v,{get active(){return U()}}),a),t(a,()=>U()?`推流中 / live`:`待机 / standby`),t(i,c(f,{get active(){return U()}}),null),e}}),a),t(i,c(s,{get when(){return!g.can(`room:publish`)},get children(){return c(b,{tone:`warning`,get children(){return[`当前角色(`,S(()=>g.role()),`)无权发布,仅 admin / publisher 可推流。可切换到「观看」进入房间发弹幕。`]}})}}),a),t(i,c(s,{get when(){return q()},get children(){return c(b,{tone:`error`,get children(){return q()}})}}),a),t(a,c(h,{delay:1,class:`min-w-0`,get children(){var n=pe(),r=n.firstChild,i=r.firstChild,a=i.firstChild,o=i.nextSibling,l=o.firstChild,u=r.nextSibling,d=u.firstChild,f=d.nextSibling,p=u.nextSibling;return t(n,c(ee,{}),r),t(i,c(O,{class:`size-4 text-acid-lime`}),a),t(l,(()=>{var e=S(()=>!!V());return()=>e()?`${V().getVideoTracks().length} 视频 · ${V().getAudioTracks().length} 音频`:`tracks · off`})()),t(o,c(y,{variant:`ghost`,size:`sm`,onClick:()=>ve(e=>!e),get children(){return X()?`隐藏弹幕`:`显示弹幕`}}),null),e(e=>Z=e,d),t(u,c(s,{get when(){return X()},get children(){return c(ce,{messages:Y})}}),f),t(f,c(_,{get variant(){return U()?`success`:`outline`},class:`bg-black/50 shadow-sm backdrop-blur-sm`,get children(){return[c(v,{get active(){return U()}}),S(()=>U()?`LIVE`:`STANDBY`)]}})),t(u,c(s,{get when(){return!V()},get children(){var e=fe(),n=e.firstChild;return t(n,c(O,{class:`size-5`})),e}}),null),t(p,c(y,{class:`h-10`,onClick:xe,get disabled(){return U()||!g.can(`room:publish`)},get children(){return[c(O,{class:`size-4`}),`开始推流`]}}),null),t(p,c(y,{variant:`danger`,class:`h-10`,onClick:$,get disabled(){return!U()},get children(){return[c(ue,{class:`size-4`}),`停止推流`]}}),null),n}}),null),t(a,c(h,{delay:2,class:`min-w-0 self-start`,get children(){var e=me(),n=e.firstChild,i=n.firstChild,a=i.firstChild,l=n.nextSibling;return t(i,c(D,{class:`size-4 text-acid-lime`}),a),t(n,c(_,{variant:`muted`,get children(){return[S(()=>x().length),` 路`]}}),null),t(l,c(s,{get when(){return x().length>0},get fallback(){return N()},get children(){return c(o,{get each(){return x()},children:e=>{let n=ge(e.kind);return(()=>{var i=P(),a=i.firstChild.firstChild,o=a.nextSibling,s=o.firstChild,l=s.firstChild;return t(a,c(n,{class:`size-4`})),t(o,c(p,{get label(){return e.name},get checked(){return!!k()[e.kind]},onChange:()=>be(e.kind),get disabled(){return U()}}),s),t(s,()=>z(e.kind),l),t(s,()=>e.primary?`主 SFU`:`对照后端`,null),t(i,c(_,{get variant(){return e.configured?`success`:`muted`},get children(){return e.configured?`在线`:`未配置`}}),null),r(()=>te(i,`flex items-center justify-between gap-3 border p-3 transition-colors ${e.configured?`border-line bg-background/50`:`border-line/60 bg-background/20 opacity-70`}`)),i})()}})}})),e}}),null),t(i,c(h,{delay:1,get children(){var e=A(),i=e.firstChild,a=i.firstChild;return t(i,c(w,{class:`size-4 text-acid-lime`}),a),t(e,c(s,{get when(){return G().length>0},get fallback(){return F()},get children(){var e=he();return t(e,c(o,{get each(){return G()},children:e=>(()=>{var i=R(),a=i.firstChild.nextSibling,o=a.firstChild;return t(o,()=>z(e.backend)),t(a,c(_,{variant:`success`,get children(){return[c(v,{active:!0}),`直播中`]}}),null),t(i,c(s,{get when(){return e.stream},get children(){var i=I(),a=i.firstChild,o=a.firstChild,s=a.nextSibling,l=s.firstChild;return t(a,c(w,{class:`size-3`}),o),t(s,c(w,{class:`size-3`}),l),r(t=>{var r=`/live/${e.stream}.m3u8`,i=`/live/${e.stream}.flv`;return r!==t.e&&n(a,`href`,t.e=r),i!==t.t&&n(s,`href`,t.t=i),t},{e:void 0,t:void 0}),i}}),null),t(i,c(s,{get when(){return e.session_id},get children(){var n=L();return n.firstChild,t(n,()=>e.session_id,null),n}}),null),i})()})),e}}),null),e}}),null),t(i,c(h,{delay:2,get children(){var e=j(),n=e.firstChild,r=n.firstChild,i=r.firstChild,a=n.nextSibling;return t(r,c(E,{class:`size-4 text-acid-lime`}),i),t(n,c(_,{variant:`muted`,get children(){return Y().length}}),null),t(a,c(ie,{messages:Y,get canChat(){return g.can(`room:chat`)},onSend:ye})),e}}),null),i})()};export{B as Publish};