1 line
9.6 KiB
JavaScript
1 line
9.6 KiB
JavaScript
import{C as e,G as t,J as n,L as r,N as i,O as a,S as o,T as s,U as c,V as l,_ as u,a as ee,b as d,c as f,h as p,i as m,j as h,k as te,l as g,m as _,n as v,o as y,q as b,r as x,t as S}from"./ui-BEZm0Fjb.js";import{n as C,t as w}from"./video-1nOl5FpE.js";import{a as ne,c as re,d as ie,f as T,l as ae,o as E,r as D,s as oe,t as se,u as ce}from"./webrtc-Baz_BzLq.js";import{t as O}from"./server-DmfY9b1N.js";import{n as le}from"./index-BjOqv38F.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=>r(_,t(e,{iconNode:k,name:`circle-stop`})),de=a(`<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=a(`<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=a(`<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=a(`<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 密钥。`),A=a(`<div class="mt-4 grid gap-3 md:grid-cols-2">`),j=a(`<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`),M=a(`<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">`),N=a(`<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)]">`),P=a(`<p class="text-sm text-muted-foreground">正在读取后端配置…`),F=a(`<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"> · `),I=a(`<div class="mt-4 border border-dashed border-line px-5 py-8 text-center text-sm text-muted-foreground">尚未开始推流`),L=a(`<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`),R=a(`<p class="mt-2 truncate font-mono text-[10px] text-muted-foreground">session · `),he=a(`<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:O}var B=()=>{let t=le({from:`/publish`}),a=()=>t().room,[_,C]=c([]),[k,B]=c({BACKEND_KIND_CLOUDFLARE:!0,BACKEND_KIND_SRS:!0}),[V,H]=c(null),[U,W]=c(!1),[G,K]=c([]),[q,J]=c(``),[Y,_e]=c([]),[X,ve]=c(!0),Z,Q={};n(()=>{u.getConfig().then(e=>C(e.backends||[])).catch(()=>{});let e=re(a(),e=>K(e.targets||[])),t=oe(a(),e=>_e(t=>[...t,e].slice(-100)));b(()=>{e(),t()})});let ye=(e,t)=>{E(a(),e,t).catch(()=>{})},be=e=>B(t=>({...t,[e]:!t[e]})),xe=async()=>{if(!p.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=_().filter(e=>k()[e.kind]);for(let n of t){let t=await u.publish(a(),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(D)}):n.kind===`BACKEND_KIND_CLOUDFLARE`&&(Q.cloudflare=await se({sessionId:t.session_id,local:e,iceServers:(t.ice_servers||[]).map(D)}))}}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 u.stop(a(),e.backend)}catch{}V()&&(V().getTracks().forEach(e=>e.stop()),H(null)),K([]),W(!1)};return b($),(()=>{var t=N(),n=t.firstChild;return o(t,r(g,{get children(){var e=de(),t=e.firstChild,n=t.firstChild;n.firstChild;var i=t.nextSibling,s=i.firstChild;return o(n,a,null),o(i,r(y,{get active(){return U()}}),s),o(s,()=>U()?`推流中 / live`:`待机 / standby`),o(i,r(f,{get active(){return U()}}),null),e}}),n),o(t,r(i,{get when(){return!p.can(`room:publish`)},get children(){return r(S,{tone:`warning`,get children(){return[`当前角色(`,e(()=>p.role()),`)无权发布,仅 admin / publisher 可推流。可切换到「观看」进入房间发弹幕。`]}})}}),n),o(t,r(i,{get when(){return q()},get children(){return r(S,{tone:`error`,get children(){return q()}})}}),n),o(n,r(g,{delay:1,class:`min-w-0`,get children(){var t=pe(),n=t.firstChild,a=n.firstChild,s=a.firstChild,c=a.nextSibling,l=c.firstChild,u=n.nextSibling,d=u.firstChild,f=d.nextSibling,m=u.nextSibling;return o(t,r(ee,{}),n),o(a,r(w,{class:`size-4 text-acid-lime`}),s),o(l,(()=>{var t=e(()=>!!V());return()=>t()?`${V().getVideoTracks().length} 视频 · ${V().getAudioTracks().length} 音频`:`tracks · off`})()),o(c,r(x,{variant:`ghost`,size:`sm`,onClick:()=>ve(e=>!e),get children(){return X()?`隐藏弹幕`:`显示弹幕`}}),null),te(e=>Z=e,d),o(u,r(i,{get when(){return X()},get children(){return r(ce,{messages:Y})}}),f),o(f,r(v,{get variant(){return U()?`success`:`outline`},class:`bg-black/50 shadow-sm backdrop-blur-sm`,get children(){return[r(y,{get active(){return U()}}),e(()=>U()?`LIVE`:`STANDBY`)]}})),o(u,r(i,{get when(){return!V()},get children(){var e=fe(),t=e.firstChild;return o(t,r(w,{class:`size-5`})),e}}),null),o(m,r(x,{class:`h-10`,onClick:xe,get disabled(){return U()||!p.can(`room:publish`)},get children(){return[r(w,{class:`size-4`}),`开始推流`]}}),null),o(m,r(x,{variant:`danger`,class:`h-10`,onClick:$,get disabled(){return!U()},get children(){return[r(ue,{class:`size-4`}),`停止推流`]}}),null),t}}),null),o(n,r(g,{delay:2,class:`min-w-0 self-start`,get children(){var t=me(),n=t.firstChild,a=n.firstChild,s=a.firstChild,c=n.nextSibling;return o(a,r(O,{class:`size-4 text-acid-lime`}),s),o(n,r(v,{variant:`muted`,get children(){return[e(()=>_().length),` 路`]}}),null),o(c,r(i,{get when(){return _().length>0},get fallback(){return P()},get children(){return r(h,{get each(){return _()},children:e=>{let t=ge(e.kind);return(()=>{var n=F(),i=n.firstChild.firstChild,a=i.nextSibling,s=a.firstChild,c=s.firstChild;return o(i,r(t,{class:`size-4`})),o(a,r(m,{get label(){return e.name},get checked(){return!!k()[e.kind]},onChange:()=>be(e.kind),get disabled(){return U()}}),s),o(s,()=>z(e.kind),c),o(s,()=>e.primary?`主 SFU`:`对照后端`,null),o(n,r(v,{get variant(){return e.configured?`success`:`muted`},get children(){return e.configured?`在线`:`未配置`}}),null),l(()=>d(n,`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`}`)),n})()}})}})),t}}),null),o(t,r(g,{delay:1,get children(){var e=j(),t=e.firstChild,n=t.firstChild;return o(t,r(T,{class:`size-4 text-acid-lime`}),n),o(e,r(i,{get when(){return G().length>0},get fallback(){return I()},get children(){var e=A();return o(e,r(h,{get each(){return G()},children:e=>(()=>{var t=he(),n=t.firstChild.nextSibling,a=n.firstChild;return o(a,()=>z(e.backend)),o(n,r(v,{variant:`success`,get children(){return[r(y,{active:!0}),`直播中`]}}),null),o(t,r(i,{get when(){return e.stream},get children(){var t=L(),n=t.firstChild,i=n.firstChild,a=n.nextSibling,c=a.firstChild;return o(n,r(T,{class:`size-3`}),i),o(a,r(T,{class:`size-3`}),c),l(t=>{var r=`/live/${e.stream}.m3u8`,i=`/live/${e.stream}.flv`;return r!==t.e&&s(n,`href`,t.e=r),i!==t.t&&s(a,`href`,t.t=i),t},{e:void 0,t:void 0}),t}}),null),o(t,r(i,{get when(){return e.session_id},get children(){var t=R();return t.firstChild,o(t,()=>e.session_id,null),t}}),null),t})()})),e}}),null),e}}),null),o(t,r(g,{delay:2,get children(){var e=M(),t=e.firstChild,n=t.firstChild,i=n.firstChild,a=t.nextSibling;return o(n,r(ie,{class:`size-4 text-acid-lime`}),i),o(t,r(v,{variant:`muted`,get children(){return Y().length}}),null),o(a,r(ae,{messages:Y,get canChat(){return p.can(`room:chat`)},onSend:ye})),e}}),null),t})()};export{B as Publish}; |