diff --git a/docs/v3/bridge-protocol.md b/docs/v3/bridge-protocol.md index df25a6d..7e1f4ed 100644 --- a/docs/v3/bridge-protocol.md +++ b/docs/v3/bridge-protocol.md @@ -28,16 +28,18 @@ C#→JSは `window.tcb.receive()` の一入口にする。JSONはSystem.Te enumは言語間で安定する文字列、IDは不変文字列とする。 +Host は値が `null` の項目を JSON からキーごと省く(`Protocol.Json` の `WhenWritingNull`)。そのため null になりうる項目は `?:X|null` と書き、Web は「キーが無い(undefined)」を `null` と同じに扱う。`!== null` だけで判定すると undefined を素通りさせ、描画が例外で止まる(v3.2.1 の内部生成フリーズ)。 + ```ts type FrameRate = "24"|"25"|"29.97df"|"30"; interface AppState { sessionId:string; - project:{displayName:string;filePath:string|null;dirty:boolean;canUndo:boolean;canRedo:boolean;recentFiles:string[]}; + project:{displayName:string;filePath?:string|null;dirty:boolean;canUndo:boolean;canRedo:boolean;recentFiles:string[]}; mode:"ltc"|"generate"; - transport:{status:"stopped"|"receiving"|"freerun"|"signalLost"|"error";statusText:string;detailText:string;signalErrorRatePercent:number|null;locked:boolean;triggerMuted:boolean;autoMuteEnabled:boolean;autoMutedCueId:string|null;autoUnmuteAtUtc:string|null;lastLtcReceivedAtUtc:string|null}; - receive:{selectedDeviceId:string|null;devices:AudioDevice[];offset:string;triggerWindowFrames:number;freerunDurationSeconds:number}; - generator:{running:boolean;startTime:string;frameRate:FrameRate;selectedOutputDeviceId:string|null;outputDevices:AudioDevice[];volume:number;ltcOutputActive:boolean;settingsPendingReset:boolean}; - currentClock:ClockState; nextCue:NextCueState|null; cues:CueDto[]; hosts:HostDto[]; + transport:{status:"stopped"|"receiving"|"freerun"|"signalLost"|"error";statusText:string;detailText:string;signalErrorRatePercent?:number|null;locked:boolean;triggerMuted:boolean;autoMuteEnabled:boolean;autoMutedCueId?:string|null;autoUnmuteAtUtc?:string|null;lastLtcReceivedAtUtc?:string|null}; + receive:{selectedDeviceId?:string|null;devices:AudioDevice[];offset:string;triggerWindowFrames:number;freerunDurationSeconds:number}; + generator:{running:boolean;startTime:string;loopEndTime?:string|null;frameRate:FrameRate;selectedOutputDeviceId?:string|null;outputDevices:AudioDevice[];volume:number;ltcOutputActive:boolean;settingsPendingReset:boolean}; + currentClock:ClockState; nextCue?:NextCueState|null; cues:CueDto[]; hosts:HostDto[]; cueSync:{oscAddress:string;targetHostIds:string[]}; triggerPanel:{rows:number;columns:number;buttons:TriggerButtonDto[]}; logs:LogDto[]; @@ -46,7 +48,7 @@ interface AppState { interface ClockState {raw:string;display:string;totalFrames:number;frameRate:FrameRate;dropFrame:boolean;receivedAtMonotonicMs:number;nextCueId?:string|null;framesUntilNextCue?:number|null} interface NextCueState {id:string;name:string;triggerTime:string;effectiveTriggerTime:string;framesUntil:number} interface AudioDevice {id:string;name:string;loopback:boolean} -interface CueDto {id:string;name:string;memo:string;triggerTime:string;effectiveTriggerTime:string;frameRate:FrameRate;oscAddress:string;additionalOscAddresses:string[];arguments:OscArgumentDto[];targetHostIds:string[];enabled:boolean;sendTriggerTimeAsSeconds:boolean;sendTimecode:string|null;triggerOffset:string|null;autoMuteOnFire:boolean;autoUnmuteAfter:string|null;runtime:{lastTriggeredAtUtc:string|null;flashToken:number;muteCountdownText:string}} +interface CueDto {id:string;name:string;memo:string;triggerTime:string;effectiveTriggerTime:string;frameRate:FrameRate;oscAddress:string;additionalOscAddresses:string[];arguments:OscArgumentDto[];targetHostIds:string[];enabled:boolean;sendTriggerTimeAsSeconds:boolean;sendTimecode?:string|null;triggerOffset?:string|null;autoMuteOnFire:boolean;autoUnmuteAfter?:string|null;runtime:{lastTriggeredAtUtc?:string|null;flashToken:number;muteCountdownText:string}} type OscArgumentDto={type:"int32";value:number}|{type:"float32";value:number}|{type:"string";value:string}; interface HostDto {id:string;name:string;ipAddress:string;port:number;enabled:boolean;reachability:"unknown"|"checking"|"reachable"|"unreachable"} interface TriggerButtonDto {id:string;row:number;column:number;label:string;oscAddress:string;arguments:OscArgumentDto[];targetHostIds:string[]} @@ -99,7 +101,7 @@ M0合否目安(推測): clock+wave、1000 cues表示を10分継続し、入 |`receive.setOffset`|`{value}`|`{normalized}` / `validation`| |`receive.setTriggerWindow`|`{frames}`|`{frames}` / `validation`| |`receive.setFreerunDuration`|`{seconds}`|`validation`| -|`generator.configure`|`{startTime,frameRate,outputDeviceId,volume}`|`validation`,`deviceNotFound`| +|`generator.configure`|`{startTime?,frameRate?,loopEndTime?,outputDeviceId?,volume?}`|`validation`,`deviceNotFound`。省いた項目は今の値のまま。`loopEndTime` は空文字か null でループ解除、開始 TC 以前なら `validation`。どれか 1 つでも `validation` になれば何も変えない| |`generator.start/stop/reset`|`{}`|`audioError`,`invalidState`| |`mute.set`, `autoMute.setEnabled`|`{muted? ,enabled?}`|`invalidState`| |`cue.add/update`|`{id?,cue:CueDraft}`|`{id?}` / `notFound`,`validation`,`conflict`| @@ -131,9 +133,9 @@ Host はページ読込完了後、`window.tcb.hostAttached()` を 250ms 間隔 ## WaveState(確定) ```ts -interface WaveState { sampleRate:number; windowMs:number; min:number[]; max:number[]; levelDbfs:number|null } +interface WaveState { sampleRate:number; windowMs:number; min:number[]; max:number[]; levelDbfs?:number|null } ``` -`min[i]`/`max[i]` は表示 i 点目の区間の最小/最大(−1..1)。点数は Web の `viewport.waveformWidth/2`(16..2048)。`levelDbfs` は直近区間のピーク(dBFS)。表示区間は UI 改修前(v2)と同じ約 0.1 フレーム分(30fps 基準で約 3.3ms、48kHz で 160 サンプル)なので、点数がサンプル数を上回るときは `min[i] == max[i]`(1 点 1 サンプル)になる。Web は塗りだけでなく線(stroke)で描くこと。 +`min[i]`/`max[i]` は表示 i 点目の区間の最小/最大(−1..1)。点数は Web の `viewport.waveformWidth/2`(16..2048)。`levelDbfs` は直近区間のピーク(dBFS)。無音(ピーク 0)なら null なので、キーごと届かない。表示区間は UI 改修前(v2)と同じ約 0.1 フレーム分(30fps 基準で約 3.3ms、48kHz で 160 サンプル)なので、点数がサンプル数を上回るときは `min[i] == max[i]`(1 点 1 サンプル)になる。Web は塗りだけでなく線(stroke)で描くこと。 ## M2b で確定した command の引数と結果(Host 実装済み, 2026-09-11) diff --git a/src/TimecodeBridge.Host/Bridge/CommandRouter.cs b/src/TimecodeBridge.Host/Bridge/CommandRouter.cs index 7082686..d49074b 100644 --- a/src/TimecodeBridge.Host/Bridge/CommandRouter.cs +++ b/src/TimecodeBridge.Host/Bridge/CommandRouter.cs @@ -216,47 +216,49 @@ public ResultMessage Execute(WebMessage msg) { var g = _state.Generator; var previousOutput = g.OutputDeviceId; var previousVolume = g.VolumeLevel; var previousRate = g.FrameRate; var previousStart = g.StartTime; var previousLoopEnd = g.LoopEndTime; - if (Str(a, "frameRate") is { } rateCode) - { - if (!HostState.TryParseFrameRate(rateCode, out var rate)) return Validation(id, "frameRate", "24 / 25 / 29.97df / 30"); - g.FrameRate = rate; - } + // 検証を全部済ませてから書き換える。途中で弾くと、開始 TC だけ新しく終了 TC は古いまま、のような組み合わせが残る + var rate = g.FrameRate; + if (Str(a, "frameRate") is { } rateCode && !HostState.TryParseFrameRate(rateCode, out rate)) + return Validation(id, "frameRate", "24 / 25 / 29.97df / 30"); + TimecodeValue startTc; if (Str(a, "startTime") is { } start) { - if (!HostState.TryParseTimecode(start, g.FrameRate, out var tc)) return Validation(id, "startTime", "HH:MM:SS:FF の形式で入力してください"); - g.StartTime = tc; + if (!HostState.TryParseTimecode(start, rate, out startTc)) return Validation(id, "startTime", "HH:MM:SS:FF の形式で入力してください"); } else { - g.StartTime = new TimecodeValue(g.StartTime.Hours, g.StartTime.Minutes, g.StartTime.Seconds, Math.Min(g.StartTime.Frames, g.FrameRate.FramesPerSecond() - 1), g.FrameRate); + startTc = new TimecodeValue(g.StartTime.Hours, g.StartTime.Minutes, g.StartTime.Seconds, Math.Min(g.StartTime.Frames, rate.FramesPerSecond() - 1), rate); } // loopEndTime は空文字と null でループ解除。範囲として成立しない値は弾く + var loopEndTc = g.LoopEndTime; if (Has(a, "loopEndTime")) { + loopEndTc = null; if (Str(a, "loopEndTime") is { Length: > 0 } loopEnd) { - if (!HostState.TryParseTimecode(loopEnd, g.FrameRate, out var endTc)) return Validation(id, "loopEndTime", "HH:MM:SS:FF の形式で入力してください"); - if (endTc.TotalFrames() <= g.StartTime.TotalFrames()) return Validation(id, "loopEndTime", "開始 TC より後の時刻を指定してください"); - g.LoopEndTime = endTc; - } - else - { - g.LoopEndTime = null; + if (!HostState.TryParseTimecode(loopEnd, rate, out var endTc)) return Validation(id, "loopEndTime", "HH:MM:SS:FF の形式で入力してください"); + if (endTc.TotalFrames() <= startTc.TotalFrames()) return Validation(id, "loopEndTime", "開始 TC より後の時刻を指定してください"); + loopEndTc = endTc; } } else if (g.LoopEndTime is { } keptEnd) { // レート変更で末尾のフレーム番号が範囲外になり、 // 開始 TC の変更で範囲として成立しなくなることがある - var clamped = new TimecodeValue(keptEnd.Hours, keptEnd.Minutes, keptEnd.Seconds, Math.Min(keptEnd.Frames, g.FrameRate.FramesPerSecond() - 1), g.FrameRate); - g.LoopEndTime = clamped.TotalFrames() > g.StartTime.TotalFrames() ? clamped : null; + var clamped = new TimecodeValue(keptEnd.Hours, keptEnd.Minutes, keptEnd.Seconds, Math.Min(keptEnd.Frames, rate.FramesPerSecond() - 1), rate); + loopEndTc = clamped.TotalFrames() > startTc.TotalFrames() ? clamped : null; } - if (Has(a, "outputDeviceId")) g.OutputDeviceId = Str(a, "outputDeviceId") ?? string.Empty; + var volume = g.VolumeLevel; if (Num(a, "volume") is { } vol) { if (vol < 0 || vol > 1) return Validation(id, "volume", "0〜1"); - g.VolumeLevel = (float)vol; + volume = (float)vol; } + g.FrameRate = rate; + g.StartTime = startTc; + g.LoopEndTime = loopEndTc; + if (Has(a, "outputDeviceId")) g.OutputDeviceId = Str(a, "outputDeviceId") ?? string.Empty; + g.VolumeLevel = volume; // 生成中は出力先と音量をその場で反映する。開始 TC・フレームレート・ループ範囲は再生し直すまで保留。 // 一時停止中に変えた場合も同じで、再開ではなく最初から掛け直さないと反映されない if (_engine.ActiveSource == TimecodeSourceType.Generator) diff --git a/src/TimecodeBridge.Web/dist/assets/app.js b/src/TimecodeBridge.Web/dist/assets/app.js index 9048daa..2b4390c 100644 --- a/src/TimecodeBridge.Web/dist/assets/app.js +++ b/src/TimecodeBridge.Web/dist/assets/app.js @@ -1,12 +1,12 @@ -"use strict";(()=>{var le,O,Ke,Xt,K,Le,Xe,Je,qe,ye,ve,_e,Jt,Z={},Ge=[],qt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,ce=Array.isArray;function W(e,t){for(var r in t)e[r]=t[r];return e}function we(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Gt(e,t,r){var o,i,a,u={};for(a in t)a=="key"?o=t[a]:a=="ref"?i=t[a]:u[a]=t[a];if(arguments.length>2&&(u.children=arguments.length>3?le.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(a in e.defaultProps)u[a]===void 0&&(u[a]=e.defaultProps[a]);return se(e,u,o,i,null)}function se(e,t,r,o,i){var a={type:e,props:t,key:r,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++Ke,__i:-1,__u:0};return i==null&&O.vnode!=null&&O.vnode(a),a}function H(e){return e.children}function ae(e,t){this.props=e,this.context=t}function G(e,t){if(t==null)return e.__?G(e.__,e.__i+1):null;for(var r;td&&K.sort(Je),e=K.shift(),d=K.length,e.__d&&(r=void 0,i=(o=(t=e).__v).__e,a=[],u=[],t.__P&&((r=W({},o)).__v=o.__v+1,O.vnode&&O.vnode(r),Te(t.__P,r,o,t.__n,t.__P.namespaceURI,32&o.__u?[i]:null,a,i??G(o),!!(32&o.__u),u),r.__v=o.__v,r.__.__k[r.__i]=r,Ze(a,r,u),r.__e!=i&&ze(r)));ie.__r=0}function Qe(e,t,r,o,i,a,u,d,m,p,s){var l,g,h,A,c,_,f,b=o&&o.__k||Ge,w=t.length;for(m=zt(r,t,b,m,w),l=0;l0?se(u.type,u.props,u.key,u.ref?u.ref:null,u.__v):u).__=e,u.__b=e.__b+1,d=null,(p=u.__i=Qt(u,r,m,l))!=-1&&(l--,(d=r[p])&&(d.__u|=2)),d==null||d.__v==null?(p==-1&&(i>s?g--:im?g--:g++,u.__u|=4))):e.__k[a]=null;if(l)for(a=0;a(s?1:0)){for(i=r-1,a=r+1;i>=0||a=0?i--:a++])!=null&&(2&p.__u)==0&&d==p.key&&m==p.type)return u}return-1}function Be(e,t,r){t[0]=="-"?e.setProperty(t,r??""):e[t]=r==null?"":typeof r!="number"||qt.test(t)?r:r+"px"}function oe(e,t,r,o,i){var a,u;e:if(t=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof o=="string"&&(e.style.cssText=o=""),o)for(t in o)r&&t in r||Be(e.style,t,"");if(r)for(t in r)o&&r[t]==o[t]||Be(e.style,t,r[t])}else if(t[0]=="o"&&t[1]=="n")a=t!=(t=t.replace(qe,"$1")),u=t.toLowerCase(),t=u in e||t=="onFocusOut"||t=="onFocusIn"?u.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+a]=r,r?o?r.u=o.u:(r.u=ye,e.addEventListener(t,a?_e:ve,a)):e.removeEventListener(t,a?_e:ve,a);else{if(i=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=r??"";break e}catch{}typeof r=="function"||(r==null||r===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&r==1?"":r))}}function Ve(e){return function(t){if(this.l){var r=this.l[t.type+e];if(t.t==null)t.t=ye++;else if(t.t0?e:ce(e)?e.map(et):W({},e)}function Yt(e,t,r,o,i,a,u,d,m){var p,s,l,g,h,A,c,_=r.props,f=t.props,b=t.type;if(b=="svg"?i="http://www.w3.org/2000/svg":b=="math"?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),a!=null){for(p=0;p=r.__.length&&r.__.push({}),r.__[e]}function C(e){return de=1,en(mt,e)}function en(e,t,r){var o=pe(z++,2);if(o.t=e,!o.__c&&(o.__=[r?r(t):mt(void 0,t),function(d){var m=o.__N?o.__N[0]:o.__[0],p=o.t(m,d);m!==p&&(o.__N=[p,o.__[1]],o.__c.setState({}))}],o.__c=I,!I.__f)){var i=function(d,m,p){if(!o.__c.__H)return!0;var s=o.__c.__H.__.filter(function(g){return!!g.__c});if(s.every(function(g){return!g.__N}))return!a||a.call(this,d,m,p);var l=o.__c.props!==d;return s.forEach(function(g){if(g.__N){var h=g.__[0];g.__=g.__N,g.__N=void 0,h!==g.__[0]&&(l=!0)}}),a&&a.call(this,d,m,p)||l};I.__f=!0;var a=I.shouldComponentUpdate,u=I.componentWillUpdate;I.componentWillUpdate=function(d,m,p){if(this.__e){var s=a;a=void 0,i(d,m,p),a=s}u&&u.call(this,d,m,p)},I.shouldComponentUpdate=i}return o.__N||o.__}function P(e,t){var r=pe(z++,3);!M.__s&&Ae(r.__H,t)&&(r.__=e,r.u=t,I.__H.__h.push(r))}function pt(e,t){var r=pe(z++,4);!M.__s&&Ae(r.__H,t)&&(r.__=e,r.u=t,I.__h.push(r))}function $(e){return de=5,tn(function(){return{current:e}},[])}function tn(e,t){var r=pe(z++,7);return Ae(r.__H,t)&&(r.__=e(),r.__H=t,r.__h=e),r.__}function nn(){for(var e;e=dt.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(ue),e.__H.__h.forEach(Se),e.__H.__h=[]}catch(t){e.__H.__h=[],M.__e(t,e.__v)}}M.__b=function(e){I=null,ot&&ot(e)},M.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),ct&&ct(e,t)},M.__r=function(e){st&&st(e),z=0;var t=(I=e.__c).__H;t&&(ke===I?(t.__h=[],I.__h=[],t.__.forEach(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(t.__h.forEach(ue),t.__h.forEach(Se),t.__h=[],z=0)),ke=I},M.diffed=function(e){at&&at(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(dt.push(t)!==1&&rt===M.requestAnimationFrame||((rt=M.requestAnimationFrame)||rn)(nn)),t.__H.__.forEach(function(r){r.u&&(r.__H=r.u),r.u=void 0})),ke=I=null},M.__c=function(e,t){t.some(function(r){try{r.__h.forEach(ue),r.__h=r.__h.filter(function(o){return!o.__||Se(o)})}catch(o){t.some(function(i){i.__h&&(i.__h=[])}),t=[],M.__e(o,r.__v)}}),it&&it(e,t)},M.unmount=function(e){lt&<(e);var t,r=e.__c;r&&r.__H&&(r.__H.__.forEach(function(o){try{ue(o)}catch(i){t=i}}),r.__H=void 0,t&&M.__e(t,r.__v))};var ut=typeof requestAnimationFrame=="function";function rn(e){var t,r=function(){clearTimeout(o),ut&&cancelAnimationFrame(t),setTimeout(e)},o=setTimeout(r,35);ut&&(t=requestAnimationFrame(r))}function ue(e){var t=I,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),I=t}function Se(e){var t=I;e.__c=e.__(),I=t}function Ae(e,t){return!e||e.length!==t.length||t.some(function(r,o){return r!==e[o]})}function mt(e,t){return typeof t=="function"?t(e):t}function ft(e,t){if(!e)return"";let r=Date.parse(e);if(Number.isNaN(r))return"";let o=r-t;if(o<=0)return"";let i=Math.ceil(o/1e3);return i<60?`${i}`:`${Math.floor(i/60)}:${String(i%60).padStart(2,"0")}`}var on=()=>({host:{sessionId:null,revision:null,state:null,clock:null,wave:null,clockSeq:-1,waveSeq:-1,connected:!1,resyncing:!1},ui:{selectedCueIds:new Set,anchorCueId:null,focusedCueId:null,cueScrollTop:0,cueColumnWidths:[38,105,280,220,50],drawerOpen:!1,drawerWidth:420,optionsOpen:!1,modalOpen:!1}});function gt(e,t){if(t.type==="snapshot")return e.host.sessionId=t.state.sessionId,e.host.revision=t.revision,e.host.state=t.state,e.host.clock=t.state.currentClock,e.host.connected=!0,e.host.resyncing=!1,"applied";if(t.type==="patch"){if(!e.host.state||t.baseRevision!==e.host.revision)return e.host.resyncing=!0,"resync";let{logsAppend:r,logsReset:o,nextCueCleared:i,openOptions:a,...u}=t.changes;return Object.assign(e.host.state,u),i&&(e.host.state.nextCue=null),a&&(e.ui.optionsOpen=!0),o?e.host.state.logs=o:r&&(e.host.state.logs=[...e.host.state.logs,...r].slice(-500)),e.host.revision=t.revision,"applied"}return t.type==="clock"?t.seq<=e.host.clockSeq?"ignored":(e.host.clockSeq=t.seq,e.host.clock=t.clock,"applied"):t.type==="wave"?t.seq<=e.host.waveSeq?"ignored":(e.host.waveSeq=t.seq,e.host.wave=t.wave,"applied"):"ignored"}var Ee=class{value=on();listeners=new Set;subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}notify(){for(let t of this.listeners)t()}updateUi(t){Object.assign(this.value.ui,t),this.notify()}},k=new Ee;var sn=0,De=new Map;function Q(e){window.invokeCSharpAction?.(JSON.stringify(e))}function x(e,t,r){let o=`web-${Date.now()}-${++sn}`,i={protocolVersion:1,type:"command",requestId:o,command:e,args:t,...r===void 0?{}:{expectedRevision:r}};return Q(i),new Promise((a,u)=>De.set(o,{resolve:a,reject:u}))}function bt(e){let t=De.get(e.requestId);t&&(De.delete(e.requestId),e.ok?t.resolve(e.data):t.reject(e.error))}function vt(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement&&(e.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(e.tagName))}function _t(e,t){if(e.repeat||e.isComposing||t||vt(e.target))return null;let r=e.metaKey||e.ctrlKey,o=e.key.toLowerCase();return r&&o==="n"?"projectNew":r&&o==="o"?"projectOpen":r&&o==="s"?e.shiftKey?"projectSaveAs":"projectSave":r&&o==="z"?e.shiftKey?"redo":"undo":e.ctrlKey&&!e.metaKey&&o==="y"?"redo":e.key==="Escape"?"closeDrawer":e.key==="ArrowUp"?"selectPrevious":e.key==="ArrowDown"?"selectNext":e.key==="Enter"?"editCue":e.key==="Delete"||e.key==="Backspace"?"deleteCue":null}var ht=e=>({ok:!0,value:e}),xe=e=>({ok:!1,message:e});function Oe(e,t=!1){if(!(t?/^[+-]\d{2}:\d{2}:\d{2}[:;]\d{2}$/:/^\d{2}:\d{2}:\d{2}[:;]\d{2}$/).test(e))return xe(t?"\xB1HH:MM:SS:FF \u5F62\u5F0F\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044":"HH:MM:SS:FF \u5F62\u5F0F\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044");let i=(t?e.slice(1):e).replace(";",":").split(":").map(Number);return(i[1]??99)<60&&(i[2]??99)<60?ht(e):xe("\u5206\u30FB\u79D2\u306F 00\u301C59 \u3067\u3059")}function Re(e){return/^\/(?:[^\s/#*,?\[\]{}]+(?:\/[^\s/#*,?\[\]{}]+)*)?$/.test(e)?ht(e):xe("/ \u3067\u59CB\u307E\u308B OSC\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044")}var ee=e=>({name:"",memo:"",triggerTime:"00:00:00:00",frameRate:e,oscAddress:"/",additionalOscAddresses:"",argumentsText:"",targetHostIds:[],enabled:!0,sendTriggerTimeAsSeconds:!1,sendTimecode:"",triggerOffset:"",autoMuteOnFire:!1,autoUnmuteAfter:""}),yt=e=>({...ee(e.frameRate),name:e.name,memo:e.memo,triggerTime:e.triggerTime,oscAddress:e.oscAddress,additionalOscAddresses:e.additionalOscAddresses.join(` +"use strict";(()=>{var le,x,Ke,Gt,K,We,Xe,qe,Ge,ye,ve,_e,zt,ee={},ze=[],Qt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i,ce=Array.isArray;function W(e,t){for(var r in t)e[r]=t[r];return e}function Te(e){e&&e.parentNode&&e.parentNode.removeChild(e)}function Yt(e,t,r){var o,i,a,u={};for(a in t)a=="key"?o=t[a]:a=="ref"?i=t[a]:u[a]=t[a];if(arguments.length>2&&(u.children=arguments.length>3?le.call(arguments,2):r),typeof e=="function"&&e.defaultProps!=null)for(a in e.defaultProps)u[a]===void 0&&(u[a]=e.defaultProps[a]);return se(e,u,o,i,null)}function se(e,t,r,o,i){var a={type:e,props:t,key:r,ref:o,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:i??++Ke,__i:-1,__u:0};return i==null&&x.vnode!=null&&x.vnode(a),a}function F(e){return e.children}function ae(e,t){this.props=e,this.context=t}function z(e,t){if(t==null)return e.__?z(e.__,e.__i+1):null;for(var r;td&&K.sort(qe),e=K.shift(),d=K.length,e.__d&&(r=void 0,i=(o=(t=e).__v).__e,a=[],u=[],t.__P&&((r=W({},o)).__v=o.__v+1,x.vnode&&x.vnode(r),we(t.__P,r,o,t.__n,t.__P.namespaceURI,32&o.__u?[i]:null,a,i??z(o),!!(32&o.__u),u),r.__v=o.__v,r.__.__k[r.__i]=r,et(a,r,u),r.__e!=i&&Qe(r)));ie.__r=0}function Ye(e,t,r,o,i,a,u,d,m,p,c){var s,g,h,A,l,_,f,b=o&&o.__k||ze,T=t.length;for(m=Zt(r,t,b,m,T),s=0;s0?se(u.type,u.props,u.key,u.ref?u.ref:null,u.__v):u).__=e,u.__b=e.__b+1,d=null,(p=u.__i=en(u,r,m,s))!=-1&&(s--,(d=r[p])&&(d.__u|=2)),d==null||d.__v==null?(p==-1&&(i>c?g--:im?g--:g++,u.__u|=4))):e.__k[a]=null;if(s)for(a=0;a(c?1:0)){for(i=r-1,a=r+1;i>=0||a=0?i--:a++])!=null&&(2&p.__u)==0&&d==p.key&&m==p.type)return u}return-1}function Ve(e,t,r){t[0]=="-"?e.setProperty(t,r??""):e[t]=r==null?"":typeof r!="number"||Qt.test(t)?r:r+"px"}function oe(e,t,r,o,i){var a,u;e:if(t=="style")if(typeof r=="string")e.style.cssText=r;else{if(typeof o=="string"&&(e.style.cssText=o=""),o)for(t in o)r&&t in r||Ve(e.style,t,"");if(r)for(t in r)o&&r[t]==o[t]||Ve(e.style,t,r[t])}else if(t[0]=="o"&&t[1]=="n")a=t!=(t=t.replace(Ge,"$1")),u=t.toLowerCase(),t=u in e||t=="onFocusOut"||t=="onFocusIn"?u.slice(2):t.slice(2),e.l||(e.l={}),e.l[t+a]=r,r?o?r.u=o.u:(r.u=ye,e.addEventListener(t,a?_e:ve,a)):e.removeEventListener(t,a?_e:ve,a);else{if(i=="http://www.w3.org/2000/svg")t=t.replace(/xlink(H|:h)/,"h").replace(/sName$/,"s");else if(t!="width"&&t!="height"&&t!="href"&&t!="list"&&t!="form"&&t!="tabIndex"&&t!="download"&&t!="rowSpan"&&t!="colSpan"&&t!="role"&&t!="popover"&&t in e)try{e[t]=r??"";break e}catch{}typeof r=="function"||(r==null||r===!1&&t[4]!="-"?e.removeAttribute(t):e.setAttribute(t,t=="popover"&&r==1?"":r))}}function Je(e){return function(t){if(this.l){var r=this.l[t.type+e];if(t.t==null)t.t=ye++;else if(t.t0?e:ce(e)?e.map(tt):W({},e)}function tn(e,t,r,o,i,a,u,d,m){var p,c,s,g,h,A,l,_=r.props,f=t.props,b=t.type;if(b=="svg"?i="http://www.w3.org/2000/svg":b=="math"?i="http://www.w3.org/1998/Math/MathML":i||(i="http://www.w3.org/1999/xhtml"),a!=null){for(p=0;p=r.__.length&&r.__.push({}),r.__[e]}function k(e){return de=1,rn(ft,e)}function rn(e,t,r){var o=pe(Q++,2);if(o.t=e,!o.__c&&(o.__=[r?r(t):ft(void 0,t),function(d){var m=o.__N?o.__N[0]:o.__[0],p=o.t(m,d);m!==p&&(o.__N=[p,o.__[1]],o.__c.setState({}))}],o.__c=I,!I.__f)){var i=function(d,m,p){if(!o.__c.__H)return!0;var c=o.__c.__H.__.filter(function(g){return!!g.__c});if(c.every(function(g){return!g.__N}))return!a||a.call(this,d,m,p);var s=o.__c.props!==d;return c.forEach(function(g){if(g.__N){var h=g.__[0];g.__=g.__N,g.__N=void 0,h!==g.__[0]&&(s=!0)}}),a&&a.call(this,d,m,p)||s};I.__f=!0;var a=I.shouldComponentUpdate,u=I.componentWillUpdate;I.componentWillUpdate=function(d,m,p){if(this.__e){var c=a;a=void 0,i(d,m,p),a=c}u&&u.call(this,d,m,p)},I.shouldComponentUpdate=i}return o.__N||o.__}function P(e,t){var r=pe(Q++,3);!M.__s&&Ae(r.__H,t)&&(r.__=e,r.u=t,I.__H.__h.push(r))}function mt(e,t){var r=pe(Q++,4);!M.__s&&Ae(r.__H,t)&&(r.__=e,r.u=t,I.__h.push(r))}function $(e){return de=5,on(function(){return{current:e}},[])}function on(e,t){var r=pe(Q++,7);return Ae(r.__H,t)&&(r.__=e(),r.__H=t,r.__h=e),r.__}function sn(){for(var e;e=pt.shift();)if(e.__P&&e.__H)try{e.__H.__h.forEach(ue),e.__H.__h.forEach(Se),e.__H.__h=[]}catch(t){e.__H.__h=[],M.__e(t,e.__v)}}M.__b=function(e){I=null,st&&st(e)},M.__=function(e,t){e&&t.__k&&t.__k.__m&&(e.__m=t.__k.__m),ut&&ut(e,t)},M.__r=function(e){at&&at(e),Q=0;var t=(I=e.__c).__H;t&&(ke===I?(t.__h=[],I.__h=[],t.__.forEach(function(r){r.__N&&(r.__=r.__N),r.u=r.__N=void 0})):(t.__h.forEach(ue),t.__h.forEach(Se),t.__h=[],Q=0)),ke=I},M.diffed=function(e){it&&it(e);var t=e.__c;t&&t.__H&&(t.__H.__h.length&&(pt.push(t)!==1&&ot===M.requestAnimationFrame||((ot=M.requestAnimationFrame)||an)(sn)),t.__H.__.forEach(function(r){r.u&&(r.__H=r.u),r.u=void 0})),ke=I=null},M.__c=function(e,t){t.some(function(r){try{r.__h.forEach(ue),r.__h=r.__h.filter(function(o){return!o.__||Se(o)})}catch(o){t.some(function(i){i.__h&&(i.__h=[])}),t=[],M.__e(o,r.__v)}}),lt&<(e,t)},M.unmount=function(e){ct&&ct(e);var t,r=e.__c;r&&r.__H&&(r.__H.__.forEach(function(o){try{ue(o)}catch(i){t=i}}),r.__H=void 0,t&&M.__e(t,r.__v))};var dt=typeof requestAnimationFrame=="function";function an(e){var t,r=function(){clearTimeout(o),dt&&cancelAnimationFrame(t),setTimeout(e)},o=setTimeout(r,35);dt&&(t=requestAnimationFrame(r))}function ue(e){var t=I,r=e.__c;typeof r=="function"&&(e.__c=void 0,r()),I=t}function Se(e){var t=I;e.__c=e.__(),I=t}function Ae(e,t){return!e||e.length!==t.length||t.some(function(r,o){return r!==e[o]})}function ft(e,t){return typeof t=="function"?t(e):t}function gt(e,t){if(!e)return"";let r=Date.parse(e);if(Number.isNaN(r))return"";let o=r-t;if(o<=0)return"";let i=Math.ceil(o/1e3);return i<60?`${i}`:`${Math.floor(i/60)}:${String(i%60).padStart(2,"0")}`}var ln=()=>({host:{sessionId:null,revision:null,state:null,clock:null,wave:null,clockSeq:-1,waveSeq:-1,connected:!1,resyncing:!1},ui:{selectedCueIds:new Set,anchorCueId:null,focusedCueId:null,cueScrollTop:0,cueColumnWidths:[38,105,280,220,50],drawerOpen:!1,drawerWidth:420,optionsOpen:!1,modalOpen:!1}});function bt(e,t){if(t.type==="snapshot")return e.host.sessionId=t.state.sessionId,e.host.revision=t.revision,e.host.state=t.state,e.host.clock=t.state.currentClock,e.host.connected=!0,e.host.resyncing=!1,"applied";if(t.type==="patch"){if(!e.host.state||t.baseRevision!==e.host.revision)return e.host.resyncing=!0,"resync";let{logsAppend:r,logsReset:o,nextCueCleared:i,openOptions:a,...u}=t.changes;return Object.assign(e.host.state,u),i&&(e.host.state.nextCue=null),a&&(e.ui.optionsOpen=!0),o?e.host.state.logs=o:r&&(e.host.state.logs=[...e.host.state.logs,...r].slice(-500)),e.host.revision=t.revision,"applied"}return t.type==="clock"?t.seq<=e.host.clockSeq?"ignored":(e.host.clockSeq=t.seq,e.host.clock=t.clock,"applied"):t.type==="wave"?t.seq<=e.host.waveSeq?"ignored":(e.host.waveSeq=t.seq,e.host.wave=t.wave,"applied"):"ignored"}var Ee=class{value=ln();listeners=new Set;subscribe(t){return this.listeners.add(t),()=>this.listeners.delete(t)}notify(){for(let t of this.listeners)t()}updateUi(t){Object.assign(this.value.ui,t),this.notify()}},S=new Ee;var cn=0,De=new Map;function Y(e){window.invokeCSharpAction?.(JSON.stringify(e))}function O(e,t,r){let o=`web-${Date.now()}-${++cn}`,i={protocolVersion:1,type:"command",requestId:o,command:e,args:t,...r===void 0?{}:{expectedRevision:r}};return Y(i),new Promise((a,u)=>De.set(o,{resolve:a,reject:u}))}function vt(e){let t=De.get(e.requestId);t&&(De.delete(e.requestId),e.ok?t.resolve(e.data):t.reject(e.error))}function _t(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement&&(e.isContentEditable||/^(INPUT|TEXTAREA|SELECT)$/.test(e.tagName))}function ht(e,t){if(e.repeat||e.isComposing||t||_t(e.target))return null;let r=e.metaKey||e.ctrlKey,o=e.key.toLowerCase();return r&&o==="n"?"projectNew":r&&o==="o"?"projectOpen":r&&o==="s"?e.shiftKey?"projectSaveAs":"projectSave":r&&o==="z"?e.shiftKey?"redo":"undo":e.ctrlKey&&!e.metaKey&&o==="y"?"redo":e.key==="Escape"?"closeDrawer":e.key==="ArrowUp"?"selectPrevious":e.key==="ArrowDown"?"selectNext":e.key==="Enter"?"editCue":e.key==="Delete"||e.key==="Backspace"?"deleteCue":null}var yt=e=>({ok:!0,value:e}),Oe=e=>({ok:!1,message:e});function xe(e,t=!1){if(!(t?/^[+-]\d{2}:\d{2}:\d{2}[:;]\d{2}$/:/^\d{2}:\d{2}:\d{2}[:;]\d{2}$/).test(e))return Oe(t?"\xB1HH:MM:SS:FF \u5F62\u5F0F\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044":"HH:MM:SS:FF \u5F62\u5F0F\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044");let i=(t?e.slice(1):e).replace(";",":").split(":").map(Number);return(i[1]??99)<60&&(i[2]??99)<60?yt(e):Oe("\u5206\u30FB\u79D2\u306F 00\u301C59 \u3067\u3059")}function Re(e){return/^\/(?:[^\s/#*,?\[\]{}]+(?:\/[^\s/#*,?\[\]{}]+)*)?$/.test(e)?yt(e):Oe("/ \u3067\u59CB\u307E\u308B OSC\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044")}var te=e=>({name:"",memo:"",triggerTime:"00:00:00:00",frameRate:e,oscAddress:"/",additionalOscAddresses:"",argumentsText:"",targetHostIds:[],enabled:!0,sendTriggerTimeAsSeconds:!1,sendTimecode:"",triggerOffset:"",autoMuteOnFire:!1,autoUnmuteAfter:""}),Tt=e=>({...te(e.frameRate),name:e.name,memo:e.memo,triggerTime:e.triggerTime,oscAddress:e.oscAddress,additionalOscAddresses:e.additionalOscAddresses.join(` `),argumentsText:e.arguments.map(t=>`${t.type}:${t.value}`).join(` -`),targetHostIds:[...e.targetHostIds],enabled:e.enabled,sendTriggerTimeAsSeconds:e.sendTriggerTimeAsSeconds,sendTimecode:e.sendTimecode??"",triggerOffset:e.triggerOffset??"",autoMuteOnFire:e.autoMuteOnFire,autoUnmuteAfter:e.autoUnmuteAfter??""});function te(e){let t=[];for(let[r,o]of e.split(/\r?\n/).entries()){if(!o.trim())continue;let i=o.indexOf(":"),a=o.slice(0,i),u=o.slice(i+1);if(i<0||!["int32","float32","string"].includes(a))return{error:`${r+1} \u884C\u76EE\u306F type:value \u5F62\u5F0F\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044`};if(a==="string")t.push({type:a,value:u});else{let d=Number(u);if(!Number.isFinite(d)||a==="int32"&&!Number.isInteger(d))return{error:`${r+1} \u884C\u76EE\u306E\u5024\u304C\u4E0D\u6B63\u3067\u3059`};t.push(a==="int32"?{type:a,value:d}:{type:"float32",value:d})}}return{value:t}}function me(e){let t={};e.name.trim()||(t.name="\u540D\u524D\u306F\u5FC5\u9808\u3067\u3059");let r=Oe(e.triggerTime);r.ok||(t.triggerTime=r.message);let o=Re(e.oscAddress);o.ok||(t.oscAddress=o.message);let i=e.additionalOscAddresses.split(/\r?\n|,/).map(u=>u.trim()).filter(Boolean);i.some(u=>!Re(u).ok)&&(t.additionalOscAddresses="\u5404\u884C\u306B / \u3067\u59CB\u307E\u308B\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044");let a=te(e.argumentsText);a.error&&(t.arguments=a.error);for(let[u,d,m]of[["sendTimecode",e.sendTimecode,!1],["triggerOffset",e.triggerOffset,!0],["autoUnmuteAfter",e.autoUnmuteAfter,!1]])d&&!Oe(d,m).ok&&(t[u]="\u6642\u523B\u5F62\u5F0F\u304C\u4E0D\u6B63\u3067\u3059");return Object.keys(t).length?{errors:t}:{errors:t,draft:{name:e.name.trim(),memo:e.memo,triggerTime:e.triggerTime,frameRate:e.frameRate,oscAddress:e.oscAddress,additionalOscAddresses:i,arguments:a.value,targetHostIds:e.targetHostIds,enabled:e.enabled,sendTriggerTimeAsSeconds:e.sendTriggerTimeAsSeconds,sendTimecode:e.sendTimecode||null,triggerOffset:e.triggerOffset||null,autoMuteOnFire:e.autoMuteOnFire,autoUnmuteAfter:e.autoUnmuteAfter||null}}}var Ie=(e,t)=>Object.fromEntries(Object.entries(e.fieldErrors??{}).filter(([r])=>r.startsWith(t+".")).map(([r,o])=>[r.slice(t.length+1),o]));var an=0,Kn=Array.isArray;function n(e,t,r,o,i,a){t||(t={});var u,d,m=t;if("ref"in m)for(d in m={},t)d=="ref"?u=t[d]:m[d]=t[d];var p={type:e,props:m,key:r,ref:u,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--an,__i:-1,__u:0,__source:i,__self:a};if(typeof e=="function"&&(u=e.defaultProps))for(d in u)m[d]===void 0&&(m[d]=u[d]);return O.vnode&&O.vnode(p),p}function Tt(e){return e.replace(/[0-9]/g,t=>String.fromCharCode(t.charCodeAt(0)-65248)).replace(/[^0-9]/g,"")}function Me(e,t=!1){let r=t&&e.startsWith("-")?"-":"+",i=(t&&/^[+-]/.test(e)?e.slice(1):e).split(/[:;]/).slice(0,4).map(Tt);return{sign:r,parts:[i[0]??"",i[1]??"",i[2]??"",i[3]??""]}}function fe(e,t="+",r=!1){return e.every(o=>o==="")?"":`${r?t:""}${e.map(o=>o.padStart(2,"0")).join(":")}`}function wt(e,t,r){let o=Tt(r),i=[...e];if(o.length<=2)return i[t]=o,{parts:i,focus:o.length===2&&t<3?t+1:null};for(let a=t,u=0;a<4&&u0?t-1:e==="ArrowRight"&&t<3?t+1:e==="Backspace"&&r&&t>0?t-1:null}var ne=e=>e==="24"?23:e==="25"?24:29;function re(e,t,r=!1){if(e==="")return e;let{sign:o,parts:i}=Me(e,r);return fe(i.map((a,u)=>Ct(a,u,t)),o,r)}function Ct(e,t,r){if(e==="")return e;let o=t===0?23:t===1||t===2?59:ne(r);return String(Math.min(o,Number(e))).padStart(2,"0")}function B({value:e,onChange:t,onCommit:r,frameRate:o,signed:i=!1,required:a=!1,disabled:u=!1,ariaLabel:d,class:m=""}){let p=Me(e,i),[s,l]=C(p.parts),[g,h]=C(p.sign),A=$([]),c=$(null),_=$(p.parts);P(()=>{if(e===c.current){c.current=null;return}let y=Me(e,i);_.current=y.parts,l(y.parts),h(y.sign)},[e,i]);let f=(y,T=g)=>{_.current=y,l(y);let S=fe(y,T,i);c.current=S,t?.(S)},b=y=>{y!==null&&A.current[y]?.focus()},w=y=>{let T=[..._.current];T[y]=Ct(T[y]??"",y,o),f(T),r?.(fe(T,g,i))};return n("span",{class:`timecode-input ${m}`,role:"group","aria-label":d,children:[i&&n("select",{class:"timecode-sign","aria-label":`${d}\u306E\u7B26\u53F7`,disabled:u,value:g,onChange:y=>{let T=y.currentTarget.value;h(T);let S=fe(_.current,T,!0);c.current=S,t?.(S),r?.(S)},children:[n("option",{value:"+",children:"+"}),n("option",{value:"-",children:"\u2212"})]}),s.map((y,T)=>n("span",{class:"timecode-segment",children:[n("input",{ref:S=>{A.current[T]=S},class:"timecode-part",inputMode:"numeric",pattern:"[0-9]*",maxlength:2,required:a,disabled:u,value:y,"aria-label":`${d} ${["\u6642","\u5206","\u79D2","\u30D5\u30EC\u30FC\u30E0"][T]??""}`,onBeforeInput:S=>{let R=S.data;R&&/[^0-9]/.test(R)&&S.preventDefault()},onCompositionStart:S=>{let R=S.currentTarget;R.blur(),window.setTimeout(()=>R.focus(),0)},onInput:S=>{let R=wt(_.current,T,S.currentTarget.value);f(R.parts),b(R.focus)},onPaste:S=>{S.preventDefault();let R=wt(_.current,T,S.clipboardData?.getData("text")??"");f(R.parts),b(R.focus)},onBlur:()=>w(T),onKeyDown:S=>{if(S.key==="ArrowUp"||S.key==="ArrowDown"){S.preventDefault();let V=T===0?23:T===1||T===2?59:ne(o),v=[..._.current],D=Number(v[T]||0);v[T]=String(Math.max(0,Math.min(V,D+(S.key==="ArrowUp"?1:-1)))).padStart(2,"0"),f(v);return}let R=ln(S.key,T,y==="");R!==null&&(S.preventDefault(),b(R))}}),T<3&&n("span",{class:"timecode-colon","aria-hidden":"true",children:":"})]})),n("small",{class:"timecode-limit",children:["FF 00\u2013",String(ne(o)).padStart(2,"0")]})]})}function X(e){return P(()=>{let t=r=>{r.key==="Escape"&&!r.isComposing&&(r.preventDefault(),e.close())};return window.addEventListener("keydown",t,!0),()=>window.removeEventListener("keydown",t,!0)},[e.close]),n("div",{class:"modal-shade",children:n("div",{class:`dialog ${e.wide?"wide":""} ${e.class??""}`,role:"dialog","aria-modal":"true",onKeyDown:t=>t.stopPropagation(),children:[n("div",{class:"dialog-title",children:[n("b",{children:e.title}),e.titleExtra,n("button",{class:"btn",onClick:e.close,children:"\u9589\u3058\u308B"})]}),e.children]})})}var ge=X,cn=({errors:e,name:t})=>n("small",{class:"field-error",children:e[t]??""}),un=["24","25","29.97df","30"],U=({label:e,name:t,errors:r,title:o,top:i,children:a})=>n("div",{class:`cue-row ${i?"top":""}`,children:[n("span",{class:"lbl",title:o,children:e}),n("div",{class:"ctl",children:[a,t&&r[t]&&n("small",{class:"field-error",children:r[t]})]})]});function Pe({cue:e,frameRate:t,hosts:r,close:o,done:i}){let[a,u]=C(()=>e?yt(e):{...ee(t),targetHostIds:r.map(c=>c.id)}),[d,m]=C({}),p=(c,_)=>u(f=>({...f,[c]:_})),s=(c,_,{signed:f=!1,disabled:b=!1}={})=>n(B,{ariaLabel:_,value:a[c],frameRate:a.frameRate,signed:f,disabled:b,required:c==="triggerTime",onChange:w=>p(c,w)}),l=(c,_)=>n("label",{class:"check",children:[n("input",{type:"checkbox",checked:a[c],onChange:f=>p(c,f.currentTarget.checked)}),_]}),g=(c,_,f,b)=>n("div",{class:"check-row",children:[n("label",{class:"check",children:[n("input",{type:"checkbox","aria-label":`${_}\u3092\u6307\u5B9A`,disabled:!f,checked:a[c]!=="",onChange:w=>p(c,w.currentTarget.checked?b:"")}),"\u6307\u5B9A"]}),s(c,_,{disabled:!f||a[c]===""})]}),h=async c=>{c.preventDefault();let _=me(a);if(!_.draft){m(_.errors);return}try{await x(e?"cue.update":"cue.add",e?{id:e.id,cue:_.draft}:{cue:_.draft}),i()}catch(f){m(Ie(f,"cue"))}},A=n("label",{class:"cue-frame-rate",children:[n("span",{children:"\u57FA\u6E96\u30D5\u30EC\u30FC\u30E0\u30EC\u30FC\u30C8"}),n("select",{class:"field",value:a.frameRate,onChange:c=>{let _=c.currentTarget.value;u(f=>({...f,frameRate:_,triggerTime:re(f.triggerTime,_),sendTimecode:re(f.sendTimecode,_),triggerOffset:re(f.triggerOffset,_,!0),autoUnmuteAfter:re(f.autoUnmuteAfter,_)}))},children:un.map(c=>n("option",{value:c,children:[c," fps"]}))}),n("small",{children:["FF 00\u2013",String(ne(a.frameRate)).padStart(2,"0")]})]});return n(ge,{title:e?"\u30AD\u30E5\u30FC\u3092\u7DE8\u96C6":"\u30AD\u30E5\u30FC\u3092\u8FFD\u52A0",close:o,class:"cue",titleExtra:A,children:n("form",{onSubmit:h,class:"cue-edit",children:[n(U,{label:"\u540D\u524D",name:"name",errors:d,children:n("input",{autofocus:!0,class:"field","aria-label":"\u540D\u524D",value:a.name,onInput:c=>p("name",c.currentTarget.value)})}),n(U,{label:"\u30C8\u30EA\u30AC\u30FC\u6642\u9593",name:"triggerTime",errors:d,children:s("triggerTime","\u30C8\u30EA\u30AC\u30FC\u6642\u9593")}),n(U,{label:"\u30C8\u30EA\u30AC\u30FC\u30AA\u30D5\u30BB\u30C3\u30C8",name:"triggerOffset",errors:d,title:"\u767A\u706B\u30BF\u30A4\u30DF\u30F3\u30B0\u3092\xB1\u305A\u3089\u3057\u307E\u3059\u3002\u5B9F\u969B\u306E\u767A\u706B\u6642\u523B = \u30C8\u30EA\u30AC\u30FC\u6642\u9593 \xB1 \u3053\u306E\u5024",children:s("triggerOffset","\u30C8\u30EA\u30AC\u30FC\u30AA\u30D5\u30BB\u30C3\u30C8",{signed:!0})}),n(U,{label:"OSC\u30A2\u30C9\u30EC\u30B9",errors:d,top:!0,children:[n("input",{class:"field mono","aria-label":"OSC\u30A2\u30C9\u30EC\u30B9",value:a.oscAddress,onInput:c=>p("oscAddress",c.currentTarget.value)}),d.oscAddress&&n("small",{class:"field-error",children:d.oscAddress}),n("span",{class:"hint",children:"\u8FFD\u52A0\u30A2\u30C9\u30EC\u30B9\uFF081\u884C1\u4EF6\u30FB\u5F15\u6570\u306A\u3057\u3067\u4E00\u7DD2\u306B\u9001\u4FE1\u3055\u308C\u307E\u3059\uFF09"}),n("textarea",{class:"mono","aria-label":"\u8FFD\u52A0\u30A2\u30C9\u30EC\u30B9",value:a.additionalOscAddresses,onInput:c=>p("additionalOscAddresses",c.currentTarget.value)}),d.additionalOscAddresses&&n("small",{class:"field-error",children:d.additionalOscAddresses})]}),n(U,{label:"TC\u79D2\u6570\u9001\u4FE1",errors:d,children:l("sendTriggerTimeAsSeconds","\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9\u3092\u79D2\u6570(float)\u3067\u5148\u982D\u5F15\u6570\u306B\u8FFD\u52A0")}),n(U,{label:"\u9001\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",name:"sendTimecode",errors:d,title:"\u79D2\u6570\u9001\u4FE1\u3067\u9001\u308B\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9\u3002\u672A\u6307\u5B9A\u306A\u3089\u30C8\u30EA\u30AC\u30FC\u6642\u9593\u3092\u305D\u306E\u307E\u307E\u9001\u308A\u307E\u3059",children:g("sendTimecode","\u9001\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",a.sendTriggerTimeAsSeconds,a.triggerTime||"00:00:00:00")}),n(U,{label:"\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8",errors:d,title:"\u3053\u306E\u30AD\u30E5\u30FC\u306E\u767A\u706B\u3068\u540C\u6642\u306BMUTE\uFF08\u81EA\u52D5\u30AD\u30E5\u30FC\u767A\u706B\u306E\u505C\u6B62\uFF09\u3092\u639B\u3051\u307E\u3059\u3002\u518D\u751F\u4E2D\u306B\u4E0D\u616E\u306ETC\u304C\u98DB\u3093\u3067\u304D\u3066\u3082\u4ED6\u306E\u30AD\u30E5\u30FC\u304C\u8AA4\u767A\u706B\u3057\u307E\u305B\u3093",children:l("autoMuteOnFire","\u767A\u706B\u3068\u540C\u6642\u306B\u81EA\u52D5\u3067\u30DF\u30E5\u30FC\u30C8\u3059\u308B")}),n(U,{label:"\u30DF\u30E5\u30FC\u30C8\u89E3\u9664",name:"autoUnmuteAfter",errors:d,title:"\u6307\u5B9A\u6642\u9593\u306E\u7D4C\u904E\u5F8C\u306BMUTE\u3092\u81EA\u52D5\u89E3\u9664\u3057\u307E\u3059\u3002\u672A\u6307\u5B9A\u306A\u3089\u624B\u52D5\u3067\u89E3\u9664\u3059\u308B\u307E\u3067\u30DF\u30E5\u30FC\u30C8\u3092\u7DAD\u6301\u3057\u307E\u3059",children:g("autoUnmuteAfter","\u30DF\u30E5\u30FC\u30C8\u89E3\u9664\u6642\u9593",a.autoMuteOnFire,"00:00:00:00")}),n(U,{label:"OSC\u5F15\u6570",name:"arguments",errors:d,top:!0,title:"type:value \u3092 1 \u884C 1 \u4EF6\u3002\u4F8B: int32:1 / float32:0.5 / string:GO",children:n("textarea",{class:"mono","aria-label":"OSC\u5F15\u6570",placeholder:`int32:1 +`),targetHostIds:[...e.targetHostIds],enabled:e.enabled,sendTriggerTimeAsSeconds:e.sendTriggerTimeAsSeconds,sendTimecode:e.sendTimecode??"",triggerOffset:e.triggerOffset??"",autoMuteOnFire:e.autoMuteOnFire,autoUnmuteAfter:e.autoUnmuteAfter??""});function ne(e){let t=[];for(let[r,o]of e.split(/\r?\n/).entries()){if(!o.trim())continue;let i=o.indexOf(":"),a=o.slice(0,i),u=o.slice(i+1);if(i<0||!["int32","float32","string"].includes(a))return{error:`${r+1} \u884C\u76EE\u306F type:value \u5F62\u5F0F\u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044`};if(a==="string")t.push({type:a,value:u});else{let d=Number(u);if(!Number.isFinite(d)||a==="int32"&&!Number.isInteger(d))return{error:`${r+1} \u884C\u76EE\u306E\u5024\u304C\u4E0D\u6B63\u3067\u3059`};t.push(a==="int32"?{type:a,value:d}:{type:"float32",value:d})}}return{value:t}}function me(e){let t={};e.name.trim()||(t.name="\u540D\u524D\u306F\u5FC5\u9808\u3067\u3059");let r=xe(e.triggerTime);r.ok||(t.triggerTime=r.message);let o=Re(e.oscAddress);o.ok||(t.oscAddress=o.message);let i=e.additionalOscAddresses.split(/\r?\n|,/).map(u=>u.trim()).filter(Boolean);i.some(u=>!Re(u).ok)&&(t.additionalOscAddresses="\u5404\u884C\u306B / \u3067\u59CB\u307E\u308B\u30A2\u30C9\u30EC\u30B9\u3092\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044");let a=ne(e.argumentsText);a.error&&(t.arguments=a.error);for(let[u,d,m]of[["sendTimecode",e.sendTimecode,!1],["triggerOffset",e.triggerOffset,!0],["autoUnmuteAfter",e.autoUnmuteAfter,!1]])d&&!xe(d,m).ok&&(t[u]="\u6642\u523B\u5F62\u5F0F\u304C\u4E0D\u6B63\u3067\u3059");return Object.keys(t).length?{errors:t}:{errors:t,draft:{name:e.name.trim(),memo:e.memo,triggerTime:e.triggerTime,frameRate:e.frameRate,oscAddress:e.oscAddress,additionalOscAddresses:i,arguments:a.value,targetHostIds:e.targetHostIds,enabled:e.enabled,sendTriggerTimeAsSeconds:e.sendTriggerTimeAsSeconds,sendTimecode:e.sendTimecode||null,triggerOffset:e.triggerOffset||null,autoMuteOnFire:e.autoMuteOnFire,autoUnmuteAfter:e.autoUnmuteAfter||null}}}var Ie=(e,t)=>Object.fromEntries(Object.entries(e.fieldErrors??{}).filter(([r])=>r.startsWith(t+".")).map(([r,o])=>[r.slice(t.length+1),o]));var un=0,zn=Array.isArray;function n(e,t,r,o,i,a){t||(t={});var u,d,m=t;if("ref"in m)for(d in m={},t)d=="ref"?u=t[d]:m[d]=t[d];var p={type:e,props:m,key:r,ref:u,__k:null,__:null,__b:0,__e:null,__c:null,constructor:void 0,__v:--un,__i:-1,__u:0,__source:i,__self:a};if(typeof e=="function"&&(u=e.defaultProps))for(d in u)m[d]===void 0&&(m[d]=u[d]);return x.vnode&&x.vnode(p),p}function Ct(e){return e.replace(/[0-9]/g,t=>String.fromCharCode(t.charCodeAt(0)-65248)).replace(/[^0-9]/g,"")}function Me(e,t=!1){let r=t&&e.startsWith("-")?"-":"+",i=(t&&/^[+-]/.test(e)?e.slice(1):e).split(/[:;]/).slice(0,4).map(Ct);return{sign:r,parts:[i[0]??"",i[1]??"",i[2]??"",i[3]??""]}}function fe(e,t="+",r=!1){return e.every(o=>o==="")?"":`${r?t:""}${e.map(o=>o.padStart(2,"0")).join(":")}`}function wt(e,t,r){let o=Ct(r),i=[...e];if(o.length<=2)return i[t]=o,{parts:i,focus:o.length===2&&t<3?t+1:null};for(let a=t,u=0;a<4&&u0?t-1:e==="ArrowRight"&&t<3?t+1:e==="Backspace"&&r&&t>0?t-1:null}function pn(e,t){e.button===0&&(e.preventDefault(),t.focus(),t.select())}var re=e=>e==="24"?23:e==="25"?24:29;function J(e,t,r=!1){if(e==="")return e;let{sign:o,parts:i}=Me(e,r);return fe(i.map((a,u)=>kt(a,u,t)),o,r)}function kt(e,t,r){if(e==="")return e;let o=t===0?23:t===1||t===2?59:re(r);return String(Math.min(o,Number(e))).padStart(2,"0")}function B({value:e,onChange:t,onCommit:r,frameRate:o,signed:i=!1,required:a=!1,disabled:u=!1,ariaLabel:d,class:m=""}){let p=Me(e,i),[c,s]=k(p.parts),[g,h]=k(p.sign),A=$([]),l=$(null),_=$(p.parts);P(()=>{if(e===l.current){l.current=null;return}let y=Me(e,i);_.current=y.parts,s(y.parts),h(y.sign)},[e,i]);let f=(y,w=g)=>{_.current=y,s(y);let C=fe(y,w,i);l.current=C,t?.(C)},b=y=>{y!==null&&A.current[y]?.focus()},T=y=>{let w=[..._.current];w[y]=kt(w[y]??"",y,o),f(w),r?.(fe(w,g,i))};return n("span",{class:`timecode-input ${m}`,role:"group","aria-label":d,children:[i&&n("select",{class:"timecode-sign","aria-label":`${d}\u306E\u7B26\u53F7`,disabled:u,value:g,onChange:y=>{let w=y.currentTarget.value;h(w);let C=fe(_.current,w,!0);l.current=C,t?.(C),r?.(C)},children:[n("option",{value:"+",children:"+"}),n("option",{value:"-",children:"\u2212"})]}),c.map((y,w)=>n("span",{class:"timecode-segment",children:[n("input",{ref:C=>{A.current[w]=C},class:"timecode-part",inputMode:"numeric",pattern:"[0-9]*",maxlength:2,required:a,disabled:u,value:y,"aria-label":`${d} ${["\u6642","\u5206","\u79D2","\u30D5\u30EC\u30FC\u30E0"][w]??""}`,onBeforeInput:C=>{let R=C.data;R&&/[^0-9]/.test(R)&&C.preventDefault()},onCompositionStart:C=>{let R=C.currentTarget;R.blur(),window.setTimeout(()=>R.focus(),0)},onInput:C=>{let R=wt(_.current,w,C.currentTarget.value);f(R.parts),b(R.focus)},onPaste:C=>{C.preventDefault();let R=wt(_.current,w,C.clipboardData?.getData("text")??"");f(R.parts),b(R.focus)},onFocus:C=>C.currentTarget.select(),onMouseDown:C=>pn(C,C.currentTarget),onBlur:()=>T(w),onKeyDown:C=>{if(C.key==="ArrowUp"||C.key==="ArrowDown"){C.preventDefault();let V=w===0?23:w===1||w===2?59:re(o),v=[..._.current],D=Number(v[w]||0);v[w]=String(Math.max(0,Math.min(V,D+(C.key==="ArrowUp"?1:-1)))).padStart(2,"0"),f(v);return}let R=dn(C.key,w,y==="");R!==null&&(C.preventDefault(),b(R))}}),w<3&&n("span",{class:"timecode-colon","aria-hidden":"true",children:":"})]})),n("small",{class:"timecode-limit",children:["FF 00\u2013",String(re(o)).padStart(2,"0")]})]})}function X(e){return P(()=>{let t=r=>{r.key==="Escape"&&!r.isComposing&&(r.preventDefault(),e.close())};return window.addEventListener("keydown",t,!0),()=>window.removeEventListener("keydown",t,!0)},[e.close]),n("div",{class:"modal-shade",children:n("div",{class:`dialog ${e.wide?"wide":""} ${e.class??""}`,role:"dialog","aria-modal":"true",onKeyDown:t=>t.stopPropagation(),children:[n("div",{class:"dialog-title",children:[n("b",{children:e.title}),e.titleExtra,n("button",{class:"btn",onClick:e.close,children:"\u9589\u3058\u308B"})]}),e.children]})})}var ge=X,mn=({errors:e,name:t})=>n("small",{class:"field-error",children:e[t]??""}),fn=["24","25","29.97df","30"],U=({label:e,name:t,errors:r,title:o,top:i,children:a})=>n("div",{class:`cue-row ${i?"top":""}`,children:[n("span",{class:"lbl",title:o,children:e}),n("div",{class:"ctl",children:[a,t&&r[t]&&n("small",{class:"field-error",children:r[t]})]})]});function Pe({cue:e,frameRate:t,hosts:r,close:o,done:i}){let[a,u]=k(()=>e?Tt(e):{...te(t),targetHostIds:r.map(l=>l.id)}),[d,m]=k({}),p=(l,_)=>u(f=>({...f,[l]:_})),c=(l,_,{signed:f=!1,disabled:b=!1}={})=>n(B,{ariaLabel:_,value:a[l],frameRate:a.frameRate,signed:f,disabled:b,required:l==="triggerTime",onChange:T=>p(l,T)}),s=(l,_)=>n("label",{class:"check",children:[n("input",{type:"checkbox",checked:a[l],onChange:f=>p(l,f.currentTarget.checked)}),_]}),g=(l,_,f,b)=>n("div",{class:"check-row",children:[n("label",{class:"check",children:[n("input",{type:"checkbox","aria-label":`${_}\u3092\u6307\u5B9A`,disabled:!f,checked:a[l]!=="",onChange:T=>p(l,T.currentTarget.checked?b:"")}),"\u6307\u5B9A"]}),c(l,_,{disabled:!f||a[l]===""})]}),h=async l=>{l.preventDefault();let _=me(a);if(!_.draft){m(_.errors);return}try{await O(e?"cue.update":"cue.add",e?{id:e.id,cue:_.draft}:{cue:_.draft}),i()}catch(f){m(Ie(f,"cue"))}},A=n("label",{class:"cue-frame-rate",children:[n("span",{children:"\u57FA\u6E96\u30D5\u30EC\u30FC\u30E0\u30EC\u30FC\u30C8"}),n("select",{class:"field",value:a.frameRate,onChange:l=>{let _=l.currentTarget.value;u(f=>({...f,frameRate:_,triggerTime:J(f.triggerTime,_),sendTimecode:J(f.sendTimecode,_),triggerOffset:J(f.triggerOffset,_,!0),autoUnmuteAfter:J(f.autoUnmuteAfter,_)}))},children:fn.map(l=>n("option",{value:l,children:[l," fps"]}))}),n("small",{children:["FF 00\u2013",String(re(a.frameRate)).padStart(2,"0")]})]});return n(ge,{title:e?"\u30AD\u30E5\u30FC\u3092\u7DE8\u96C6":"\u30AD\u30E5\u30FC\u3092\u8FFD\u52A0",close:o,class:"cue",titleExtra:A,children:n("form",{onSubmit:h,class:"cue-edit",children:[n(U,{label:"\u540D\u524D",name:"name",errors:d,children:n("input",{autofocus:!0,class:"field","aria-label":"\u540D\u524D",value:a.name,onInput:l=>p("name",l.currentTarget.value)})}),n(U,{label:"\u30C8\u30EA\u30AC\u30FC\u6642\u9593",name:"triggerTime",errors:d,children:c("triggerTime","\u30C8\u30EA\u30AC\u30FC\u6642\u9593")}),n(U,{label:"\u30C8\u30EA\u30AC\u30FC\u30AA\u30D5\u30BB\u30C3\u30C8",name:"triggerOffset",errors:d,title:"\u767A\u706B\u30BF\u30A4\u30DF\u30F3\u30B0\u3092\xB1\u305A\u3089\u3057\u307E\u3059\u3002\u5B9F\u969B\u306E\u767A\u706B\u6642\u523B = \u30C8\u30EA\u30AC\u30FC\u6642\u9593 \xB1 \u3053\u306E\u5024",children:c("triggerOffset","\u30C8\u30EA\u30AC\u30FC\u30AA\u30D5\u30BB\u30C3\u30C8",{signed:!0})}),n(U,{label:"OSC\u30A2\u30C9\u30EC\u30B9",errors:d,top:!0,children:[n("input",{class:"field mono","aria-label":"OSC\u30A2\u30C9\u30EC\u30B9",value:a.oscAddress,onInput:l=>p("oscAddress",l.currentTarget.value)}),d.oscAddress&&n("small",{class:"field-error",children:d.oscAddress}),n("span",{class:"hint",children:"\u8FFD\u52A0\u30A2\u30C9\u30EC\u30B9\uFF081\u884C1\u4EF6\u30FB\u5F15\u6570\u306A\u3057\u3067\u4E00\u7DD2\u306B\u9001\u4FE1\u3055\u308C\u307E\u3059\uFF09"}),n("textarea",{class:"mono","aria-label":"\u8FFD\u52A0\u30A2\u30C9\u30EC\u30B9",value:a.additionalOscAddresses,onInput:l=>p("additionalOscAddresses",l.currentTarget.value)}),d.additionalOscAddresses&&n("small",{class:"field-error",children:d.additionalOscAddresses})]}),n(U,{label:"TC\u79D2\u6570\u9001\u4FE1",errors:d,children:s("sendTriggerTimeAsSeconds","\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9\u3092\u79D2\u6570(float)\u3067\u5148\u982D\u5F15\u6570\u306B\u8FFD\u52A0")}),n(U,{label:"\u9001\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",name:"sendTimecode",errors:d,title:"\u79D2\u6570\u9001\u4FE1\u3067\u9001\u308B\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9\u3002\u672A\u6307\u5B9A\u306A\u3089\u30C8\u30EA\u30AC\u30FC\u6642\u9593\u3092\u305D\u306E\u307E\u307E\u9001\u308A\u307E\u3059",children:g("sendTimecode","\u9001\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",a.sendTriggerTimeAsSeconds,a.triggerTime||"00:00:00:00")}),n(U,{label:"\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8",errors:d,title:"\u3053\u306E\u30AD\u30E5\u30FC\u306E\u767A\u706B\u3068\u540C\u6642\u306BMUTE\uFF08\u81EA\u52D5\u30AD\u30E5\u30FC\u767A\u706B\u306E\u505C\u6B62\uFF09\u3092\u639B\u3051\u307E\u3059\u3002\u518D\u751F\u4E2D\u306B\u4E0D\u616E\u306ETC\u304C\u98DB\u3093\u3067\u304D\u3066\u3082\u4ED6\u306E\u30AD\u30E5\u30FC\u304C\u8AA4\u767A\u706B\u3057\u307E\u305B\u3093",children:s("autoMuteOnFire","\u767A\u706B\u3068\u540C\u6642\u306B\u81EA\u52D5\u3067\u30DF\u30E5\u30FC\u30C8\u3059\u308B")}),n(U,{label:"\u30DF\u30E5\u30FC\u30C8\u89E3\u9664",name:"autoUnmuteAfter",errors:d,title:"\u6307\u5B9A\u6642\u9593\u306E\u7D4C\u904E\u5F8C\u306BMUTE\u3092\u81EA\u52D5\u89E3\u9664\u3057\u307E\u3059\u3002\u672A\u6307\u5B9A\u306A\u3089\u624B\u52D5\u3067\u89E3\u9664\u3059\u308B\u307E\u3067\u30DF\u30E5\u30FC\u30C8\u3092\u7DAD\u6301\u3057\u307E\u3059",children:g("autoUnmuteAfter","\u30DF\u30E5\u30FC\u30C8\u89E3\u9664\u6642\u9593",a.autoMuteOnFire,"00:00:00:00")}),n(U,{label:"OSC\u5F15\u6570",name:"arguments",errors:d,top:!0,title:"type:value \u3092 1 \u884C 1 \u4EF6\u3002\u4F8B: int32:1 / float32:0.5 / string:GO",children:n("textarea",{class:"mono","aria-label":"OSC\u5F15\u6570",placeholder:`int32:1 float32:0.5 -string:GO`,value:a.argumentsText,onInput:c=>p("argumentsText",c.currentTarget.value)})}),n(U,{label:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8",name:"targetHostIds",errors:d,top:!0,children:n("div",{class:"host-pick",children:[n("div",{class:"host-pick-actions",children:[n("button",{type:"button",class:"btn mini",disabled:!r.length,onClick:()=>p("targetHostIds",r.map(c=>c.id)),children:"\u5168\u9078\u629E"}),n("button",{type:"button",class:"btn mini",disabled:!a.targetHostIds.length,onClick:()=>p("targetHostIds",[]),children:"\u5168\u89E3\u9664"})]}),n("div",{class:"host-pick-list",children:r.length?r.map(c=>n("label",{class:"check",children:[n("input",{type:"checkbox",checked:a.targetHostIds.includes(c.id),onChange:_=>p("targetHostIds",_.currentTarget.checked?[...a.targetHostIds,c.id]:a.targetHostIds.filter(f=>f!==c.id))}),n("span",{children:c.name})]})):n("span",{class:"host-pick-empty",children:["\u30DB\u30B9\u30C8\u304C\u672A\u767B\u9332\u3067\u3059\u3002",n("br",{}),"\u5148\u306B\u300C\u30DB\u30B9\u30C8\u7BA1\u7406\u300D\u304B\u3089\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044"]})})]})}),n(U,{label:"\u30E1\u30E2",name:"memo",errors:d,top:!0,children:n("textarea",{"aria-label":"\u30E1\u30E2",value:a.memo,onInput:c=>p("memo",c.currentTarget.value)})}),n(U,{label:"",errors:d,children:l("enabled","\u6709\u52B9")}),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:o,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:e?"\u66F4\u65B0":"\u8FFD\u52A0"})]})]})})}function kt({cue:e,close:t,done:r}){let[o,i]=C(2),[a,u]=C("00:00:00:00"),[d,m]=C("");return n(ge,{title:"\u9023\u7D9A\u8907\u88FD",close:t,children:n("form",{class:"simple-form",onSubmit:async p=>{p.preventDefault();try{await x("cue.duplicate",{id:e.id,count:o,interval:a}),r()}catch(s){m(s.message)}},children:[n("label",{children:["\u8907\u88FD\u6570",n("input",{class:"field count",type:"number",min:"1",max:"500",value:o,onInput:p=>i(Number(p.currentTarget.value))})]}),n("div",{class:"simple-row",children:[n("span",{children:"\u9593\u9694"}),n(B,{ariaLabel:"\u8907\u88FD\u306E\u9593\u9694",value:a,frameRate:e.frameRate,onChange:u})]}),n("small",{class:"hint",children:["\u300C",e.name,"\u300D\u306E ",e.effectiveTriggerTime," \u304B\u3089\u9593\u9694\u305A\u3064\u5F8C\u308D\u306B\u4E26\u3079\u307E\u3059"]}),d&&n("small",{class:"field-error",children:d}),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:"\u8907\u88FD"})]})]})})}function St({ids:e,hosts:t,frameRate:r,close:o,done:i,notice:a}){let[u,d]=C(new Set),[m,p]=C({}),[s,l]=C({}),g={oscAddress:"OSC\u30A2\u30C9\u30EC\u30B9",additionalOscAddresses:"\u8FFD\u52A0\u30A2\u30C9\u30EC\u30B9\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09",sendTriggerTimeAsSeconds:"TC\u79D2\u6570\u9001\u4FE1",sendTimecode:"\u9001\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",targetHostIds:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8",arguments:"OSC\u5F15\u6570\uFF08type:value\u30011 \u884C 1 \u4EF6\uFF09",triggerOffset:"\u30C8\u30EA\u30AC\u30FC\u30AA\u30D5\u30BB\u30C3\u30C8",autoMuteOnFire:"\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8",autoUnmuteAfter:"\u30DF\u30E5\u30FC\u30C8\u89E3\u9664",memo:"\u30E1\u30E2",enabled:"\u6709\u52B9"},h=["sendTimecode","triggerOffset","autoUnmuteAfter"],A=["enabled","sendTriggerTimeAsSeconds","autoMuteOnFire"];return n(ge,{title:`${e.length} \u4EF6\u3092\u4E00\u62EC\u7DE8\u96C6`,close:o,wide:!0,children:n("form",{class:"batch-form",onSubmit:async c=>{c.preventDefault();let _={};for(let f of u){let b=m[f];if(b===void 0&&(b=A.includes(f)?!1:f==="targetHostIds"?[]:""),f==="arguments"){let w=te(String(b));if(w.error){l({arguments:w.error});return}b=w.value??[]}f==="additionalOscAddresses"&&(b=String(b).split(",").map(w=>w.trim()).filter(Boolean)),h.includes(f)&&b===""&&(b=null),_[f]=b}try{let f=await x("cue.batchUpdate",{ids:e,changes:_});f.offsetSkipped>0&&a(`${f.offsetSkipped} \u4EF6\u306F\u30AA\u30D5\u30BB\u30C3\u30C8\u9069\u7528\u5F8C\u306E\u6642\u523B\u304C\u7BC4\u56F2\u5916\u306E\u305F\u3081\u30AA\u30D5\u30BB\u30C3\u30C8\u3092\u4ED8\u3051\u307E\u305B\u3093\u3067\u3057\u305F`),i()}catch(f){l(Ie(f,"changes"))}},children:[Object.entries(g).map(([c,_])=>n("div",{class:"batch-row",children:[n("label",{children:[n("input",{type:"checkbox",checked:u.has(c),onChange:f=>{let b=f.currentTarget.checked;d(w=>{let y=new Set(w);return b?y.add(c):y.delete(c),y})}}),_]}),n("div",{children:[A.includes(c)?n("input",{type:"checkbox",onChange:f=>{let b=f.currentTarget.checked;p(w=>({...w,[c]:b}))}}):c==="targetHostIds"?n("div",{class:"host-pick-list",children:t.map(f=>n("label",{children:[n("input",{type:"checkbox",onChange:b=>{let w=b.currentTarget.checked;p(y=>{let T=y[c]??[];return{...y,[c]:w?[...T,f.id]:T.filter(S=>S!==f.id)}})}}),n("span",{children:f.name})]}))}):h.includes(c)?n(B,{ariaLabel:_,value:String(m[c]??""),frameRate:r,signed:c==="triggerOffset",onChange:f=>p(b=>({...b,[c]:f}))}):c==="arguments"?n("textarea",{class:"mono","aria-label":_,placeholder:`int32:1 +string:GO`,value:a.argumentsText,onInput:l=>p("argumentsText",l.currentTarget.value)})}),n(U,{label:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8",name:"targetHostIds",errors:d,top:!0,children:n("div",{class:"host-pick",children:[n("div",{class:"host-pick-actions",children:[n("button",{type:"button",class:"btn mini",disabled:!r.length,onClick:()=>p("targetHostIds",r.map(l=>l.id)),children:"\u5168\u9078\u629E"}),n("button",{type:"button",class:"btn mini",disabled:!a.targetHostIds.length,onClick:()=>p("targetHostIds",[]),children:"\u5168\u89E3\u9664"})]}),n("div",{class:"host-pick-list",children:r.length?r.map(l=>n("label",{class:"check",children:[n("input",{type:"checkbox",checked:a.targetHostIds.includes(l.id),onChange:_=>p("targetHostIds",_.currentTarget.checked?[...a.targetHostIds,l.id]:a.targetHostIds.filter(f=>f!==l.id))}),n("span",{children:l.name})]})):n("span",{class:"host-pick-empty",children:["\u30DB\u30B9\u30C8\u304C\u672A\u767B\u9332\u3067\u3059\u3002",n("br",{}),"\u5148\u306B\u300C\u30DB\u30B9\u30C8\u7BA1\u7406\u300D\u304B\u3089\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044"]})})]})}),n(U,{label:"\u30E1\u30E2",name:"memo",errors:d,top:!0,children:n("textarea",{"aria-label":"\u30E1\u30E2",value:a.memo,onInput:l=>p("memo",l.currentTarget.value)})}),n(U,{label:"",errors:d,children:s("enabled","\u6709\u52B9")}),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:o,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:e?"\u66F4\u65B0":"\u8FFD\u52A0"})]})]})})}function St({cue:e,close:t,done:r}){let[o,i]=k(2),[a,u]=k("00:00:00:00"),[d,m]=k("");return n(ge,{title:"\u9023\u7D9A\u8907\u88FD",close:t,children:n("form",{class:"simple-form",onSubmit:async p=>{p.preventDefault();try{await O("cue.duplicate",{id:e.id,count:o,interval:a}),r()}catch(c){m(c.message)}},children:[n("label",{children:["\u8907\u88FD\u6570",n("input",{class:"field count",type:"number",min:"1",max:"500",value:o,onInput:p=>i(Number(p.currentTarget.value))})]}),n("div",{class:"simple-row",children:[n("span",{children:"\u9593\u9694"}),n(B,{ariaLabel:"\u8907\u88FD\u306E\u9593\u9694",value:a,frameRate:e.frameRate,onChange:u})]}),n("small",{class:"hint",children:["\u300C",e.name,"\u300D\u306E ",e.effectiveTriggerTime," \u304B\u3089\u9593\u9694\u305A\u3064\u5F8C\u308D\u306B\u4E26\u3079\u307E\u3059"]}),d&&n("small",{class:"field-error",children:d}),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:"\u8907\u88FD"})]})]})})}function At({ids:e,hosts:t,frameRate:r,close:o,done:i,notice:a}){let[u,d]=k(new Set),[m,p]=k({}),[c,s]=k({}),g={oscAddress:"OSC\u30A2\u30C9\u30EC\u30B9",additionalOscAddresses:"\u8FFD\u52A0\u30A2\u30C9\u30EC\u30B9\uFF08\u30AB\u30F3\u30DE\u533A\u5207\u308A\uFF09",sendTriggerTimeAsSeconds:"TC\u79D2\u6570\u9001\u4FE1",sendTimecode:"\u9001\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",targetHostIds:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8",arguments:"OSC\u5F15\u6570\uFF08type:value\u30011 \u884C 1 \u4EF6\uFF09",triggerOffset:"\u30C8\u30EA\u30AC\u30FC\u30AA\u30D5\u30BB\u30C3\u30C8",autoMuteOnFire:"\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8",autoUnmuteAfter:"\u30DF\u30E5\u30FC\u30C8\u89E3\u9664",memo:"\u30E1\u30E2",enabled:"\u6709\u52B9"},h=["sendTimecode","triggerOffset","autoUnmuteAfter"],A=["enabled","sendTriggerTimeAsSeconds","autoMuteOnFire"];return n(ge,{title:`${e.length} \u4EF6\u3092\u4E00\u62EC\u7DE8\u96C6`,close:o,wide:!0,children:n("form",{class:"batch-form",onSubmit:async l=>{l.preventDefault();let _={};for(let f of u){let b=m[f];if(b===void 0&&(b=A.includes(f)?!1:f==="targetHostIds"?[]:""),f==="arguments"){let T=ne(String(b));if(T.error){s({arguments:T.error});return}b=T.value??[]}f==="additionalOscAddresses"&&(b=String(b).split(",").map(T=>T.trim()).filter(Boolean)),h.includes(f)&&b===""&&(b=null),_[f]=b}try{let f=await O("cue.batchUpdate",{ids:e,changes:_});f.offsetSkipped>0&&a(`${f.offsetSkipped} \u4EF6\u306F\u30AA\u30D5\u30BB\u30C3\u30C8\u9069\u7528\u5F8C\u306E\u6642\u523B\u304C\u7BC4\u56F2\u5916\u306E\u305F\u3081\u30AA\u30D5\u30BB\u30C3\u30C8\u3092\u4ED8\u3051\u307E\u305B\u3093\u3067\u3057\u305F`),i()}catch(f){s(Ie(f,"changes"))}},children:[Object.entries(g).map(([l,_])=>n("div",{class:"batch-row",children:[n("label",{children:[n("input",{type:"checkbox",checked:u.has(l),onChange:f=>{let b=f.currentTarget.checked;d(T=>{let y=new Set(T);return b?y.add(l):y.delete(l),y})}}),_]}),n("div",{children:[A.includes(l)?n("input",{type:"checkbox",onChange:f=>{let b=f.currentTarget.checked;p(T=>({...T,[l]:b}))}}):l==="targetHostIds"?n("div",{class:"host-pick-list",children:t.map(f=>n("label",{children:[n("input",{type:"checkbox",onChange:b=>{let T=b.currentTarget.checked;p(y=>{let w=y[l]??[];return{...y,[l]:T?[...w,f.id]:w.filter(C=>C!==f.id)}})}}),n("span",{children:f.name})]}))}):h.includes(l)?n(B,{ariaLabel:_,value:String(m[l]??""),frameRate:r,signed:l==="triggerOffset",onChange:f=>p(b=>({...b,[l]:f}))}):l==="arguments"?n("textarea",{class:"mono","aria-label":_,placeholder:`int32:1 float32:0.5 -string:GO`,value:String(m[c]??""),onInput:f=>{let b=f.currentTarget.value;p(w=>({...w,[c]:b}))}}):n("input",{class:"field",value:String(m[c]??""),onInput:f=>{let b=f.currentTarget.value;p(w=>({...w,[c]:b}))}}),n(cn,{errors:s,name:c})]})]})),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:o,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",disabled:!u.size,children:"\u9069\u7528"})]})]})})}function J({message:e,close:t,confirm:r,confirmLabel:o="\u524A\u9664"}){return n(ge,{title:"\u78BA\u8A8D",close:t,children:[n("div",{class:"confirm-body",children:e}),n("div",{class:"dialog-actions",children:[n("button",{class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn danger",onClick:r,children:o})]})]})}function At({close:e,notice:t}){let r=k.value.host.state.transport;P(()=>k.updateUi({modalOpen:!0}),[]);let o=(i,a)=>void x(i,{enabled:a}).catch(u=>t(u.message));return n(X,{title:"\u30AA\u30D7\u30B7\u30E7\u30F3",close:e,children:n("div",{class:"options",children:[n("h3",{children:"\u30AA\u30FC\u30C8\u30DF\u30E5\u30FC\u30C8"}),n("label",{class:"check options-row",children:[n("input",{type:"checkbox",checked:r.autoMuteEnabled,onChange:i=>o("autoMute.setEnabled",i.currentTarget.checked)}),n("span",{children:[n("b",{children:"\u767A\u706B\u5F8C\u30AA\u30FC\u30C8\u30DF\u30E5\u30FC\u30C8\u3092\u4F7F\u3046"}),n("small",{children:"\u5207\u308B\u3068\u3001\u30AD\u30E5\u30FC\u3054\u3068\u306E\u300C\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8\u300D\u3082\u50CD\u304D\u307E\u305B\u3093\u3002\u30AD\u30E5\u30FC\u30EA\u30B9\u30C8\u306E\u30C4\u30FC\u30EB\u30D0\u30FC\u304B\u3089\u3082\u5207\u308A\u66FF\u3048\u3089\u308C\u307E\u3059"})]})]}),n("label",{class:"check options-row",children:[n("input",{type:"checkbox",checked:r.autoMuteOnManualTrigger,onChange:i=>o("autoMute.setOnManualTrigger",i.currentTarget.checked)}),n("span",{children:[n("b",{children:"\u624B\u52D5\u3067\u53E9\u3044\u305F\u3068\u304D\u3082\u30DF\u30E5\u30FC\u30C8\u3059\u308B"}),n("small",{children:"\u884C\u306E \u25B6 \u3067\u767A\u706B\u3057\u305F\u3068\u304D\u306E\u52D5\u4F5C\u3067\u3059\u3002\u5207\u3063\u3066\u3042\u308B\u3068\u3001\u9032\u884C\u306E\u78BA\u8A8D\u3084\u5DEE\u3057\u8FBC\u307F\u3067\u53E9\u3044\u3066\u3082\u30DF\u30E5\u30FC\u30C8\u3055\u308C\u305A\u3001\u5F8C\u7D9A\u306E\u81EA\u52D5\u767A\u706B\u304C\u6B62\u307E\u308A\u307E\u305B\u3093"})]})]}),n("div",{class:"dialog-actions",children:n("button",{type:"button",class:"btn primary",onClick:e,children:"\u9589\u3058\u308B"})})]})})}var He=(e,t={})=>void x(e,t),dn=e=>He("receive.selectDevice",{deviceId:e||null});async function pn(e){e(!0);try{await x("audio.refreshDevices",{direction:"capture"})}catch{}finally{e(!1)}}function mn(e,t,r=Date.now()){if(e!=="signalLost"&&e!=="freerun")return null;if(!t)return"\u6700\u7D42\u53D7\u4FE1\u306A\u3057";let o=Date.parse(t);return Number.isFinite(o)?`\u6700\u7D42\u53D7\u4FE1 ${Math.max(0,Math.floor((r-o)/1e3))} \u79D2\u524D`:"\u6700\u7D42\u53D7\u4FE1\u306A\u3057"}function Et(){let e=k.value.host.state,t=e.receive.selectedDeviceId,[r,o]=C(Date.now()),[i,a]=C(!1),u=e.transport.status==="signalLost"||e.transport.status==="freerun";P(()=>{if(!u)return;o(Date.now());let m=window.setInterval(()=>o(Date.now()),1e3);return()=>window.clearInterval(m)},[u,e.transport.lastLtcReceivedAtUtc]);let d=mn(e.transport.status,e.transport.lastLtcReceivedAtUtc,r);return n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"TC \u5165\u51FA\u529B"}),n("span",{class:"tiny",children:"LTC \u53D7\u4FE1\u8A2D\u5B9A"})]}),n("div",{class:"status",children:[n("span",{children:[n("i",{class:"led"}),"\u5165\u529B ",n("b",{children:e.transport.locked?"\u63A5\u7D9A":"\u672A\u63A5\u7D9A"})]}),n("span",{children:[n("i",{class:"led"}),"LTC ",n("b",{children:e.transport.statusText}),d&&n("span",{class:"tiny muted",children:[" ",d]}),e.transport.signalErrorRatePercent!=null&&n("span",{class:"tiny muted",children:[" \u8AA4\u308A\u7387 ",e.transport.signalErrorRatePercent.toFixed(1),"%"]})]}),n("span",{children:["\u25CB \u51FA\u529B ",n("b",{children:"\u505C\u6B62"})]}),n("span",{children:[n("i",{class:"led"}),"\u9001\u51FA ",n("b",{children:e.transport.triggerMuted?"MUTE":"LIVE"})]})]}),n("div",{class:"settings",children:[n("div",{class:"set device-set",children:[n("span",{class:"tiny",children:"\u5165\u529B\u30C7\u30D0\u30A4\u30B9"}),n("select",{class:"field","aria-label":"\u5165\u529B\u30C7\u30D0\u30A4\u30B9",value:t??"",onChange:m=>dn(m.currentTarget.value),children:[n("option",{value:"",children:"\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"}),e.receive.devices.map(m=>n("option",{value:m.id,children:m.name}))]}),n(fn,{scanning:i,onClick:()=>void pn(a)})]}),n("div",{class:"set",children:[n("span",{class:"tiny",children:"\u63A5\u7D9A"}),n("span",{class:`field status-field ${t?"":"device-required"}`,children:t?e.transport.detailText:"\u5165\u529B\u30C7\u30D0\u30A4\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044"}),n("button",{class:"btn",disabled:!t,onClick:()=>He("ltc.reconnect",{deviceId:t}),children:"\u518D\u63A5\u7D9A"})]}),n("div",{class:"set",children:[n("span",{class:"tiny",children:"\u30D5\u30EA\u30FC\u30E9\u30F3"}),n("input",{class:"field","aria-label":"\u30D5\u30EA\u30FC\u30E9\u30F3\uFF08\u79D2\uFF09",type:"number",min:"0",step:"0.1",value:e.receive.freerunDurationSeconds,onChange:m=>He("receive.setFreerunDuration",{seconds:Number(m.currentTarget.value)})}),n("span",{class:"tiny unit",children:"\u79D2"})]})]}),n(gn,{})]})}function fn({scanning:e,onClick:t}){return n(H,{children:[n("button",{class:"btn rescan",disabled:e,"aria-busy":e,onClick:t,children:e?"\u30B9\u30AD\u30E3\u30F3\u4E2D\u2026":"\u518D\u30B9\u30AD\u30E3\u30F3"}),e&&n("div",{class:"scan-progress",role:"progressbar","aria-label":"\u30C7\u30D0\u30A4\u30B9\u3092\u30B9\u30AD\u30E3\u30F3\u4E2D",children:n("i",{})})]})}function gn(){let e=k.value.host.wave;if(!e)return n("div",{class:"wave",children:n("span",{class:"tiny",children:"\u6CE2\u5F62\u5F85\u6A5F\u4E2D"})});let t=Math.min(e.min.length,e.max.length),r=[];for(let o=0;o=0;o--)r.push(`${o/Math.max(1,t-1)*360},${15-(e.min[o]??0)*14}`);return n("div",{class:"wave",children:n("svg",{viewBox:"0 0 360 30",preserveAspectRatio:"none",children:n("polygon",{points:r.join(" ")})})})}var bn=e=>e==="24"?24:e==="25"?25:30;function Dt(e,t,r=10){let o=e.split(":").map(p=>Number(p));if(o.length!==4||o.some(p=>!Number.isFinite(p)))return e;let i=bn(t),a=((o[0]*60+o[1])*60+o[2])*i+o[3]+r*i,u=24*3600*i-1,d=Math.min(a,u),m=p=>String(p).padStart(2,"0");return[m(Math.floor(d/(3600*i))),m(Math.floor(d/(60*i))%60),m(Math.floor(d/i)%60),m(d%i)].join(":")}function xt({notice:e}){let t=k.value.host.state.generator,r=()=>({startTime:t.startTime,loopEndTime:t.loopEndTime,frameRate:t.frameRate,outputDeviceId:t.selectedOutputDeviceId??"",volume:t.volume}),[o,i]=C(r),a=$(null);P(()=>i(r()),[t.startTime,t.loopEndTime,t.frameRate,t.selectedOutputDeviceId,t.volume]);let u=s=>void x("generator.configure",s).catch(l=>e(l.message)),d=(s,l)=>{let g={...o,[s]:l};i(g),u(g)},m=s=>d("loopEndTime",s?o.loopEndTime??Dt(o.startTime,o.frameRate):null),p=(s,l=!1)=>{let g={...o,volume:s};i(g),a.current!==null&&window.clearTimeout(a.current),l?u(g):a.current=window.setTimeout(()=>u(g),100)};return n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"TC \u5165\u51FA\u529B"}),n("span",{class:"tiny",children:"\u5185\u90E8\u751F\u6210\u8A2D\u5B9A"})]}),n("div",{class:"status",children:[n("span",{children:["\u25CB \u5165\u529B ",n("b",{children:"\u505C\u6B62"})]}),n("span",{children:[n("i",{class:"led"}),"\u751F\u6210 ",n("b",{children:t.running?"\u518D\u751F\u4E2D":"\u505C\u6B62"})]}),n("span",{children:[n("i",{class:"led"}),"\u51FA\u529B ",n("b",{children:t.ltcOutputActive?"\u9001\u51FA\u4E2D":"\u505C\u6B62"})]}),n("span",{children:["\u97F3\u91CF ",n("b",{children:[Math.round(o.volume*100),"%"]})]})]}),n("div",{class:"settings generator-settings",children:[n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u958B\u59CB TC"}),n(B,{value:o.startTime,frameRate:o.frameRate,ariaLabel:"\u958B\u59CB\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",required:!0,onChange:s=>d("startTime",s)})]}),n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u30EB\u30FC\u30D7"}),n("span",{class:"loop-toggle",children:[n("input",{type:"checkbox",checked:o.loopEndTime!==null,onChange:s=>m(s.currentTarget.checked)}),n("span",{children:"\u958B\u59CB TC \u304B\u3089\u4E0B\u306E\u6642\u523B\u307E\u3067\u3092\u7E70\u308A\u8FD4\u3059"})]})]}),o.loopEndTime!==null&&n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u7D42\u4E86 TC"}),n(B,{value:o.loopEndTime,frameRate:o.frameRate,ariaLabel:"\u30EB\u30FC\u30D7\u7D42\u4E86\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",required:!0,onChange:s=>d("loopEndTime",s)})]}),n("label",{children:[n("span",{class:"tiny",children:"FPS"}),n("select",{class:"field",value:o.frameRate,onChange:s=>d("frameRate",s.currentTarget.value),children:["24","25","29.97df","30"].map(s=>n("option",{value:s,children:s}))})]}),n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u51FA\u529B\u30C7\u30D0\u30A4\u30B9"}),n("select",{class:"field",value:o.outputDeviceId,onChange:s=>d("outputDeviceId",s.currentTarget.value),children:[n("option",{value:"",children:"\u306A\u3057\uFF08\u51FA\u529B\u3057\u306A\u3044\uFF09"}),t.outputDevices.map(s=>n("option",{value:s.id,children:s.name}))]})]}),n("label",{class:"wide-control volume-control",children:[n("span",{class:"tiny",children:"\u97F3\u91CF"}),n("input",{type:"range",min:"0",max:"1",step:"0.01",value:o.volume,onInput:s=>p(Number(s.currentTarget.value)),onPointerUp:s=>p(Number(s.currentTarget.value),!0)})]})]}),t.running&&t.settingsPendingReset&&n("small",{class:"pending-note",children:"\u8A2D\u5B9A\u306F\u518D\u751F\u3057\u76F4\u3059\u3068\u53CD\u6620\u3055\u308C\u307E\u3059"}),n("div",{class:"generator-actions",children:[n("button",{class:`btn transport-toggle ${t.running?"danger":""}`,onClick:()=>void x(t.running?"generator.stop":"generator.start",{}).catch(s=>e(s.message)),children:t.running?"\u25A0 \u505C\u6B62":"\u25B6 \u518D\u751F"}),n("button",{class:"btn",onClick:()=>void x("generator.reset",{}).catch(s=>e(s.message)),children:"\u30EA\u30BB\u30C3\u30C8"})]})]})}function vn(e){let t={};e.name.trim()||(t.name="\u540D\u524D\u306F\u5FC5\u9808\u3067\u3059"),e.ipAddress.trim()||(t.ipAddress="IP \u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059");let r=Number(e.port);return(!Number.isInteger(r)||r<1||r>65535)&&(t.port="1\u301C65535 \u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044"),t}var _n=e=>Object.fromEntries(Object.entries(e.fieldErrors??{}).filter(([t])=>t.startsWith("host.")).map(([t,r])=>[t.slice(5),r]));function hn({host:e,close:t}){let[r,o]=C({name:e?.name??"",ipAddress:e?.ipAddress??"",port:String(e?.port??53e3)}),[i,a]=C({});P(()=>k.updateUi({modalOpen:!0}),[]);let u=(d,m)=>n("label",{class:"form-field",children:[n("span",{children:m}),n("input",{autofocus:d==="name",class:"field",value:r[d],onInput:p=>{let s=p.currentTarget.value;o(l=>({...l,[d]:s}))}}),n("small",{class:"field-error",children:i[d]??""})]});return n(X,{title:e?"\u30DB\u30B9\u30C8\u3092\u7DE8\u96C6":"\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0",close:t,children:n("form",{class:"simple-form host-form",onSubmit:async d=>{d.preventDefault();let m=vn(r);if(Object.keys(m).length){a(m);return}try{let p={name:r.name.trim(),ipAddress:r.ipAddress.trim(),port:Number(r.port),enabled:e?.enabled??!0};await x(e?"host.update":"host.add",e?{id:e.id,host:p}:{host:p}),t()}catch(p){a(_n(p))}},children:[u("name","\u540D\u524D"),u("ipAddress","IP \u30A2\u30C9\u30EC\u30B9"),u("port","\u30DD\u30FC\u30C8"),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:e?"\u66F4\u65B0":"\u8FFD\u52A0"})]})]})})}function yn(e,t,r){let o=t.filter(u=>u.targetHostIds.includes(e.id)).length,i=r.filter(u=>u.targetHostIds.includes(e.id)).length,a=[o?`\u30AD\u30E5\u30FC ${o} \u4EF6`:"",i?`\u30DD\u30F3\u51FA\u3057 ${i} \u4EF6`:""].filter(Boolean).join("\u3068");return a?`\u300C${e.name}\u300D\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F ${a}\u304C\u9001\u4FE1\u5148\u306B\u3057\u3066\u3044\u307E\u3059\u3002\u524A\u9664\u3059\u308B\u3068\u305D\u308C\u3089\u306F\u9001\u4FE1\u5148\u3092\u5931\u3044\u307E\u3059`:`\u300C${e.name}\u300D\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F`}function Ot({notice:e}){let t=k.value.host.state,[r,o]=C(null),[i,a]=C(null),u=()=>{o(null),a(null),k.updateUi({modalOpen:!1})},d=(m,p)=>void x(m,p).then(s=>{if(m==="host.ping"){let l=s??{};e(l.reachable===void 0?"\u758E\u901A\u78BA\u8A8D\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F":l.reachable?`\u758E\u901A OK \xB7 ${l.latencyMs??"--"} ms`:"\u758E\u901A\u3067\u304D\u307E\u305B\u3093")}}).catch(s=>e(s.message));return n(H,{children:[n("div",{class:"panel-toolbar",children:[n("b",{children:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8"}),n("button",{class:"btn right",onClick:()=>o("new"),children:"\uFF0B \u8FFD\u52A0"})]}),n("div",{class:"host-list",children:t.hosts.map(m=>n("div",{class:`host-row ${m.enabled?"":"disabled"}`,children:[n("span",{class:`reach ${m.reachability}`}),n("b",{class:"host-name",children:m.name}),n("span",{class:"mono host-address",children:[m.ipAddress,":",m.port]}),n("div",{class:"host-actions",children:[n("label",{children:[n("input",{type:"checkbox",checked:m.enabled,onChange:p=>d("host.setEnabled",{id:m.id,enabled:p.currentTarget.checked})}),"\u6709\u52B9"]}),n("button",{class:"btn",onClick:()=>d("host.ping",{id:m.id}),children:"\u758E\u901A\u78BA\u8A8D"}),n("button",{class:"btn",onClick:()=>o(m),children:"\u7DE8\u96C6"}),n("button",{class:"btn danger-link",onClick:()=>{a(m),k.updateUi({modalOpen:!0})},children:"\u524A\u9664"})]})]}))}),r&&n(hn,{host:r==="new"?void 0:r,close:u})," ",i&&n(J,{message:yn(i,t.cues,t.triggerPanel.buttons),close:u,confirm:()=>{d("host.remove",{id:i.id}),u()}})]})}var wn=e=>[...e].sort((t,r)=>Date.parse(r.timestampUtc)-Date.parse(t.timestampUtc));function Rt(){let[e,t]=C(!1),r=wn(k.value.host.state.logs),o=e?r.filter(u=>!u.success):r,i=$(null),a=$(!0);return pt(()=>{let u=i.current;u&&a.current&&(u.scrollTop=0)},[o.length]),n(H,{children:[n("div",{class:"panel-toolbar",children:[n("b",{children:"\u9001\u4FE1\u30ED\u30B0"}),n("span",{class:"tiny",children:"\u65B0\u3057\u3044\u9806"}),n("label",{class:"check tiny log-filter",children:[n("input",{type:"checkbox",checked:e,onChange:u=>t(u.currentTarget.checked)}),"\u5931\u6557\u306E\u307F"]}),n("button",{class:"btn right",onClick:()=>void x("logs.clear",{}),children:"\u30AF\u30EA\u30A2"})]}),n("div",{class:"dock log-dock",ref:i,onScroll:u=>{a.current=u.currentTarget.scrollTop<4},children:o.length?o.map(u=>n("div",{class:u.success?"log-success":"failure",children:[n("time",{children:new Date(u.timestampUtc).toLocaleTimeString("ja-JP")}),n("span",{children:u.message})]})):n("div",{class:"muted",children:e&&r.length?"\u5931\u6557\u3057\u305F\u9001\u4FE1\u306F\u3042\u308A\u307E\u305B\u3093":"\u9001\u4FE1\u30ED\u30B0\u306F\u3042\u308A\u307E\u305B\u3093"})})]})}function It({notice:e}){let t=k.value.host.state,[r,o]=C("logs");return n(H,{children:[n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"Cue-Sync \u9001\u4FE1\u8A2D\u5B9A"}),n("span",{class:"tiny mono",children:t.cueSync.oscAddress})]}),n("div",{class:"set",children:[n("span",{class:"tiny",children:"OSC\u30A2\u30C9\u30EC\u30B9"}),n("input",{class:"field mono","aria-label":"Cue-Sync OSC\u30A2\u30C9\u30EC\u30B9",value:t.cueSync.oscAddress,onChange:i=>void x("cueSync.configure",{oscAddress:i.currentTarget.value,targetHostIds:t.cueSync.targetHostIds})}),n("button",{class:"btn",onClick:()=>void x("cueSync.send",{}),children:"\u5358\u767A\u9001\u4FE1"})]}),n("div",{class:"hosts",children:[t.hosts.map(i=>n("label",{children:[n("input",{type:"checkbox",checked:t.cueSync.targetHostIds.includes(i.id),onChange:a=>void x("cueSync.configure",{oscAddress:t.cueSync.oscAddress,targetHostIds:a.currentTarget.checked?[...t.cueSync.targetHostIds,i.id]:t.cueSync.targetHostIds.filter(u=>u!==i.id)})}),n("span",{children:i.name})]})),n("span",{class:"tiny",children:[t.cueSync.targetHostIds.length," / ",t.hosts.length," \u6709\u52B9"]})]})]}),n("div",{class:"tab-panel",children:[n("div",{class:"tabs",children:[n("button",{class:`tab ${r==="logs"?"on":""}`,onClick:()=>o("logs"),children:"\u9001\u4FE1\u30ED\u30B0"}),n("button",{class:`tab ${r==="hosts"?"on":""}`,onClick:()=>o("hosts"),children:"\u30DB\u30B9\u30C8\u7BA1\u7406"})]}),r==="logs"?n(Rt,{}):n(Ot,{notice:e})]})]})}function Mt(e,t){let r=[];for(let o of t){let i=o.runtime.flashToken,a=e.get(o.id);e.set(o.id,i),a!==void 0&&i>a&&r.push(o.id)}return r}function Tn({cell:e,close:t,notice:r}){let o=e.button,[i,a]=C(o?.label??""),[u,d]=C(o?.oscAddress??"/"),[m,p]=C(o?.arguments.map(c=>`${c.type}:${c.value}`).join(` -`)??""),[s,l]=C(o?.targetHostIds??[]),[g,h]=C({}),A=k.value.host.state;return P(()=>k.updateUi({modalOpen:!0}),[]),n(X,{title:o?"\u30DD\u30F3\u51FA\u3057\u30DC\u30BF\u30F3\u3092\u7DE8\u96C6":"\u30DD\u30F3\u51FA\u3057\u30DC\u30BF\u30F3\u3092\u4F5C\u6210",close:t,children:n("form",{class:"cue-form",onSubmit:async c=>{c.preventDefault();let _={};i.trim()||(_.label="\u30E9\u30D9\u30EB\u306F\u5FC5\u9808\u3067\u3059"),u.startsWith("/")||(_.oscAddress="/ \u3067\u59CB\u3081\u3066\u304F\u3060\u3055\u3044");let f=te(m);if(f.error&&(_.arguments=f.error),Object.keys(_).length){h(_);return}try{await x("triggerPanel.upsertButton",{button:{...o?{id:o.id}:{},row:e.row,column:e.column,label:i.trim(),oscAddress:u,arguments:f.value??[],targetHostIds:s}}),t()}catch(b){r(b.message)}},children:[n("label",{class:"form-field",children:[n("span",{children:"\u30E9\u30D9\u30EB"}),n("input",{autofocus:!0,class:"field",value:i,onInput:c=>a(c.currentTarget.value)}),n("small",{class:"field-error",children:g.label})]}),n("label",{class:"form-field",children:[n("span",{children:"OSC\u30A2\u30C9\u30EC\u30B9"}),n("input",{class:"field mono",value:u,onInput:c=>d(c.currentTarget.value)}),n("small",{class:"field-error",children:g.oscAddress})]}),n("label",{class:"form-field",children:[n("span",{children:"OSC\u5F15\u6570\uFF08type:value\u30011 \u884C 1 \u4EF6\uFF09"}),n("textarea",{class:"mono",value:m,onInput:c=>p(c.currentTarget.value),placeholder:`int32:1 +string:GO`,value:String(m[l]??""),onInput:f=>{let b=f.currentTarget.value;p(T=>({...T,[l]:b}))}}):n("input",{class:"field",value:String(m[l]??""),onInput:f=>{let b=f.currentTarget.value;p(T=>({...T,[l]:b}))}}),n(mn,{errors:c,name:l})]})]})),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:o,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",disabled:!u.size,children:"\u9069\u7528"})]})]})})}function q({message:e,close:t,confirm:r,confirmLabel:o="\u524A\u9664"}){return n(ge,{title:"\u78BA\u8A8D",close:t,children:[n("div",{class:"confirm-body",children:e}),n("div",{class:"dialog-actions",children:[n("button",{class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn danger",onClick:r,children:o})]})]})}function Et({close:e,notice:t}){let r=S.value.host.state.transport;P(()=>S.updateUi({modalOpen:!0}),[]);let o=(i,a)=>void O(i,{enabled:a}).catch(u=>t(u.message));return n(X,{title:"\u30AA\u30D7\u30B7\u30E7\u30F3",close:e,children:n("div",{class:"options",children:[n("h3",{children:"\u30AA\u30FC\u30C8\u30DF\u30E5\u30FC\u30C8"}),n("label",{class:"check options-row",children:[n("input",{type:"checkbox",checked:r.autoMuteEnabled,onChange:i=>o("autoMute.setEnabled",i.currentTarget.checked)}),n("span",{children:[n("b",{children:"\u767A\u706B\u5F8C\u30AA\u30FC\u30C8\u30DF\u30E5\u30FC\u30C8\u3092\u4F7F\u3046"}),n("small",{children:"\u5207\u308B\u3068\u3001\u30AD\u30E5\u30FC\u3054\u3068\u306E\u300C\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8\u300D\u3082\u50CD\u304D\u307E\u305B\u3093\u3002\u30AD\u30E5\u30FC\u30EA\u30B9\u30C8\u306E\u30C4\u30FC\u30EB\u30D0\u30FC\u304B\u3089\u3082\u5207\u308A\u66FF\u3048\u3089\u308C\u307E\u3059"})]})]}),n("label",{class:"check options-row",children:[n("input",{type:"checkbox",checked:r.autoMuteOnManualTrigger,onChange:i=>o("autoMute.setOnManualTrigger",i.currentTarget.checked)}),n("span",{children:[n("b",{children:"\u624B\u52D5\u3067\u53E9\u3044\u305F\u3068\u304D\u3082\u30DF\u30E5\u30FC\u30C8\u3059\u308B"}),n("small",{children:"\u884C\u306E \u25B6 \u3067\u767A\u706B\u3057\u305F\u3068\u304D\u306E\u52D5\u4F5C\u3067\u3059\u3002\u5207\u3063\u3066\u3042\u308B\u3068\u3001\u9032\u884C\u306E\u78BA\u8A8D\u3084\u5DEE\u3057\u8FBC\u307F\u3067\u53E9\u3044\u3066\u3082\u30DF\u30E5\u30FC\u30C8\u3055\u308C\u305A\u3001\u5F8C\u7D9A\u306E\u81EA\u52D5\u767A\u706B\u304C\u6B62\u307E\u308A\u307E\u305B\u3093"})]})]}),n("div",{class:"dialog-actions",children:n("button",{type:"button",class:"btn primary",onClick:e,children:"\u9589\u3058\u308B"})})]})})}var Fe=(e,t={})=>void O(e,t),gn=e=>Fe("receive.selectDevice",{deviceId:e||null});async function bn(e){e(!0);try{await O("audio.refreshDevices",{direction:"capture"})}catch{}finally{e(!1)}}function vn(e,t,r=Date.now()){if(e!=="signalLost"&&e!=="freerun")return null;if(!t)return"\u6700\u7D42\u53D7\u4FE1\u306A\u3057";let o=Date.parse(t);return Number.isFinite(o)?`\u6700\u7D42\u53D7\u4FE1 ${Math.max(0,Math.floor((r-o)/1e3))} \u79D2\u524D`:"\u6700\u7D42\u53D7\u4FE1\u306A\u3057"}function Dt(){let e=S.value.host.state,t=e.receive.selectedDeviceId,[r,o]=k(Date.now()),[i,a]=k(!1),u=e.transport.status==="signalLost"||e.transport.status==="freerun";P(()=>{if(!u)return;o(Date.now());let m=window.setInterval(()=>o(Date.now()),1e3);return()=>window.clearInterval(m)},[u,e.transport.lastLtcReceivedAtUtc]);let d=vn(e.transport.status,e.transport.lastLtcReceivedAtUtc,r);return n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"TC \u5165\u51FA\u529B"}),n("span",{class:"tiny",children:"LTC \u53D7\u4FE1\u8A2D\u5B9A"})]}),n("div",{class:"status",children:[n("span",{children:[n("i",{class:"led"}),"\u5165\u529B ",n("b",{children:e.transport.locked?"\u63A5\u7D9A":"\u672A\u63A5\u7D9A"})]}),n("span",{children:[n("i",{class:"led"}),"LTC ",n("b",{children:e.transport.statusText}),d&&n("span",{class:"tiny muted",children:[" ",d]}),e.transport.signalErrorRatePercent!=null&&n("span",{class:"tiny muted",children:[" \u8AA4\u308A\u7387 ",e.transport.signalErrorRatePercent.toFixed(1),"%"]})]}),n("span",{children:["\u25CB \u51FA\u529B ",n("b",{children:"\u505C\u6B62"})]}),n("span",{children:[n("i",{class:"led"}),"\u9001\u51FA ",n("b",{children:e.transport.triggerMuted?"MUTE":"LIVE"})]})]}),n("div",{class:"settings",children:[n("div",{class:"set device-set",children:[n("span",{class:"tiny",children:"\u5165\u529B\u30C7\u30D0\u30A4\u30B9"}),n("select",{class:"field","aria-label":"\u5165\u529B\u30C7\u30D0\u30A4\u30B9",value:t??"",onChange:m=>gn(m.currentTarget.value),children:[n("option",{value:"",children:"\u9078\u629E\u3057\u3066\u304F\u3060\u3055\u3044"}),e.receive.devices.map(m=>n("option",{value:m.id,children:m.name}))]}),n(_n,{scanning:i,onClick:()=>void bn(a)})]}),n("div",{class:"set",children:[n("span",{class:"tiny",children:"\u63A5\u7D9A"}),n("span",{class:`field status-field ${t?"":"device-required"}`,children:t?e.transport.detailText:"\u5165\u529B\u30C7\u30D0\u30A4\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044"}),n("button",{class:"btn",disabled:!t,onClick:()=>Fe("ltc.reconnect",{deviceId:t}),children:"\u518D\u63A5\u7D9A"})]}),n("div",{class:"set",children:[n("span",{class:"tiny",children:"\u30D5\u30EA\u30FC\u30E9\u30F3"}),n("input",{class:"field","aria-label":"\u30D5\u30EA\u30FC\u30E9\u30F3\uFF08\u79D2\uFF09",type:"number",min:"0",step:"0.1",value:e.receive.freerunDurationSeconds,onChange:m=>Fe("receive.setFreerunDuration",{seconds:Number(m.currentTarget.value)})}),n("span",{class:"tiny unit",children:"\u79D2"})]})]}),n(hn,{})]})}function _n({scanning:e,onClick:t}){return n(F,{children:[n("button",{class:"btn rescan",disabled:e,"aria-busy":e,onClick:t,children:e?"\u30B9\u30AD\u30E3\u30F3\u4E2D\u2026":"\u518D\u30B9\u30AD\u30E3\u30F3"}),e&&n("div",{class:"scan-progress",role:"progressbar","aria-label":"\u30C7\u30D0\u30A4\u30B9\u3092\u30B9\u30AD\u30E3\u30F3\u4E2D",children:n("i",{})})]})}function hn(){let e=S.value.host.wave;if(!e)return n("div",{class:"wave",children:n("span",{class:"tiny",children:"\u6CE2\u5F62\u5F85\u6A5F\u4E2D"})});let t=Math.min(e.min.length,e.max.length),r=[];for(let o=0;o=0;o--)r.push(`${o/Math.max(1,t-1)*360},${15-(e.min[o]??0)*14}`);return n("div",{class:"wave",children:n("svg",{viewBox:"0 0 360 30",preserveAspectRatio:"none",children:n("polygon",{points:r.join(" ")})})})}var yn=e=>e==="24"?24:e==="25"?25:30;function xt(e,t,r=10){let o=e.split(":").map(p=>Number(p));if(o.length!==4||o.some(p=>!Number.isFinite(p)))return e;let i=yn(t),a=((o[0]*60+o[1])*60+o[2])*i+o[3]+r*i,u=24*3600*i-1,d=Math.min(a,u),m=p=>String(p).padStart(2,"0");return[m(Math.floor(d/(3600*i))),m(Math.floor(d/(60*i))%60),m(Math.floor(d/i)%60),m(d%i)].join(":")}var Ot=e=>{let t=e.split(/[:;]/).map(r=>Number(r));return t.length!==4||t.some(r=>!Number.isFinite(r))?null:((t[0]*60+t[1])*60+t[2])*100+t[3]};function He(e,t){if(t===null)return!0;let r=Ot(e),o=Ot(t);return r===null||o===null||o>r}function Rt({notice:e}){let t=S.value.host.state.generator,r=()=>({startTime:t.startTime,loopEndTime:t.loopEndTime??null,frameRate:t.frameRate,outputDeviceId:t.selectedOutputDeviceId??"",volume:t.volume}),[o,i]=k(r),a=$(null);P(()=>i(r()),[t.startTime,t.loopEndTime,t.frameRate,t.selectedOutputDeviceId,t.volume]);let u=s=>{let{startTime:g,loopEndTime:h,...A}=s;O("generator.configure",He(s.startTime,s.loopEndTime)?s:A).catch(l=>e(l.message))},d=(s,g)=>{let h={...o,[s]:g};i(h),u(h)},m=s=>{let g={...o,frameRate:s,startTime:J(o.startTime,s),loopEndTime:o.loopEndTime===null?null:J(o.loopEndTime,s)};i(g),u(g)},p=s=>d("loopEndTime",s?o.loopEndTime??xt(o.startTime,o.frameRate):null),c=(s,g=!1)=>{let h={...o,volume:s};i(h),a.current!==null&&window.clearTimeout(a.current),g?u(h):a.current=window.setTimeout(()=>u(h),100)};return n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"TC \u5165\u51FA\u529B"}),n("span",{class:"tiny",children:"\u5185\u90E8\u751F\u6210\u8A2D\u5B9A"})]}),n("div",{class:"status",children:[n("span",{children:["\u25CB \u5165\u529B ",n("b",{children:"\u505C\u6B62"})]}),n("span",{children:[n("i",{class:"led"}),"\u751F\u6210 ",n("b",{children:t.running?"\u518D\u751F\u4E2D":"\u505C\u6B62"})]}),n("span",{children:[n("i",{class:"led"}),"\u51FA\u529B ",n("b",{children:t.ltcOutputActive?"\u9001\u51FA\u4E2D":"\u505C\u6B62"})]}),n("span",{children:["\u97F3\u91CF ",n("b",{children:[Math.round(o.volume*100),"%"]})]})]}),n("div",{class:"settings generator-settings",children:[n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u958B\u59CB TC"}),n(B,{value:o.startTime,frameRate:o.frameRate,ariaLabel:"\u958B\u59CB\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",required:!0,onChange:s=>d("startTime",s)})]}),n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u30EB\u30FC\u30D7"}),n("span",{class:"loop-toggle",children:[n("input",{type:"checkbox",checked:o.loopEndTime!==null,onChange:s=>p(s.currentTarget.checked)}),n("span",{children:"\u958B\u59CB TC \u304B\u3089\u4E0B\u306E\u6642\u523B\u307E\u3067\u3092\u7E70\u308A\u8FD4\u3059"})]})]}),o.loopEndTime!==null&&n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u7D42\u4E86 TC"}),n(B,{value:o.loopEndTime,frameRate:o.frameRate,ariaLabel:"\u30EB\u30FC\u30D7\u7D42\u4E86\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9",required:!0,onChange:s=>d("loopEndTime",s)})]}),!He(o.startTime,o.loopEndTime)&&n("small",{class:"pending-note wide-control",role:"alert",children:"\u7D42\u4E86 TC \u3092\u958B\u59CB TC \u3088\u308A\u5F8C\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u76F4\u3059\u307E\u3067 TC \u306E\u5909\u66F4\u306F\u53CD\u6620\u3055\u308C\u307E\u305B\u3093"}),n("label",{children:[n("span",{class:"tiny",children:"FPS"}),n("select",{class:"field",value:o.frameRate,onChange:s=>m(s.currentTarget.value),children:["24","25","29.97df","30"].map(s=>n("option",{value:s,children:s}))})]}),n("label",{class:"wide-control",children:[n("span",{class:"tiny",children:"\u51FA\u529B\u30C7\u30D0\u30A4\u30B9"}),n("select",{class:"field",value:o.outputDeviceId,onChange:s=>d("outputDeviceId",s.currentTarget.value),children:[n("option",{value:"",children:"\u306A\u3057\uFF08\u51FA\u529B\u3057\u306A\u3044\uFF09"}),t.outputDevices.map(s=>n("option",{value:s.id,children:s.name}))]})]}),n("label",{class:"wide-control volume-control",children:[n("span",{class:"tiny",children:"\u97F3\u91CF"}),n("input",{type:"range",min:"0",max:"1",step:"0.01",value:o.volume,onInput:s=>c(Number(s.currentTarget.value)),onPointerUp:s=>c(Number(s.currentTarget.value),!0)})]})]}),t.running&&t.settingsPendingReset&&n("small",{class:"pending-note",children:"\u8A2D\u5B9A\u306F\u518D\u751F\u3057\u76F4\u3059\u3068\u53CD\u6620\u3055\u308C\u307E\u3059"}),n("div",{class:"generator-actions",children:[n("button",{class:`btn transport-toggle ${t.running?"danger":""}`,onClick:()=>void O(t.running?"generator.stop":"generator.start",{}).catch(s=>e(s.message)),children:t.running?"\u25A0 \u505C\u6B62":"\u25B6 \u518D\u751F"}),n("button",{class:"btn",onClick:()=>void O("generator.reset",{}).catch(s=>e(s.message)),children:"\u30EA\u30BB\u30C3\u30C8"})]})]})}function Tn(e){let t={};e.name.trim()||(t.name="\u540D\u524D\u306F\u5FC5\u9808\u3067\u3059"),e.ipAddress.trim()||(t.ipAddress="IP \u30A2\u30C9\u30EC\u30B9\u306F\u5FC5\u9808\u3067\u3059");let r=Number(e.port);return(!Number.isInteger(r)||r<1||r>65535)&&(t.port="1\u301C65535 \u3067\u5165\u529B\u3057\u3066\u304F\u3060\u3055\u3044"),t}var wn=e=>Object.fromEntries(Object.entries(e.fieldErrors??{}).filter(([t])=>t.startsWith("host.")).map(([t,r])=>[t.slice(5),r]));function Cn({host:e,close:t}){let[r,o]=k({name:e?.name??"",ipAddress:e?.ipAddress??"",port:String(e?.port??53e3)}),[i,a]=k({});P(()=>S.updateUi({modalOpen:!0}),[]);let u=(d,m)=>n("label",{class:"form-field",children:[n("span",{children:m}),n("input",{autofocus:d==="name",class:"field",value:r[d],onInput:p=>{let c=p.currentTarget.value;o(s=>({...s,[d]:c}))}}),n("small",{class:"field-error",children:i[d]??""})]});return n(X,{title:e?"\u30DB\u30B9\u30C8\u3092\u7DE8\u96C6":"\u30DB\u30B9\u30C8\u3092\u8FFD\u52A0",close:t,children:n("form",{class:"simple-form host-form",onSubmit:async d=>{d.preventDefault();let m=Tn(r);if(Object.keys(m).length){a(m);return}try{let p={name:r.name.trim(),ipAddress:r.ipAddress.trim(),port:Number(r.port),enabled:e?.enabled??!0};await O(e?"host.update":"host.add",e?{id:e.id,host:p}:{host:p}),t()}catch(p){a(wn(p))}},children:[u("name","\u540D\u524D"),u("ipAddress","IP \u30A2\u30C9\u30EC\u30B9"),u("port","\u30DD\u30FC\u30C8"),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:e?"\u66F4\u65B0":"\u8FFD\u52A0"})]})]})})}function kn(e,t,r){let o=t.filter(u=>u.targetHostIds.includes(e.id)).length,i=r.filter(u=>u.targetHostIds.includes(e.id)).length,a=[o?`\u30AD\u30E5\u30FC ${o} \u4EF6`:"",i?`\u30DD\u30F3\u51FA\u3057 ${i} \u4EF6`:""].filter(Boolean).join("\u3068");return a?`\u300C${e.name}\u300D\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F ${a}\u304C\u9001\u4FE1\u5148\u306B\u3057\u3066\u3044\u307E\u3059\u3002\u524A\u9664\u3059\u308B\u3068\u305D\u308C\u3089\u306F\u9001\u4FE1\u5148\u3092\u5931\u3044\u307E\u3059`:`\u300C${e.name}\u300D\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F`}function It({notice:e}){let t=S.value.host.state,[r,o]=k(null),[i,a]=k(null),u=()=>{o(null),a(null),S.updateUi({modalOpen:!1})},d=(m,p)=>void O(m,p).then(c=>{if(m==="host.ping"){let s=c??{};e(s.reachable===void 0?"\u758E\u901A\u78BA\u8A8D\u3092\u9001\u4FE1\u3057\u307E\u3057\u305F":s.reachable?`\u758E\u901A OK \xB7 ${s.latencyMs??"--"} ms`:"\u758E\u901A\u3067\u304D\u307E\u305B\u3093")}}).catch(c=>e(c.message));return n(F,{children:[n("div",{class:"panel-toolbar",children:[n("b",{children:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8"}),n("button",{class:"btn right",onClick:()=>o("new"),children:"\uFF0B \u8FFD\u52A0"})]}),n("div",{class:"host-list",children:t.hosts.map(m=>n("div",{class:`host-row ${m.enabled?"":"disabled"}`,children:[n("span",{class:`reach ${m.reachability}`}),n("b",{class:"host-name",children:m.name}),n("span",{class:"mono host-address",children:[m.ipAddress,":",m.port]}),n("div",{class:"host-actions",children:[n("label",{children:[n("input",{type:"checkbox",checked:m.enabled,onChange:p=>d("host.setEnabled",{id:m.id,enabled:p.currentTarget.checked})}),"\u6709\u52B9"]}),n("button",{class:"btn",onClick:()=>d("host.ping",{id:m.id}),children:"\u758E\u901A\u78BA\u8A8D"}),n("button",{class:"btn",onClick:()=>o(m),children:"\u7DE8\u96C6"}),n("button",{class:"btn danger-link",onClick:()=>{a(m),S.updateUi({modalOpen:!0})},children:"\u524A\u9664"})]})]}))}),r&&n(Cn,{host:r==="new"?void 0:r,close:u})," ",i&&n(q,{message:kn(i,t.cues,t.triggerPanel.buttons),close:u,confirm:()=>{d("host.remove",{id:i.id}),u()}})]})}var Sn=e=>[...e].sort((t,r)=>Date.parse(r.timestampUtc)-Date.parse(t.timestampUtc));function Mt(){let[e,t]=k(!1),r=Sn(S.value.host.state.logs),o=e?r.filter(u=>!u.success):r,i=$(null),a=$(!0);return mt(()=>{let u=i.current;u&&a.current&&(u.scrollTop=0)},[o.length]),n(F,{children:[n("div",{class:"panel-toolbar",children:[n("b",{children:"\u9001\u4FE1\u30ED\u30B0"}),n("span",{class:"tiny",children:"\u65B0\u3057\u3044\u9806"}),n("label",{class:"check tiny log-filter",children:[n("input",{type:"checkbox",checked:e,onChange:u=>t(u.currentTarget.checked)}),"\u5931\u6557\u306E\u307F"]}),n("button",{class:"btn right",onClick:()=>void O("logs.clear",{}),children:"\u30AF\u30EA\u30A2"})]}),n("div",{class:"dock log-dock",ref:i,onScroll:u=>{a.current=u.currentTarget.scrollTop<4},children:o.length?o.map(u=>n("div",{class:u.success?"log-success":"failure",children:[n("time",{children:new Date(u.timestampUtc).toLocaleTimeString("ja-JP")}),n("span",{children:u.message})]})):n("div",{class:"muted",children:e&&r.length?"\u5931\u6557\u3057\u305F\u9001\u4FE1\u306F\u3042\u308A\u307E\u305B\u3093":"\u9001\u4FE1\u30ED\u30B0\u306F\u3042\u308A\u307E\u305B\u3093"})})]})}function Pt({notice:e}){let t=S.value.host.state,[r,o]=k("logs");return n(F,{children:[n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"Cue-Sync \u9001\u4FE1\u8A2D\u5B9A"}),n("span",{class:"tiny mono",children:t.cueSync.oscAddress})]}),n("div",{class:"set",children:[n("span",{class:"tiny",children:"OSC\u30A2\u30C9\u30EC\u30B9"}),n("input",{class:"field mono","aria-label":"Cue-Sync OSC\u30A2\u30C9\u30EC\u30B9",value:t.cueSync.oscAddress,onChange:i=>void O("cueSync.configure",{oscAddress:i.currentTarget.value,targetHostIds:t.cueSync.targetHostIds})}),n("button",{class:"btn",onClick:()=>void O("cueSync.send",{}),children:"\u5358\u767A\u9001\u4FE1"})]}),n("div",{class:"hosts",children:[t.hosts.map(i=>n("label",{children:[n("input",{type:"checkbox",checked:t.cueSync.targetHostIds.includes(i.id),onChange:a=>void O("cueSync.configure",{oscAddress:t.cueSync.oscAddress,targetHostIds:a.currentTarget.checked?[...t.cueSync.targetHostIds,i.id]:t.cueSync.targetHostIds.filter(u=>u!==i.id)})}),n("span",{children:i.name})]})),n("span",{class:"tiny",children:[t.cueSync.targetHostIds.length," / ",t.hosts.length," \u6709\u52B9"]})]})]}),n("div",{class:"tab-panel",children:[n("div",{class:"tabs",children:[n("button",{class:`tab ${r==="logs"?"on":""}`,onClick:()=>o("logs"),children:"\u9001\u4FE1\u30ED\u30B0"}),n("button",{class:`tab ${r==="hosts"?"on":""}`,onClick:()=>o("hosts"),children:"\u30DB\u30B9\u30C8\u7BA1\u7406"})]}),r==="logs"?n(Mt,{}):n(It,{notice:e})]})]})}function Ft(e,t){let r=[];for(let o of t){let i=o.runtime.flashToken,a=e.get(o.id);e.set(o.id,i),a!==void 0&&i>a&&r.push(o.id)}return r}function An({cell:e,close:t,notice:r}){let o=e.button,[i,a]=k(o?.label??""),[u,d]=k(o?.oscAddress??"/"),[m,p]=k(o?.arguments.map(l=>`${l.type}:${l.value}`).join(` +`)??""),[c,s]=k(o?.targetHostIds??[]),[g,h]=k({}),A=S.value.host.state;return P(()=>S.updateUi({modalOpen:!0}),[]),n(X,{title:o?"\u30DD\u30F3\u51FA\u3057\u30DC\u30BF\u30F3\u3092\u7DE8\u96C6":"\u30DD\u30F3\u51FA\u3057\u30DC\u30BF\u30F3\u3092\u4F5C\u6210",close:t,children:n("form",{class:"cue-form",onSubmit:async l=>{l.preventDefault();let _={};i.trim()||(_.label="\u30E9\u30D9\u30EB\u306F\u5FC5\u9808\u3067\u3059"),u.startsWith("/")||(_.oscAddress="/ \u3067\u59CB\u3081\u3066\u304F\u3060\u3055\u3044");let f=ne(m);if(f.error&&(_.arguments=f.error),Object.keys(_).length){h(_);return}try{await O("triggerPanel.upsertButton",{button:{...o?{id:o.id}:{},row:e.row,column:e.column,label:i.trim(),oscAddress:u,arguments:f.value??[],targetHostIds:c}}),t()}catch(b){r(b.message)}},children:[n("label",{class:"form-field",children:[n("span",{children:"\u30E9\u30D9\u30EB"}),n("input",{autofocus:!0,class:"field",value:i,onInput:l=>a(l.currentTarget.value)}),n("small",{class:"field-error",children:g.label})]}),n("label",{class:"form-field",children:[n("span",{children:"OSC\u30A2\u30C9\u30EC\u30B9"}),n("input",{class:"field mono",value:u,onInput:l=>d(l.currentTarget.value)}),n("small",{class:"field-error",children:g.oscAddress})]}),n("label",{class:"form-field",children:[n("span",{children:"OSC\u5F15\u6570\uFF08type:value\u30011 \u884C 1 \u4EF6\uFF09"}),n("textarea",{class:"mono",value:m,onInput:l=>p(l.currentTarget.value),placeholder:`int32:1 float32:0.5 -string:GO`}),n("small",{class:"field-error",children:g.arguments})]}),n("fieldset",{children:[n("legend",{children:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8"}),A.hosts.map(c=>n("label",{children:[n("input",{type:"checkbox",checked:s.includes(c.id),onChange:_=>l(_.currentTarget.checked?[...s,c.id]:s.filter(f=>f!==c.id))}),n("span",{children:c.name})]}))]}),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:"\u4FDD\u5B58"})]})]})})}function Pt({notice:e}){let t=k.value.host.state,r=k.value.ui,[o,i]=C(!1),[a,u]=C(null),[d,m]=C(null),[p,s]=C(null),[l,g]=C({}),h=(b,w)=>{let y=t.triggerPanel.buttons.filter(T=>T.row>=b||T.column>=w).length;if(y>0){s({rows:b,columns:w,lost:y}),k.updateUi({modalOpen:!0});return}x("triggerPanel.configureGrid",{rows:b,columns:w})},A=()=>{u(null),s(null),m(null),k.updateUi({modalOpen:!1})},c=async b=>{try{let w=await x("triggerPanel.fire",{id:b.id});g(y=>({...y,[b.id]:w.sent===!1?w.reason??"\u9001\u4FE1\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F":"\u9001\u4FE1\u3057\u307E\u3057\u305F"}))}catch(w){g(y=>({...y,[b.id]:w.message}))}},_=Array.from({length:t.triggerPanel.rows*t.triggerPanel.columns},(b,w)=>{let y=Math.floor(w/t.triggerPanel.columns),T=w%t.triggerPanel.columns;return{row:y,column:T,button:t.triggerPanel.buttons.find(S=>S.row===y&&S.column===T)}}),f=b=>{let w=b.clientX,y=r.drawerWidth;b.currentTarget.setPointerCapture(b.pointerId);let T=R=>k.updateUi({drawerWidth:Math.min(900,Math.max(280,y-(R.clientX-w)))}),S=()=>{window.removeEventListener("pointermove",T),window.removeEventListener("pointerup",S)};window.addEventListener("pointermove",T),window.addEventListener("pointerup",S)};return n("section",{class:`osc-panel ${r.drawerOpen?"open":""}`,"aria-hidden":!r.drawerOpen,children:[n("i",{class:"osc-resize",onPointerDown:f,title:"\u30C9\u30E9\u30C3\u30B0\u3067\u5E45\u3092\u5909\u3048\u3089\u308C\u307E\u3059"}),n("div",{class:"dh",children:[n("h2",{children:"OSC \u30DD\u30F3\u51FA\u3057"}),n("button",{class:"btn close","aria-label":"OSC \u30DD\u30F3\u51FA\u3057\u3092\u9589\u3058\u308B",title:"\u9589\u3058\u308B\uFF08Esc\uFF09",onClick:()=>k.updateUi({drawerOpen:!1}),children:"\u2715"}),n("div",{class:"dh-row",children:[n("button",{class:`btn ${o?"":"primary"}`,onClick:()=>i(!1),children:"\u5B9F\u884C\u30E2\u30FC\u30C9"}),n("button",{class:`btn ${o?"primary":""}`,onClick:()=>i(!0),children:"\u7DE8\u96C6\u30E2\u30FC\u30C9"}),o&&n(H,{children:[n("label",{class:"grid-size",children:["\u884C ",n("input",{class:"field",type:"number",min:"1",max:"12",value:t.triggerPanel.rows,onChange:b=>h(Number(b.currentTarget.value),t.triggerPanel.columns)})]}),n("label",{class:"grid-size",children:["\u5217 ",n("input",{class:"field",type:"number",min:"1",max:"12",value:t.triggerPanel.columns,onChange:b=>h(t.triggerPanel.rows,Number(b.currentTarget.value))})]})]}),n("span",{class:"muted",children:[t.triggerPanel.rows," \u884C \xD7 ",t.triggerPanel.columns," \u5217"]})]})]}),n("div",{class:`grid ${o?"editing":""}`,style:{gridTemplateColumns:`repeat(${t.triggerPanel.columns},1fr)`,gridTemplateRows:`repeat(${t.triggerPanel.rows},1fr)`},children:_.map(b=>b.button?n("div",{class:"trigger-cell",children:[n("button",{class:"trig",onClick:()=>o?u(b):void c(b.button),children:b.button.label}),l[b.button.id]&&n("small",{class:l[b.button.id]==="\u9001\u4FE1\u3057\u307E\u3057\u305F"?"":"failure",children:l[b.button.id]}),o&&n("button",{class:"cell-remove","aria-label":`${b.button.label}\u3092\u524A\u9664`,onClick:()=>{m(b.button),k.updateUi({modalOpen:!0})},children:"\xD7"})]}):n("button",{class:"empty-cell","aria-label":`${b.row+1}\u884C${b.column+1}\u5217\u306B\u30DC\u30BF\u30F3\u3092\u4F5C\u6210`,disabled:!o,onClick:()=>u(b),children:o?"\uFF0B":""}))}),a&&n(Tn,{cell:a,close:A,notice:e})," ",d&&n(J,{message:`\u300C${d.label}\u300D\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F`,close:A,confirm:()=>{x("triggerPanel.removeButton",{id:d.id}),A()}}),p&&n(J,{message:`${p.rows} \u884C \xD7 ${p.columns} \u5217\u306B\u7E2E\u5C0F\u3059\u308B\u3068\u3001\u7BC4\u56F2\u5916\u306E\u30DC\u30BF\u30F3 ${p.lost} \u500B\u304C\u6D88\u3048\u307E\u3059\u3002\u7D9A\u3051\u307E\u3059\u304B\uFF1F`,confirmLabel:"\u7E2E\u5C0F",close:A,confirm:()=>{x("triggerPanel.configureGrid",{rows:p.rows,columns:p.columns}),A()}})]})}var Ft=e=>e.hosts.filter(t=>t.enabled&&e.cueSync.targetHostIds.includes(t.id)).length;function Cn(e,t){e?.sentCount===0&&t("\u9001\u4FE1\u5148\u30DB\u30B9\u30C8\u304C\u3042\u308A\u307E\u305B\u3093")}function kn(e,t,r){if(Ft(e)===0){t("Cue-Sync \u306E\u9001\u4FE1\u5148\u30DB\u30B9\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044");return}x("cueSync.send",{}).then(()=>r()).catch(o=>t(o.message))}var Sn=new Map,Y=new Map,An=e=>e.split(/[\\/]/).pop()||e,En=e=>e==null||!Number.isFinite(e)?"-- dBFS":`${e>=0?"":"\u2212"}${Math.abs(e).toFixed(1)} dBFS`,Ht=0;function Dn({current:e,frameRate:t,apply:r}){let[o,i]=C(e),[a,u]=C(e);a!==e&&(u(e),i(e));let d=o!==e,m=$({draft:o,current:e});return m.current={draft:o,current:e},n("span",{class:"offset-editor",children:[n(B,{class:"monitor-offset",value:o,frameRate:t,signed:!0,ariaLabel:"\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9\u30AA\u30D5\u30BB\u30C3\u30C8",onChange:i}),n("button",{class:`btn mini ${d?"primary":""}`,disabled:!d,onClick:()=>{let{draft:s,current:l}=m.current;s!==l&&r(s)},children:"\u78BA\u5B9A"}),d&&n("span",{class:"tiny offset-pending",children:"\u672A\u78BA\u5B9A"})]})}function Ut(){let[,e]=C(0),[t,r]=C(null),[o,i]=C(!1),[a,u]=C(""),[d,m]=C(0),p=k.value,s=p.host.state,l=p.host.clock??s?.currentClock;P(()=>k.subscribe(()=>{for(let v of Mt(Sn,k.value.host.state?.cues??[])){let D=(Y.get(v)??0)+1;Y.set(v,D),window.setTimeout(()=>{Y.get(v)===D&&(Y.delete(v),e(E=>E+1))},700)}e(v=>v+1)}),[]),P(()=>k.updateUi({modalOpen:t!==null}),[t]),P(()=>{if(!a)return;let v=window.setTimeout(()=>u(""),4e3);return()=>window.clearTimeout(v)},[a]),P(()=>{let v=()=>Q({protocolVersion:1,type:"viewport",waveformWidth:360,devicePixelRatio:window.devicePixelRatio,visible:document.visibilityState==="visible"});return v(),window.addEventListener("resize",v),document.addEventListener("visibilitychange",v),()=>{window.removeEventListener("resize",v),document.removeEventListener("visibilitychange",v)}},[]);let g=()=>s?.cues.filter(v=>p.ui.selectedCueIds.has(v.id))??[],h=()=>{g().length&&r(g().length===1?"edit":"batch")},A=()=>{g().length&&r("remove")},c=(v,D={})=>void x(v,D).catch(E=>u(E.message)),_=()=>m(v=>v+1),f=()=>{s&&kn(s,u,_)},b=v=>void x("mode.set",{mode:v}).then(D=>{v==="ltc"&&D?.ltcStarted===!1&&u("\u5165\u529B\u30C7\u30D0\u30A4\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044")}).catch(D=>u(D.message));if(P(()=>{let v=D=>{let E=_t(D,p.ui.modalOpen);if(E)if(D.preventDefault(),E==="closeDrawer")k.updateUi({drawerOpen:!1});else if(E==="editCue")h();else if(E==="deleteCue")A();else if(E==="selectPrevious"||E==="selectNext"){if(!s)return;let F=Math.max(0,s.cues.findIndex(j=>j.id===p.ui.focusedCueId)),L=s.cues[Math.max(0,Math.min(s.cues.length-1,F+(E==="selectNext"?1:-1)))];L&&k.updateUi({focusedCueId:L.id,selectedCueIds:new Set([L.id])})}else c({projectNew:"project.new",projectOpen:"project.open",projectSave:"project.save",projectSaveAs:"project.saveAs",undo:"app.undo",redo:"app.redo"}[E])};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)}),!s||!l)return n("main",{class:"app loading",children:"HOST \u306B\u63A5\u7D9A\u3057\u3066\u3044\u307E\u3059\u2026"});let w=(v,D)=>{let E=new Set(p.ui.selectedCueIds);if(D.metaKey||D.ctrlKey)E.has(v)?E.delete(v):E.add(v);else if(D.shiftKey&&p.ui.anchorCueId){let F=s.cues.findIndex(j=>j.id===p.ui.anchorCueId),L=s.cues.findIndex(j=>j.id===v);E=new Set(s.cues.slice(Math.min(F,L),Math.max(F,L)+1).map(j=>j.id))}else E=new Set([v]);k.updateUi({selectedCueIds:E,focusedCueId:v,anchorCueId:v})},y=v=>{i(!1),c(v)},T=()=>r(null),S=(v,D)=>{let E=D.clientX,F=[...p.ui.cueColumnWidths];D.currentTarget.setPointerCapture(D.pointerId);let L=Bt=>{let je=Bt.clientX-E,Vt=Math.max(38,(F[v]??38)+je),Kt=Math.max(50,(F[v+1]??50)-je),be=[...F];be[v]=Vt,be[v+1]=Kt,k.updateUi({cueColumnWidths:be})},j=()=>{window.removeEventListener("pointermove",L),window.removeEventListener("pointerup",j)};window.addEventListener("pointermove",L),window.addEventListener("pointerup",j)},R=s.transport.triggerMuted?ft(s.transport.autoUnmuteAtUtc,Date.now()):"",V={"--cue-cols":p.ui.cueColumnWidths.map(v=>`${v}px`).join(" ")};return n(H,{children:[n("div",{class:`split ${p.ui.drawerOpen?"osc-open":""}`,style:{"--osc-width":`${p.ui.drawerWidth}px`},children:[n("main",{class:"app",children:[n("header",{children:[n("b",{children:"TIMEcode BRIDGE 3"}),n("button",{class:"project-button",onClick:()=>i(!o),children:[s.project.displayName,"\u3000\u25CF ",s.project.dirty?"\u672A\u4FDD\u5B58":"\u4FDD\u5B58\u6E08\u307F"]}),o&&n("div",{class:"project-menu",children:[n("button",{onClick:()=>y("project.new"),children:"\u65B0\u898F"}),n("button",{onClick:()=>y("project.open"),children:"\u958B\u304F\u2026"}),n("button",{onClick:()=>y("project.save"),children:"\u4FDD\u5B58"}),n("button",{onClick:()=>y("project.saveAs"),children:"\u540D\u524D\u3092\u4ED8\u3051\u3066\u4FDD\u5B58\u2026"}),s.project.recentFiles.length>0&&n(H,{children:[n("div",{class:"project-menu-sep",children:"\u6700\u8FD1\u4F7F\u3063\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8"}),s.project.recentFiles.map(v=>n("button",{class:"recent",title:v,onClick:()=>{i(!1),c("project.open",{path:v})},children:An(v)}))]})]}),n("button",{class:"btn","aria-label":"\u53D6\u308A\u6D88\u3059",disabled:!s.project.canUndo,onClick:()=>c("app.undo"),children:"\u21B6"}),n("button",{class:"btn","aria-label":"\u3084\u308A\u76F4\u3059",disabled:!s.project.canRedo,onClick:()=>c("app.redo"),children:"\u21B7"}),n("span",{class:"right muted",children:[n("i",{class:"led"}),"ENGINE ONLINE\u3000 ",l.frameRate," FPS / ",l.dropFrame?"DROP":"NON-DROP"]})]}),n("section",{class:"monitor",children:[n("div",{children:[n("span",{class:"tiny",children:[n("i",{class:"led"}),"\u53D7\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9 / OFFSET\u9069\u7528\u5F8C"]}),n("div",{class:"tc",children:l.display}),n("span",{class:"tiny monitor-offset-line",children:["RAW\u3000",n("span",{class:"mono",children:l.raw}),"\u3000 OFFSET\u3000",n(Dn,{current:s.receive.offset,frameRate:l.frameRate,apply:v=>c("receive.setOffset",{value:v})}),"\u3000 ",s.transport.locked?"LOCK":"UNLOCK"," / ",En(p.host.wave?.levelDbfs)]})]}),n("div",{class:"next",children:[n("span",{class:"tiny",children:["NEXT CUE ",n("b",{class:"right",children:["T\u2212 ",s.nextCue?l.framesUntilNextCue??"--":"--","f"]})]}),n("div",{class:"next-main",children:[n("strong",{children:s.nextCue?.effectiveTriggerTime??"--:--:--:--"}),n("b",{children:s.nextCue?.name??"\u6B21\u306E\u30AD\u30E5\u30FC\u306F\u3042\u308A\u307E\u305B\u3093"})]}),n("span",{class:"tiny mono",children:s.nextCue?s.cues.find(v=>v.id===s.nextCue?.id)?.oscAddress:"\u2014"})]}),n("div",{class:"majorbox",children:[n("button",{class:`major ${d===0?"":d%2?"flash-a":"flash-b"}`,onClick:f,children:["CUE SYNC",n("small",{children:[Ft(s),"\u30DB\u30B9\u30C8\u3078\u9001\u4FE1"]})]}),n("button",{class:`major ${s.transport.triggerMuted?"on":""}`,onClick:()=>c("mute.set",{muted:!s.transport.triggerMuted}),children:[s.transport.triggerMuted?"MUTE":"LIVE",R&&n("b",{class:"mute-countdown",children:R}),n("small",{children:R?"\u5F8C\u306B\u81EA\u52D5\u89E3\u9664":`\u30AD\u30E5\u30FC\u9001\u51FA ${s.transport.triggerMuted?"\u505C\u6B62":"\u6709\u52B9"}`})]})]})]}),n("section",{class:"work",children:[n("section",{class:"cues",style:V,children:[n("div",{class:"tool",children:[n("h2",{children:"\u30AD\u30E5\u30FC\u30EA\u30B9\u30C8"}),n("label",{class:"judge-control muted",title:"\u3053\u306E\u5E45(\u30D5\u30EC\u30FC\u30E0)\u4EE5\u5185\u306E\u524D\u9032\u3084\u5F8C\u9000\u306F\u901A\u5E38\u518D\u751F\u30FB\u30B8\u30C3\u30BF\u30FC\u3068\u3057\u3066\u6271\u3044\u3001\u53D6\u308A\u3053\u307C\u3057\u305F\u9593\u306E\u30AD\u30E5\u30FC\u3082\u767A\u706B\u3057\u307E\u3059\u3002\u8D85\u3048\u3066\u98DB\u3093\u3060\u3089\u982D\u51FA\u3057(\u30B7\u30FC\u30AF)\u3084\u5DFB\u304D\u623B\u3057\u3068\u3057\u3066\u9014\u4E2D\u306E\u30AD\u30E5\u30FC\u306F\u767A\u706B\u3057\u307E\u305B\u3093",children:[n("span",{children:"\u30B8\u30E3\u30F3\u30D7\u5224\u5B9A"}),n("span",{"aria-hidden":"true",children:"\xB1"}),n("input",{class:"inline-input judge-input",type:"number",value:s.receive.triggerWindowFrames,min:"0",step:"1","aria-label":"\u30B8\u30E3\u30F3\u30D7\u5224\u5B9A\uFF08\u30D5\u30EC\u30FC\u30E0\uFF09",onChange:v=>c("receive.setTriggerWindow",{frames:Number(v.currentTarget.value)})}),n("span",{"aria-hidden":"true",children:"f"})]}),n("button",{class:"btn",onClick:()=>r("add"),children:"\uFF0B \u8FFD\u52A0"}),n("button",{class:"btn",disabled:!g().length,onClick:h,children:g().length>1?"\u4E00\u62EC\u7DE8\u96C6":"\u7DE8\u96C6"}),n("button",{class:"btn",disabled:g().length!==1,onClick:()=>c("cue.duplicate",{id:g()[0].id}),children:"\u8907\u88FD"}),n("button",{class:"btn",disabled:g().length!==1,onClick:()=>r("duplicate"),children:"\u9023\u7D9A\u8907\u88FD"}),n("button",{class:"btn",disabled:!g().length,onClick:A,children:"\u524A\u9664"}),n("button",{class:`btn right auto-mute-toggle ${s.transport.autoMuteEnabled?"on":""}`,"aria-pressed":s.transport.autoMuteEnabled,title:"\u30AD\u30E5\u30FC\u767A\u706B\u5F8C\u306E\u81EA\u52D5\u30DF\u30E5\u30FC\u30C8\u3092\u307E\u3068\u3081\u3066\u5165\u5207\u3057\u307E\u3059\u3002\u5207\u308B\u3068\u3001\u30AD\u30E5\u30FC\u3054\u3068\u306E\u300C\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8\u300D\u3082\u50CD\u304D\u307E\u305B\u3093",onClick:()=>c("autoMute.setEnabled",{enabled:!s.transport.autoMuteEnabled}),children:["\u30AA\u30FC\u30C8\u30DF\u30E5\u30FC\u30C8 ",s.transport.autoMuteEnabled?"ON":"OFF"]}),n("button",{class:"btn",onClick:()=>c("cue.sortByTime"),children:"\u6642\u9593\u9806"})]}),n("div",{class:"cols",children:["\u6709\u52B9","\u30C8\u30EA\u30AC\u30FC\u6642\u9593","\u30AD\u30E5\u30FC\u540D","OSC\u30A2\u30C9\u30EC\u30B9","\u624B\u52D5"].map((v,D)=>n("span",{children:[v,D<4&&n("i",{class:"resize-handle",onPointerDown:E=>S(D,E)})]}))}),n("div",{class:"list",children:s.cues.map(v=>n("div",{class:`row ${v.id===l.nextCueId?"current":""} ${v.enabled?"":"disabled"} ${p.ui.selectedCueIds.has(v.id)?"selected":""} ${Y.has(v.id)?Y.get(v.id)%2?"fired-a":"fired-b":""}`,tabIndex:0,"aria-label":`${v.name} ${v.effectiveTriggerTime}`,onPointerDown:()=>{Ht=Date.now()},onFocus:()=>{Date.now()-Ht<300||p.ui.selectedCueIds.has(v.id)||k.updateUi({selectedCueIds:new Set([v.id]),focusedCueId:v.id,anchorCueId:v.id})},onClick:D=>w(v.id,D),onDblClick:D=>{D.target.closest("button,input")||h()},children:[n("span",{children:n("input",{type:"checkbox","aria-label":`${v.name}\u3092${v.enabled?"\u7121\u52B9":"\u6709\u52B9"}\u306B\u3059\u308B`,checked:v.enabled,onChange:D=>c("cue.setEnabled",{id:v.id,enabled:D.currentTarget.checked})})}),n("span",{class:"mono",children:v.effectiveTriggerTime}),n("span",{children:[v.name,s.transport.autoMutedCueId===v.id&&n("b",{class:"mute-tag",children:["MUTE",R?` ${R}`:""]})]}),n("span",{class:"mono",children:v.oscAddress}),n("button",{class:"btn fire","aria-label":`${v.name}\u3092\u767A\u706B`,onClick:D=>{D.stopPropagation(),x("cue.fire",{id:v.id}).then(E=>Cn(E,u)).catch(E=>u(E.message))},children:"\u25B6"})]},v.id))}),n("div",{class:"footcue",children:[n("span",{class:"tag",children:"NEXT"}),n("b",{class:"mono",children:s.nextCue?.effectiveTriggerTime}),n("span",{children:s.nextCue?.name})]})]}),n("aside",{class:"side",children:[n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"\u52D5\u4F5C\u30E2\u30FC\u30C9"}),n("span",{class:"tiny",children:s.transport.statusText})]}),n("div",{class:"mode",children:[n("button",{class:s.mode==="ltc"?"active":"",onClick:()=>b("ltc"),children:"LTC\u53D7\u4FE1"}),n("button",{class:s.mode==="generate"?"active":"",onClick:()=>b("generate"),children:"\u5185\u90E8\u751F\u6210"})]})]}),s.mode==="ltc"?n(Et,{}):n(xt,{notice:u}),n(It,{notice:u})]})]}),n("footer",{children:[n("span",{children:[n("i",{class:"led"}),s.mode==="ltc"?"LTC INPUT":"LTC GENERATOR"," ",s.transport.locked?"LOCK":"UNLOCK",s.transport.detailText?` \xB7 ${s.transport.detailText}`:""]}),n("button",{class:"btn right","aria-pressed":p.ui.drawerOpen,title:"OSC \u30DD\u30F3\u51FA\u3057\u30D1\u30CD\u30EB\u3092\u53F3\u306B\u958B\u9589\u3057\u307E\u3059",onClick:()=>k.updateUi({drawerOpen:!p.ui.drawerOpen}),children:p.ui.drawerOpen?"\u25E7 OSC \u30DD\u30F3\u51FA\u3057\u3092\u9589\u3058\u308B":"\u25E8 OSC \u30DD\u30F3\u51FA\u3057\u3092\u958B\u304F"})]}),a&&n("div",{class:"toast",onClick:()=>u(""),children:a})]}),n(Pt,{notice:u})]}),p.ui.optionsOpen&&n(At,{notice:u,close:()=>k.updateUi({optionsOpen:!1,modalOpen:!1})})," ",t==="add"&&n(Pe,{frameRate:l.frameRate,hosts:s.hosts,close:T,done:T})," ",t==="edit"&&n(Pe,{cue:g()[0],frameRate:l.frameRate,hosts:s.hosts,close:T,done:T})," ",t==="batch"&&n(St,{ids:g().map(v=>v.id),hosts:s.hosts,frameRate:l.frameRate,close:T,done:T,notice:u})," ",t==="duplicate"&&n(kt,{cue:g()[0],close:T,done:T})," ",t==="remove"&&n(J,{message:`\u9078\u629E\u3057\u305F ${g().length} \u4EF6\u306E\u30AD\u30E5\u30FC\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F`,close:T,confirm:()=>{c("cue.remove",{ids:g().map(v=>v.id)}),T()}})]})}var q=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),N=e=>typeof e=="number"&&Number.isFinite(e);function Nt(e){return q(e)&&typeof e.raw=="string"&&typeof e.display=="string"&&N(e.totalFrames)&&["24","25","29.97df","30"].includes(String(e.frameRate))&&typeof e.dropFrame=="boolean"&&N(e.receivedAtMonotonicMs)}function xn(e){return!q(e)||e.protocolVersion!==1||typeof e.type!="string"?!1:e.type==="clock"?N(e.seq)&&Nt(e.clock):e.type==="wave"?N(e.seq)&&q(e.wave)&&N(e.wave.sampleRate)&&N(e.wave.windowMs)&&Array.isArray(e.wave.min)&&Array.isArray(e.wave.max)&&e.wave.min.every(N)&&e.wave.max.every(N)&&(e.wave.levelDbfs===null||N(e.wave.levelDbfs)):e.type==="snapshot"?N(e.revision)&&q(e.state)&&typeof e.state.sessionId=="string"&&Array.isArray(e.state.cues)&&q(e.state.transport)&&Nt(e.state.currentClock):e.type==="patch"?N(e.revision)&&N(e.baseRevision)&&q(e.changes):e.type==="result"?typeof e.requestId=="string"&&typeof e.ok=="boolean"&&(e.ok||q(e.error)):!1}function $t(e){try{let t=typeof e=="string"?JSON.parse(e):e;return xn(t)?t:null}catch{return null}}var Fe=(e,t,r,o)=>({id:e,name:t,memo:"",triggerTime:r,effectiveTriggerTime:r,frameRate:"30",oscAddress:o,additionalOscAddresses:[],arguments:[],targetHostIds:["qlab"],enabled:!0,sendTriggerTimeAsSeconds:!1,sendTimecode:null,triggerOffset:null,autoMuteOnFire:!1,autoUnmuteAfter:null,runtime:{lastTriggeredAtUtc:null,flashToken:0}});function On(){return{sessionId:"fake-session",project:{displayName:"show_A.tcb3",filePath:null,dirty:!1,canUndo:!1,canRedo:!1,recentFiles:[]},mode:"ltc",transport:{status:"receiving",statusText:"\u53D7\u4FE1\u4E2D",detailText:"CH 1 \xB7 48 kHz",signalErrorRatePercent:0,locked:!0,triggerMuted:!1,autoMuteEnabled:!1,autoMuteOnManualTrigger:!1,autoMutedCueId:null,autoUnmuteAtUtc:null,lastLtcReceivedAtUtc:null},receive:{selectedDeviceId:"in",devices:[{id:"in",name:"UR44 \u2014 Input 1 / 2",loopback:!1}],offset:"+00:00:00:08",triggerWindowFrames:3,freerunDurationSeconds:1},generator:{running:!1,startTime:"01:00:00:00",loopEndTime:null,frameRate:"30",selectedOutputDeviceId:"out",outputDevices:[{id:"out",name:"UR44 \u2014 Output 1 / 2",loopback:!1}],volume:.4,ltcOutputActive:!1,settingsPendingReset:!1},currentClock:{raw:"01:24:16:00",display:"01:24:16:08",totalFrames:151688,frameRate:"30",dropFrame:!1,receivedAtMonotonicMs:0,nextCueId:"cue-2",framesUntilNextCue:112},nextCue:{id:"cue-2",name:"\u30BF\u30A4\u30C8\u30EB OUT",triggerTime:"01:24:20:00",effectiveTriggerTime:"01:24:20:00",framesUntil:112},cues:[Fe("cue-1","\u672C\u7DE8 IN","01:23:40:00","/qlab/go"),Fe("cue-2","\u30BF\u30A4\u30C8\u30EB OUT","01:24:20:00","/video/title/out")],hosts:[{id:"qlab",name:"QLab \u2014 Main",ipAddress:"192.168.1.20",port:53e3,enabled:!0,reachability:"reachable"},{id:"reso",name:"Resolume \u2014 Stage",ipAddress:"192.168.1.31",port:7e3,enabled:!0,reachability:"reachable"}],cueSync:{oscAddress:"/cuesync",targetHostIds:["qlab","reso"]},triggerPanel:{rows:4,columns:4,buttons:[{id:"go",row:0,column:0,label:"GO",oscAddress:"/go",arguments:[],targetHostIds:["qlab"]}]},logs:[{id:"log-1",timestampUtc:new Date(Date.now()-1e3).toISOString(),message:"fake-host \u3092\u958B\u59CB\u3057\u307E\u3057\u305F",success:!0}],uiCapabilities:{supportsNativeOpenDialog:!1,supportsNativeSaveDialog:!1,platform:"macos"}}}function jt(){let e=On(),t=1,r=0,o=10,i=!0,a=null,u=p=>queueMicrotask(()=>i&&window.tcb.receive(JSON.stringify(p))),d=p=>{let{logsAppend:s,logsReset:l,...g}=p;e={...e,...g},l&&(e.logs=l),s&&(e.logs=[...e.logs,...s]),u({protocolVersion:1,type:"patch",baseRevision:t,revision:++t,changes:p})},m=p=>{let s=JSON.parse(p);if(s.type==="ready"||s.type==="resync"){u({protocolVersion:1,type:"snapshot",revision:t,state:e}),a===null&&(a=window.setInterval(()=>u({protocolVersion:1,type:"clock",seq:++r,clock:{...e.currentClock,receivedAtMonotonicMs:performance.now()}}),100));return}if(s.type!=="command")return;let l=s.args,g=c=>u({protocolVersion:1,type:"result",requestId:s.requestId,ok:!0,data:c,revision:t}),h=c=>u({protocolVersion:1,type:"result",requestId:s.requestId,ok:!1,error:{code:"validation",message:"\u5165\u529B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044",retryable:!1,fieldErrors:c}}),A=(c,_=!0)=>d({logsAppend:[{id:`log-${++o}`,timestampUtc:new Date().toISOString(),message:c,success:_}]});if(s.command==="mode.set"){let c=l.mode,_=c==="ltc"&&!!e.receive.selectedDeviceId;d({mode:c,transport:{...e.transport,status:_?"receiving":"stopped",statusText:_?"\u53D7\u4FE1\u4E2D":c==="ltc"?"\u505C\u6B62\u4E2D":"\u751F\u6210\u5F85\u6A5F",locked:_}}),g({ltcStarted:_});return}if(s.command==="ltc.stop"){d({transport:{...e.transport,status:"stopped",statusText:"\u505C\u6B62",locked:!1}}),g();return}if(s.command==="receive.selectDevice"&&!(l.deviceId??"")){d({receive:{...e.receive,selectedDeviceId:null},transport:{...e.transport,status:"stopped",statusText:"\u505C\u6B62\u4E2D",locked:!1}}),g();return}if(s.command==="receive.selectDevice"){d({receive:{...e.receive,selectedDeviceId:l.deviceId},transport:{...e.transport,status:"receiving",statusText:"\u53D7\u4FE1\u4E2D",locked:!0}}),g();return}if(s.command==="ltc.start"||s.command==="ltc.reconnect"){d({receive:{...e.receive,selectedDeviceId:l.deviceId??e.receive.selectedDeviceId},transport:{...e.transport,status:"receiving",statusText:"\u53D7\u4FE1\u4E2D",locked:!0}}),g();return}if(s.command==="receive.setFreerunDuration"){d({receive:{...e.receive,freerunDurationSeconds:Number(l.seconds)}}),g();return}if(s.command==="audio.refreshDevices"){d(l.direction==="capture"?{receive:{...e.receive}}:{generator:{...e.generator}}),g();return}if(s.command==="generator.configure"){d({generator:{...e.generator,startTime:l.startTime,loopEndTime:l.loopEndTime??null,frameRate:l.frameRate,selectedOutputDeviceId:l.outputDeviceId||null,volume:l.volume,settingsPendingReset:e.generator.running}}),g();return}if(s.command==="generator.start"||s.command==="generator.stop"){let c=s.command.endsWith("start");d({generator:{...e.generator,running:c,ltcOutputActive:c&&!!e.generator.selectedOutputDeviceId,settingsPendingReset:!1},transport:{...e.transport,status:c?"receiving":"stopped",statusText:c?"\u751F\u6210\u4E2D":"\u505C\u6B62"}}),g();return}if(s.command==="generator.reset"){d({generator:{...e.generator,running:!1,ltcOutputActive:!1,settingsPendingReset:!1},currentClock:{...e.currentClock,raw:e.generator.startTime,display:e.generator.startTime}}),g();return}if(s.command==="host.add"||s.command==="host.update"){let c=l.host,_={...c.name?{}:{"host.name":"\u5FC5\u9808"},...c.ipAddress?{}:{"host.ipAddress":"\u5FC5\u9808"},...c.port>=1&&c.port<=65535?{}:{"host.port":"1\u301C65535"}};if(Object.keys(_).length){h(_);return}let f=s.command==="host.add"?`host-${++o}`:String(l.id),b={id:f,name:c.name,ipAddress:c.ipAddress,port:c.port,enabled:c.enabled??!0,reachability:"unknown"};d({hosts:s.command==="host.add"?[...e.hosts,b]:e.hosts.map(w=>w.id===f?b:w)}),g({id:f});return}if(s.command==="host.remove"){d({hosts:e.hosts.filter(c=>c.id!==l.id)}),g();return}if(s.command==="host.setEnabled"){d({hosts:e.hosts.map(c=>c.id===l.id?{...c,enabled:!!l.enabled}:c)}),g();return}if(s.command==="host.ping"){d({hosts:e.hosts.map(c=>c.id===l.id?{...c,reachability:"reachable"}:c)}),g({reachable:!0,latencyMs:2});return}if(s.command==="triggerPanel.configureGrid"){d({triggerPanel:{...e.triggerPanel,rows:Number(l.rows),columns:Number(l.columns),buttons:e.triggerPanel.buttons.filter(c=>c.rowf.id!==c),_]}}),g({id:c});return}if(s.command==="triggerPanel.removeButton"){d({triggerPanel:{...e.triggerPanel,buttons:e.triggerPanel.buttons.filter(c=>c.id!==l.id)}}),g();return}if(s.command==="triggerPanel.fire"){A(`\u30DD\u30F3\u51FA\u3057: ${e.triggerPanel.buttons.find(c=>c.id===l.id)?.label??l.id}`),g({sent:!0,sentCount:1,skippedHostIds:[],reason:"None"});return}if(s.command==="logs.clear"){d({logsReset:[]}),g();return}if(s.command==="cueSync.configure"){d({cueSync:{...e.cueSync,...l}}),g();return}if(s.command==="cueSync.send"){A("Cue-Sync \u3092\u9001\u4FE1\u3057\u307E\u3057\u305F"),g({sent:!0,sentCount:2,skippedHostIds:[]});return}if(s.command==="cue.add"||s.command==="cue.update"){let c=l.cue,_={...ee(c.frameRate??"30"),...c,additionalOscAddresses:(c.additionalOscAddresses??[]).join(` -`),argumentsText:(c.arguments??[]).map(y=>`${y.type}:${y.value}`).join(` -`),sendTimecode:c.sendTimecode??"",triggerOffset:c.triggerOffset??"",autoUnmuteAfter:c.autoUnmuteAfter??""},f=me(_);if(!f.draft){h(Object.fromEntries(Object.entries(f.errors).map(([y,T])=>[`cue.${y}`,T])));return}let b=s.command==="cue.add"?`cue-${++o}`:String(l.id),w={...Fe(b,f.draft.name,f.draft.triggerTime,f.draft.oscAddress),...f.draft,id:b,effectiveTriggerTime:f.draft.triggerTime};d({cues:s.command==="cue.add"?[...e.cues,w]:e.cues.map(y=>y.id===b?w:y),project:{...e.project,dirty:!0,canUndo:!0}}),g({id:b});return}if(s.command==="cue.remove"){d({cues:e.cues.filter(c=>!l.ids.includes(c.id))}),g();return}if(s.command==="cue.duplicate"){let c=e.cues.find(f=>f.id===l.id),_=[];if(c){let f=Array.from({length:Number(l.count??1)},(b,w)=>{let y=`cue-${++o}`;return _.push(y),{...c,id:y,name:`${c.name} (\u30B3\u30D4\u30FC${w?` ${w+1}`:""})`}});d({cues:[...e.cues,...f]})}g({ids:_});return}if(s.command==="cue.batchUpdate"){d({cues:e.cues.map(c=>l.ids.includes(c.id)?{...c,...l.changes}:c)}),g({updated:l.ids.length,offsetSkipped:0});return}if(s.command.startsWith("project.")){d({...s.command==="project.new"?{cues:[]}:{},project:{...e.project,displayName:s.command==="project.new"?"\u540D\u79F0\u672A\u8A2D\u5B9A.tcb3":e.project.displayName,dirty:!1,canUndo:!1,canRedo:!1}}),g({cancelled:!1});return}if(s.command==="app.undo"||s.command==="app.redo"){d({project:{...e.project,canUndo:s.command==="app.redo",canRedo:s.command==="app.undo"}}),g();return}s.command==="mute.set"&&d({transport:{...e.transport,triggerMuted:!!l.muted}}),s.command==="cue.setEnabled"&&d({cues:e.cues.map(c=>c.id===l.id?{...c,enabled:!!l.enabled}:c)}),g()};return window.invokeCSharpAction=m,{dispose:()=>{i=!1,a!==null&&window.clearInterval(a),window.invokeCSharpAction===m&&delete window.invokeCSharpAction}}}var Ue=!1,Ne=!1;function Rn(){Ne=!0,!Ue&&(Ue=!0,requestAnimationFrame(()=>{Ue=!1,Ne&&(Ne=!1,k.notify())}))}var $e=()=>Q({protocolVersion:1,type:"ready",clientVersion:"3.0.0",capabilities:["clock-latest-only","wave-minmax","m1","m2a","m2b","m3"]});function Lt(e=800){let t=!1,r=null,o=window.setTimeout(()=>{t||window.invokeCSharpAction||(r=jt(),$e())},e);return window.tcb={receive:i=>{let a=$t(i);if(!a)return;if(a.type==="result"){bt(a);return}gt(k.value,a)==="resync"&&Q({protocolVersion:1,type:"resync",currentRevision:k.value.host.revision,reason:"patch baseRevision mismatch"}),Rn()},hostAttached:()=>{t=!0,window.clearTimeout(o),r?.dispose(),r=null,$e()}},$e(),{dispose:()=>{t=!0,window.clearTimeout(o),r?.dispose(),r=null}}}Lt();var Wt=document.getElementById("app");if(!Wt)throw new Error("Missing #app mount point");nt(n(Ut,{}),Wt);})(); +string:GO`}),n("small",{class:"field-error",children:g.arguments})]}),n("fieldset",{children:[n("legend",{children:"\u9001\u4FE1\u5148\u30DB\u30B9\u30C8"}),A.hosts.map(l=>n("label",{children:[n("input",{type:"checkbox",checked:c.includes(l.id),onChange:_=>s(_.currentTarget.checked?[...c,l.id]:c.filter(f=>f!==l.id))}),n("span",{children:l.name})]}))]}),n("div",{class:"dialog-actions",children:[n("button",{type:"button",class:"btn",onClick:t,children:"\u30AD\u30E3\u30F3\u30BB\u30EB"}),n("button",{class:"btn primary",children:"\u4FDD\u5B58"})]})]})})}function Ht({notice:e}){let t=S.value.host.state,r=S.value.ui,[o,i]=k(!1),[a,u]=k(null),[d,m]=k(null),[p,c]=k(null),[s,g]=k({}),h=(b,T)=>{let y=t.triggerPanel.buttons.filter(w=>w.row>=b||w.column>=T).length;if(y>0){c({rows:b,columns:T,lost:y}),S.updateUi({modalOpen:!0});return}O("triggerPanel.configureGrid",{rows:b,columns:T})},A=()=>{u(null),c(null),m(null),S.updateUi({modalOpen:!1})},l=async b=>{try{let T=await O("triggerPanel.fire",{id:b.id});g(y=>({...y,[b.id]:T.sent===!1?T.reason??"\u9001\u4FE1\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F":"\u9001\u4FE1\u3057\u307E\u3057\u305F"}))}catch(T){g(y=>({...y,[b.id]:T.message}))}},_=Array.from({length:t.triggerPanel.rows*t.triggerPanel.columns},(b,T)=>{let y=Math.floor(T/t.triggerPanel.columns),w=T%t.triggerPanel.columns;return{row:y,column:w,button:t.triggerPanel.buttons.find(C=>C.row===y&&C.column===w)}}),f=b=>{let T=b.clientX,y=r.drawerWidth;b.currentTarget.setPointerCapture(b.pointerId);let w=R=>S.updateUi({drawerWidth:Math.min(900,Math.max(280,y-(R.clientX-T)))}),C=()=>{window.removeEventListener("pointermove",w),window.removeEventListener("pointerup",C)};window.addEventListener("pointermove",w),window.addEventListener("pointerup",C)};return n("section",{class:`osc-panel ${r.drawerOpen?"open":""}`,"aria-hidden":!r.drawerOpen,children:[n("i",{class:"osc-resize",onPointerDown:f,title:"\u30C9\u30E9\u30C3\u30B0\u3067\u5E45\u3092\u5909\u3048\u3089\u308C\u307E\u3059"}),n("div",{class:"dh",children:[n("h2",{children:"OSC \u30DD\u30F3\u51FA\u3057"}),n("button",{class:"btn close","aria-label":"OSC \u30DD\u30F3\u51FA\u3057\u3092\u9589\u3058\u308B",title:"\u9589\u3058\u308B\uFF08Esc\uFF09",onClick:()=>S.updateUi({drawerOpen:!1}),children:"\u2715"}),n("div",{class:"dh-row",children:[n("button",{class:`btn ${o?"":"primary"}`,onClick:()=>i(!1),children:"\u5B9F\u884C\u30E2\u30FC\u30C9"}),n("button",{class:`btn ${o?"primary":""}`,onClick:()=>i(!0),children:"\u7DE8\u96C6\u30E2\u30FC\u30C9"}),o&&n(F,{children:[n("label",{class:"grid-size",children:["\u884C ",n("input",{class:"field",type:"number",min:"1",max:"12",value:t.triggerPanel.rows,onChange:b=>h(Number(b.currentTarget.value),t.triggerPanel.columns)})]}),n("label",{class:"grid-size",children:["\u5217 ",n("input",{class:"field",type:"number",min:"1",max:"12",value:t.triggerPanel.columns,onChange:b=>h(t.triggerPanel.rows,Number(b.currentTarget.value))})]})]}),n("span",{class:"muted",children:[t.triggerPanel.rows," \u884C \xD7 ",t.triggerPanel.columns," \u5217"]})]})]}),n("div",{class:`grid ${o?"editing":""}`,style:{gridTemplateColumns:`repeat(${t.triggerPanel.columns},1fr)`,gridTemplateRows:`repeat(${t.triggerPanel.rows},1fr)`},children:_.map(b=>b.button?n("div",{class:"trigger-cell",children:[n("button",{class:"trig",onClick:()=>o?u(b):void l(b.button),children:b.button.label}),s[b.button.id]&&n("small",{class:s[b.button.id]==="\u9001\u4FE1\u3057\u307E\u3057\u305F"?"":"failure",children:s[b.button.id]}),o&&n("button",{class:"cell-remove","aria-label":`${b.button.label}\u3092\u524A\u9664`,onClick:()=>{m(b.button),S.updateUi({modalOpen:!0})},children:"\xD7"})]}):n("button",{class:"empty-cell","aria-label":`${b.row+1}\u884C${b.column+1}\u5217\u306B\u30DC\u30BF\u30F3\u3092\u4F5C\u6210`,disabled:!o,onClick:()=>u(b),children:o?"\uFF0B":""}))}),a&&n(An,{cell:a,close:A,notice:e})," ",d&&n(q,{message:`\u300C${d.label}\u300D\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F`,close:A,confirm:()=>{O("triggerPanel.removeButton",{id:d.id}),A()}}),p&&n(q,{message:`${p.rows} \u884C \xD7 ${p.columns} \u5217\u306B\u7E2E\u5C0F\u3059\u308B\u3068\u3001\u7BC4\u56F2\u5916\u306E\u30DC\u30BF\u30F3 ${p.lost} \u500B\u304C\u6D88\u3048\u307E\u3059\u3002\u7D9A\u3051\u307E\u3059\u304B\uFF1F`,confirmLabel:"\u7E2E\u5C0F",close:A,confirm:()=>{O("triggerPanel.configureGrid",{rows:p.rows,columns:p.columns}),A()}})]})}var Nt=e=>e.hosts.filter(t=>t.enabled&&e.cueSync.targetHostIds.includes(t.id)).length;function En(e,t){e?.sentCount===0&&t("\u9001\u4FE1\u5148\u30DB\u30B9\u30C8\u304C\u3042\u308A\u307E\u305B\u3093")}function Dn(e,t,r){if(Nt(e)===0){t("Cue-Sync \u306E\u9001\u4FE1\u5148\u30DB\u30B9\u30C8\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044");return}O("cueSync.send",{}).then(()=>r()).catch(o=>t(o.message))}var On=new Map,Z=new Map,xn=e=>e.split(/[\\/]/).pop()||e,Rn=e=>e==null||!Number.isFinite(e)?"-- dBFS":`${e>=0?"":"\u2212"}${Math.abs(e).toFixed(1)} dBFS`,Ut=0;function In({current:e,frameRate:t,apply:r}){let[o,i]=k(e),[a,u]=k(e);a!==e&&(u(e),i(e));let d=o!==e,m=$({draft:o,current:e});return m.current={draft:o,current:e},n("span",{class:"offset-editor",children:[n(B,{class:"monitor-offset",value:o,frameRate:t,signed:!0,ariaLabel:"\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9\u30AA\u30D5\u30BB\u30C3\u30C8",onChange:i}),n("button",{class:`btn mini ${d?"primary":""}`,disabled:!d,onClick:()=>{let{draft:c,current:s}=m.current;c!==s&&r(c)},children:"\u78BA\u5B9A"}),d&&n("span",{class:"tiny offset-pending",children:"\u672A\u78BA\u5B9A"})]})}function $t(){let[,e]=k(0),[t,r]=k(null),[o,i]=k(!1),[a,u]=k(""),[d,m]=k(0),p=S.value,c=p.host.state,s=p.host.clock??c?.currentClock;P(()=>S.subscribe(()=>{for(let v of Ft(On,S.value.host.state?.cues??[])){let D=(Z.get(v)??0)+1;Z.set(v,D),window.setTimeout(()=>{Z.get(v)===D&&(Z.delete(v),e(E=>E+1))},700)}e(v=>v+1)}),[]),P(()=>S.updateUi({modalOpen:t!==null}),[t]),P(()=>{if(!a)return;let v=window.setTimeout(()=>u(""),4e3);return()=>window.clearTimeout(v)},[a]),P(()=>{let v=()=>Y({protocolVersion:1,type:"viewport",waveformWidth:360,devicePixelRatio:window.devicePixelRatio,visible:document.visibilityState==="visible"});return v(),window.addEventListener("resize",v),document.addEventListener("visibilitychange",v),()=>{window.removeEventListener("resize",v),document.removeEventListener("visibilitychange",v)}},[]);let g=()=>c?.cues.filter(v=>p.ui.selectedCueIds.has(v.id))??[],h=()=>{g().length&&r(g().length===1?"edit":"batch")},A=()=>{g().length&&r("remove")},l=(v,D={})=>void O(v,D).catch(E=>u(E.message)),_=()=>m(v=>v+1),f=()=>{c&&Dn(c,u,_)},b=v=>void O("mode.set",{mode:v}).then(D=>{v==="ltc"&&D?.ltcStarted===!1&&u("\u5165\u529B\u30C7\u30D0\u30A4\u30B9\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044")}).catch(D=>u(D.message));if(P(()=>{let v=D=>{let E=ht(D,p.ui.modalOpen);if(E)if(D.preventDefault(),E==="closeDrawer")S.updateUi({drawerOpen:!1});else if(E==="editCue")h();else if(E==="deleteCue")A();else if(E==="selectPrevious"||E==="selectNext"){if(!c)return;let H=Math.max(0,c.cues.findIndex(j=>j.id===p.ui.focusedCueId)),L=c.cues[Math.max(0,Math.min(c.cues.length-1,H+(E==="selectNext"?1:-1)))];L&&S.updateUi({focusedCueId:L.id,selectedCueIds:new Set([L.id])})}else l({projectNew:"project.new",projectOpen:"project.open",projectSave:"project.save",projectSaveAs:"project.saveAs",undo:"app.undo",redo:"app.redo"}[E])};return window.addEventListener("keydown",v),()=>window.removeEventListener("keydown",v)}),!c||!s)return n("main",{class:"app loading",children:"HOST \u306B\u63A5\u7D9A\u3057\u3066\u3044\u307E\u3059\u2026"});let T=(v,D)=>{let E=new Set(p.ui.selectedCueIds);if(D.metaKey||D.ctrlKey)E.has(v)?E.delete(v):E.add(v);else if(D.shiftKey&&p.ui.anchorCueId){let H=c.cues.findIndex(j=>j.id===p.ui.anchorCueId),L=c.cues.findIndex(j=>j.id===v);E=new Set(c.cues.slice(Math.min(H,L),Math.max(H,L)+1).map(j=>j.id))}else E=new Set([v]);S.updateUi({selectedCueIds:E,focusedCueId:v,anchorCueId:v})},y=v=>{i(!1),l(v)},w=()=>r(null),C=(v,D)=>{let E=D.clientX,H=[...p.ui.cueColumnWidths];D.currentTarget.setPointerCapture(D.pointerId);let L=Kt=>{let Le=Kt.clientX-E,Xt=Math.max(38,(H[v]??38)+Le),qt=Math.max(50,(H[v+1]??50)-Le),be=[...H];be[v]=Xt,be[v+1]=qt,S.updateUi({cueColumnWidths:be})},j=()=>{window.removeEventListener("pointermove",L),window.removeEventListener("pointerup",j)};window.addEventListener("pointermove",L),window.addEventListener("pointerup",j)},R=c.transport.triggerMuted?gt(c.transport.autoUnmuteAtUtc,Date.now()):"",V={"--cue-cols":p.ui.cueColumnWidths.map(v=>`${v}px`).join(" ")};return n(F,{children:[n("div",{class:`split ${p.ui.drawerOpen?"osc-open":""}`,style:{"--osc-width":`${p.ui.drawerWidth}px`},children:[n("main",{class:"app",children:[n("header",{children:[n("b",{children:"TIMEcode BRIDGE 3"}),n("button",{class:"project-button",onClick:()=>i(!o),children:[c.project.displayName,"\u3000\u25CF ",c.project.dirty?"\u672A\u4FDD\u5B58":"\u4FDD\u5B58\u6E08\u307F"]}),o&&n("div",{class:"project-menu",children:[n("button",{onClick:()=>y("project.new"),children:"\u65B0\u898F"}),n("button",{onClick:()=>y("project.open"),children:"\u958B\u304F\u2026"}),n("button",{onClick:()=>y("project.save"),children:"\u4FDD\u5B58"}),n("button",{onClick:()=>y("project.saveAs"),children:"\u540D\u524D\u3092\u4ED8\u3051\u3066\u4FDD\u5B58\u2026"}),c.project.recentFiles.length>0&&n(F,{children:[n("div",{class:"project-menu-sep",children:"\u6700\u8FD1\u4F7F\u3063\u305F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8"}),c.project.recentFiles.map(v=>n("button",{class:"recent",title:v,onClick:()=>{i(!1),l("project.open",{path:v})},children:xn(v)}))]})]}),n("button",{class:"btn","aria-label":"\u53D6\u308A\u6D88\u3059",disabled:!c.project.canUndo,onClick:()=>l("app.undo"),children:"\u21B6"}),n("button",{class:"btn","aria-label":"\u3084\u308A\u76F4\u3059",disabled:!c.project.canRedo,onClick:()=>l("app.redo"),children:"\u21B7"}),n("span",{class:"right muted",children:[n("i",{class:"led"}),"ENGINE ONLINE\u3000 ",s.frameRate," FPS / ",s.dropFrame?"DROP":"NON-DROP"]})]}),n("section",{class:"monitor",children:[n("div",{children:[n("span",{class:"tiny",children:[n("i",{class:"led"}),"\u53D7\u4FE1\u30BF\u30A4\u30E0\u30B3\u30FC\u30C9 / OFFSET\u9069\u7528\u5F8C"]}),n("div",{class:"tc",children:s.display}),n("span",{class:"tiny monitor-offset-line",children:["RAW\u3000",n("span",{class:"mono",children:s.raw}),"\u3000 OFFSET\u3000",n(In,{current:c.receive.offset,frameRate:s.frameRate,apply:v=>l("receive.setOffset",{value:v})}),"\u3000 ",c.transport.locked?"LOCK":"UNLOCK"," / ",Rn(p.host.wave?.levelDbfs)]})]}),n("div",{class:"next",children:[n("span",{class:"tiny",children:["NEXT CUE ",n("b",{class:"right",children:["T\u2212 ",c.nextCue?s.framesUntilNextCue??"--":"--","f"]})]}),n("div",{class:"next-main",children:[n("strong",{children:c.nextCue?.effectiveTriggerTime??"--:--:--:--"}),n("b",{children:c.nextCue?.name??"\u6B21\u306E\u30AD\u30E5\u30FC\u306F\u3042\u308A\u307E\u305B\u3093"})]}),n("span",{class:"tiny mono",children:c.nextCue?c.cues.find(v=>v.id===c.nextCue?.id)?.oscAddress:"\u2014"})]}),n("div",{class:"majorbox",children:[n("button",{class:`major ${d===0?"":d%2?"flash-a":"flash-b"}`,onClick:f,children:["CUE SYNC",n("small",{children:[Nt(c),"\u30DB\u30B9\u30C8\u3078\u9001\u4FE1"]})]}),n("button",{class:`major ${c.transport.triggerMuted?"on":""}`,onClick:()=>l("mute.set",{muted:!c.transport.triggerMuted}),children:[c.transport.triggerMuted?"MUTE":"LIVE",R&&n("b",{class:"mute-countdown",children:R}),n("small",{children:R?"\u5F8C\u306B\u81EA\u52D5\u89E3\u9664":`\u30AD\u30E5\u30FC\u9001\u51FA ${c.transport.triggerMuted?"\u505C\u6B62":"\u6709\u52B9"}`})]})]})]}),n("section",{class:"work",children:[n("section",{class:"cues",style:V,children:[n("div",{class:"tool",children:[n("h2",{children:"\u30AD\u30E5\u30FC\u30EA\u30B9\u30C8"}),n("label",{class:"judge-control muted",title:"\u3053\u306E\u5E45(\u30D5\u30EC\u30FC\u30E0)\u4EE5\u5185\u306E\u524D\u9032\u3084\u5F8C\u9000\u306F\u901A\u5E38\u518D\u751F\u30FB\u30B8\u30C3\u30BF\u30FC\u3068\u3057\u3066\u6271\u3044\u3001\u53D6\u308A\u3053\u307C\u3057\u305F\u9593\u306E\u30AD\u30E5\u30FC\u3082\u767A\u706B\u3057\u307E\u3059\u3002\u8D85\u3048\u3066\u98DB\u3093\u3060\u3089\u982D\u51FA\u3057(\u30B7\u30FC\u30AF)\u3084\u5DFB\u304D\u623B\u3057\u3068\u3057\u3066\u9014\u4E2D\u306E\u30AD\u30E5\u30FC\u306F\u767A\u706B\u3057\u307E\u305B\u3093",children:[n("span",{children:"\u30B8\u30E3\u30F3\u30D7\u5224\u5B9A"}),n("span",{"aria-hidden":"true",children:"\xB1"}),n("input",{class:"inline-input judge-input",type:"number",value:c.receive.triggerWindowFrames,min:"0",step:"1","aria-label":"\u30B8\u30E3\u30F3\u30D7\u5224\u5B9A\uFF08\u30D5\u30EC\u30FC\u30E0\uFF09",onChange:v=>l("receive.setTriggerWindow",{frames:Number(v.currentTarget.value)})}),n("span",{"aria-hidden":"true",children:"f"})]}),n("button",{class:"btn",onClick:()=>r("add"),children:"\uFF0B \u8FFD\u52A0"}),n("button",{class:"btn",disabled:!g().length,onClick:h,children:g().length>1?"\u4E00\u62EC\u7DE8\u96C6":"\u7DE8\u96C6"}),n("button",{class:"btn",disabled:g().length!==1,onClick:()=>l("cue.duplicate",{id:g()[0].id}),children:"\u8907\u88FD"}),n("button",{class:"btn",disabled:g().length!==1,onClick:()=>r("duplicate"),children:"\u9023\u7D9A\u8907\u88FD"}),n("button",{class:"btn",disabled:!g().length,onClick:A,children:"\u524A\u9664"}),n("button",{class:`btn right auto-mute-toggle ${c.transport.autoMuteEnabled?"on":""}`,"aria-pressed":c.transport.autoMuteEnabled,title:"\u30AD\u30E5\u30FC\u767A\u706B\u5F8C\u306E\u81EA\u52D5\u30DF\u30E5\u30FC\u30C8\u3092\u307E\u3068\u3081\u3066\u5165\u5207\u3057\u307E\u3059\u3002\u5207\u308B\u3068\u3001\u30AD\u30E5\u30FC\u3054\u3068\u306E\u300C\u767A\u706B\u6642\u30DF\u30E5\u30FC\u30C8\u300D\u3082\u50CD\u304D\u307E\u305B\u3093",onClick:()=>l("autoMute.setEnabled",{enabled:!c.transport.autoMuteEnabled}),children:["\u30AA\u30FC\u30C8\u30DF\u30E5\u30FC\u30C8 ",c.transport.autoMuteEnabled?"ON":"OFF"]}),n("button",{class:"btn",onClick:()=>l("cue.sortByTime"),children:"\u6642\u9593\u9806"})]}),n("div",{class:"cols",children:["\u6709\u52B9","\u30C8\u30EA\u30AC\u30FC\u6642\u9593","\u30AD\u30E5\u30FC\u540D","OSC\u30A2\u30C9\u30EC\u30B9","\u624B\u52D5"].map((v,D)=>n("span",{children:[v,D<4&&n("i",{class:"resize-handle",onPointerDown:E=>C(D,E)})]}))}),n("div",{class:"list",children:c.cues.map(v=>n("div",{class:`row ${v.id===s.nextCueId?"current":""} ${v.enabled?"":"disabled"} ${p.ui.selectedCueIds.has(v.id)?"selected":""} ${Z.has(v.id)?Z.get(v.id)%2?"fired-a":"fired-b":""}`,tabIndex:0,"aria-label":`${v.name} ${v.effectiveTriggerTime}`,onPointerDown:()=>{Ut=Date.now()},onFocus:()=>{Date.now()-Ut<300||p.ui.selectedCueIds.has(v.id)||S.updateUi({selectedCueIds:new Set([v.id]),focusedCueId:v.id,anchorCueId:v.id})},onClick:D=>T(v.id,D),onDblClick:D=>{D.target.closest("button,input")||h()},children:[n("span",{children:n("input",{type:"checkbox","aria-label":`${v.name}\u3092${v.enabled?"\u7121\u52B9":"\u6709\u52B9"}\u306B\u3059\u308B`,checked:v.enabled,onChange:D=>l("cue.setEnabled",{id:v.id,enabled:D.currentTarget.checked})})}),n("span",{class:"mono",children:v.effectiveTriggerTime}),n("span",{children:[v.name,c.transport.autoMutedCueId===v.id&&n("b",{class:"mute-tag",children:["MUTE",R?` ${R}`:""]})]}),n("span",{class:"mono",children:v.oscAddress}),n("button",{class:"btn fire","aria-label":`${v.name}\u3092\u767A\u706B`,onClick:D=>{D.stopPropagation(),O("cue.fire",{id:v.id}).then(E=>En(E,u)).catch(E=>u(E.message))},children:"\u25B6"})]},v.id))}),n("div",{class:"footcue",children:[n("span",{class:"tag",children:"NEXT"}),n("b",{class:"mono",children:c.nextCue?.effectiveTriggerTime}),n("span",{children:c.nextCue?.name})]})]}),n("aside",{class:"side",children:[n("div",{class:"sec",children:[n("div",{class:"head",children:[n("b",{children:"\u52D5\u4F5C\u30E2\u30FC\u30C9"}),n("span",{class:"tiny",children:c.transport.statusText})]}),n("div",{class:"mode",children:[n("button",{class:c.mode==="ltc"?"active":"",onClick:()=>b("ltc"),children:"LTC\u53D7\u4FE1"}),n("button",{class:c.mode==="generate"?"active":"",onClick:()=>b("generate"),children:"\u5185\u90E8\u751F\u6210"})]})]}),c.mode==="ltc"?n(Dt,{}):n(Rt,{notice:u}),n(Pt,{notice:u})]})]}),n("footer",{children:[n("span",{children:[n("i",{class:"led"}),c.mode==="ltc"?"LTC INPUT":"LTC GENERATOR"," ",c.transport.locked?"LOCK":"UNLOCK",c.transport.detailText?` \xB7 ${c.transport.detailText}`:""]}),n("button",{class:"btn right","aria-pressed":p.ui.drawerOpen,title:"OSC \u30DD\u30F3\u51FA\u3057\u30D1\u30CD\u30EB\u3092\u53F3\u306B\u958B\u9589\u3057\u307E\u3059",onClick:()=>S.updateUi({drawerOpen:!p.ui.drawerOpen}),children:p.ui.drawerOpen?"\u25E7 OSC \u30DD\u30F3\u51FA\u3057\u3092\u9589\u3058\u308B":"\u25E8 OSC \u30DD\u30F3\u51FA\u3057\u3092\u958B\u304F"})]}),a&&n("div",{class:"toast",onClick:()=>u(""),children:a})]}),n(Ht,{notice:u})]}),p.ui.optionsOpen&&n(Et,{notice:u,close:()=>S.updateUi({optionsOpen:!1,modalOpen:!1})})," ",t==="add"&&n(Pe,{frameRate:s.frameRate,hosts:c.hosts,close:w,done:w})," ",t==="edit"&&n(Pe,{cue:g()[0],frameRate:s.frameRate,hosts:c.hosts,close:w,done:w})," ",t==="batch"&&n(At,{ids:g().map(v=>v.id),hosts:c.hosts,frameRate:s.frameRate,close:w,done:w,notice:u})," ",t==="duplicate"&&n(St,{cue:g()[0],close:w,done:w})," ",t==="remove"&&n(q,{message:`\u9078\u629E\u3057\u305F ${g().length} \u4EF6\u306E\u30AD\u30E5\u30FC\u3092\u524A\u9664\u3057\u307E\u3059\u304B\uFF1F`,close:w,confirm:()=>{l("cue.remove",{ids:g().map(v=>v.id)}),w()}})]})}var G=e=>typeof e=="object"&&e!==null&&!Array.isArray(e),N=e=>typeof e=="number"&&Number.isFinite(e);function jt(e){return G(e)&&typeof e.raw=="string"&&typeof e.display=="string"&&N(e.totalFrames)&&["24","25","29.97df","30"].includes(String(e.frameRate))&&typeof e.dropFrame=="boolean"&&N(e.receivedAtMonotonicMs)}function Mn(e){return!G(e)||e.protocolVersion!==1||typeof e.type!="string"?!1:e.type==="clock"?N(e.seq)&&jt(e.clock):e.type==="wave"?N(e.seq)&&G(e.wave)&&N(e.wave.sampleRate)&&N(e.wave.windowMs)&&Array.isArray(e.wave.min)&&Array.isArray(e.wave.max)&&e.wave.min.every(N)&&e.wave.max.every(N)&&(e.wave.levelDbfs==null||N(e.wave.levelDbfs)):e.type==="snapshot"?N(e.revision)&&G(e.state)&&typeof e.state.sessionId=="string"&&Array.isArray(e.state.cues)&&G(e.state.transport)&&jt(e.state.currentClock):e.type==="patch"?N(e.revision)&&N(e.baseRevision)&&G(e.changes):e.type==="result"?typeof e.requestId=="string"&&typeof e.ok=="boolean"&&(e.ok||G(e.error)):!1}function Lt(e){try{let t=typeof e=="string"?JSON.parse(e):e;return Mn(t)?t:null}catch{return null}}var Ue=(e,t,r,o)=>({id:e,name:t,memo:"",triggerTime:r,effectiveTriggerTime:r,frameRate:"30",oscAddress:o,additionalOscAddresses:[],arguments:[],targetHostIds:["qlab"],enabled:!0,sendTriggerTimeAsSeconds:!1,sendTimecode:null,triggerOffset:null,autoMuteOnFire:!1,autoUnmuteAfter:null,runtime:{lastTriggeredAtUtc:null,flashToken:0}}),Wt=(e,t)=>t===null?void 0:t,Pn=e=>JSON.parse(JSON.stringify(e,Wt));function Fn(){return Pn({sessionId:"fake-session",project:{displayName:"show_A.tcb3",filePath:null,dirty:!1,canUndo:!1,canRedo:!1,recentFiles:[]},mode:"ltc",transport:{status:"receiving",statusText:"\u53D7\u4FE1\u4E2D",detailText:"CH 1 \xB7 48 kHz",signalErrorRatePercent:0,locked:!0,triggerMuted:!1,autoMuteEnabled:!1,autoMuteOnManualTrigger:!1,autoMutedCueId:null,autoUnmuteAtUtc:null,lastLtcReceivedAtUtc:null},receive:{selectedDeviceId:"in",devices:[{id:"in",name:"UR44 \u2014 Input 1 / 2",loopback:!1}],offset:"+00:00:00:08",triggerWindowFrames:3,freerunDurationSeconds:1},generator:{running:!1,startTime:"01:00:00:00",loopEndTime:null,frameRate:"30",selectedOutputDeviceId:"out",outputDevices:[{id:"out",name:"UR44 \u2014 Output 1 / 2",loopback:!1}],volume:.4,ltcOutputActive:!1,settingsPendingReset:!1},currentClock:{raw:"01:24:16:00",display:"01:24:16:08",totalFrames:151688,frameRate:"30",dropFrame:!1,receivedAtMonotonicMs:0,nextCueId:"cue-2",framesUntilNextCue:112},nextCue:{id:"cue-2",name:"\u30BF\u30A4\u30C8\u30EB OUT",triggerTime:"01:24:20:00",effectiveTriggerTime:"01:24:20:00",framesUntil:112},cues:[Ue("cue-1","\u672C\u7DE8 IN","01:23:40:00","/qlab/go"),Ue("cue-2","\u30BF\u30A4\u30C8\u30EB OUT","01:24:20:00","/video/title/out")],hosts:[{id:"qlab",name:"QLab \u2014 Main",ipAddress:"192.168.1.20",port:53e3,enabled:!0,reachability:"reachable"},{id:"reso",name:"Resolume \u2014 Stage",ipAddress:"192.168.1.31",port:7e3,enabled:!0,reachability:"reachable"}],cueSync:{oscAddress:"/cuesync",targetHostIds:["qlab","reso"]},triggerPanel:{rows:4,columns:4,buttons:[{id:"go",row:0,column:0,label:"GO",oscAddress:"/go",arguments:[],targetHostIds:["qlab"]}]},logs:[{id:"log-1",timestampUtc:new Date(Date.now()-1e3).toISOString(),message:"fake-host \u3092\u958B\u59CB\u3057\u307E\u3057\u305F",success:!0}],uiCapabilities:{supportsNativeOpenDialog:!1,supportsNativeSaveDialog:!1,platform:"macos"}})}function Bt(){let e=Fn(),t=1,r=0,o=10,i=!0,a=null,u=p=>queueMicrotask(()=>i&&window.tcb.receive(JSON.stringify(p,Wt))),d=p=>{let{logsAppend:c,logsReset:s,...g}=p;e={...e,...g},s&&(e.logs=s),c&&(e.logs=[...e.logs,...c]),u({protocolVersion:1,type:"patch",baseRevision:t,revision:++t,changes:p})},m=p=>{let c=JSON.parse(p);if(c.type==="ready"||c.type==="resync"){u({protocolVersion:1,type:"snapshot",revision:t,state:e}),a===null&&(a=window.setInterval(()=>u({protocolVersion:1,type:"clock",seq:++r,clock:{...e.currentClock,receivedAtMonotonicMs:performance.now()}}),100));return}if(c.type!=="command")return;let s=c.args,g=l=>u({protocolVersion:1,type:"result",requestId:c.requestId,ok:!0,data:l,revision:t}),h=l=>u({protocolVersion:1,type:"result",requestId:c.requestId,ok:!1,error:{code:"validation",message:"\u5165\u529B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044",retryable:!1,fieldErrors:l}}),A=(l,_=!0)=>d({logsAppend:[{id:`log-${++o}`,timestampUtc:new Date().toISOString(),message:l,success:_}]});if(c.command==="mode.set"){let l=s.mode,_=l==="ltc"&&!!e.receive.selectedDeviceId;d({mode:l,transport:{...e.transport,status:_?"receiving":"stopped",statusText:_?"\u53D7\u4FE1\u4E2D":l==="ltc"?"\u505C\u6B62\u4E2D":"\u751F\u6210\u5F85\u6A5F",locked:_}}),g({ltcStarted:_});return}if(c.command==="ltc.stop"){d({transport:{...e.transport,status:"stopped",statusText:"\u505C\u6B62",locked:!1}}),g();return}if(c.command==="receive.selectDevice"&&!(s.deviceId??"")){d({receive:{...e.receive,selectedDeviceId:null},transport:{...e.transport,status:"stopped",statusText:"\u505C\u6B62\u4E2D",locked:!1}}),g();return}if(c.command==="receive.selectDevice"){d({receive:{...e.receive,selectedDeviceId:s.deviceId},transport:{...e.transport,status:"receiving",statusText:"\u53D7\u4FE1\u4E2D",locked:!0}}),g();return}if(c.command==="ltc.start"||c.command==="ltc.reconnect"){d({receive:{...e.receive,selectedDeviceId:s.deviceId??e.receive.selectedDeviceId},transport:{...e.transport,status:"receiving",statusText:"\u53D7\u4FE1\u4E2D",locked:!0}}),g();return}if(c.command==="receive.setFreerunDuration"){d({receive:{...e.receive,freerunDurationSeconds:Number(s.seconds)}}),g();return}if(c.command==="audio.refreshDevices"){d(s.direction==="capture"?{receive:{...e.receive}}:{generator:{...e.generator}}),g();return}if(c.command==="generator.configure"){d({generator:{...e.generator,startTime:s.startTime??e.generator.startTime,loopEndTime:"loopEndTime"in s?s.loopEndTime||null:e.generator.loopEndTime??null,frameRate:s.frameRate,selectedOutputDeviceId:s.outputDeviceId||null,volume:s.volume,settingsPendingReset:e.generator.running}}),g();return}if(c.command==="generator.start"||c.command==="generator.stop"){let l=c.command.endsWith("start");d({generator:{...e.generator,running:l,ltcOutputActive:l&&!!e.generator.selectedOutputDeviceId,settingsPendingReset:!1},transport:{...e.transport,status:l?"receiving":"stopped",statusText:l?"\u751F\u6210\u4E2D":"\u505C\u6B62"}}),g();return}if(c.command==="generator.reset"){d({generator:{...e.generator,running:!1,ltcOutputActive:!1,settingsPendingReset:!1},currentClock:{...e.currentClock,raw:e.generator.startTime,display:e.generator.startTime}}),g();return}if(c.command==="host.add"||c.command==="host.update"){let l=s.host,_={...l.name?{}:{"host.name":"\u5FC5\u9808"},...l.ipAddress?{}:{"host.ipAddress":"\u5FC5\u9808"},...l.port>=1&&l.port<=65535?{}:{"host.port":"1\u301C65535"}};if(Object.keys(_).length){h(_);return}let f=c.command==="host.add"?`host-${++o}`:String(s.id),b={id:f,name:l.name,ipAddress:l.ipAddress,port:l.port,enabled:l.enabled??!0,reachability:"unknown"};d({hosts:c.command==="host.add"?[...e.hosts,b]:e.hosts.map(T=>T.id===f?b:T)}),g({id:f});return}if(c.command==="host.remove"){d({hosts:e.hosts.filter(l=>l.id!==s.id)}),g();return}if(c.command==="host.setEnabled"){d({hosts:e.hosts.map(l=>l.id===s.id?{...l,enabled:!!s.enabled}:l)}),g();return}if(c.command==="host.ping"){d({hosts:e.hosts.map(l=>l.id===s.id?{...l,reachability:"reachable"}:l)}),g({reachable:!0,latencyMs:2});return}if(c.command==="triggerPanel.configureGrid"){d({triggerPanel:{...e.triggerPanel,rows:Number(s.rows),columns:Number(s.columns),buttons:e.triggerPanel.buttons.filter(l=>l.rowf.id!==l),_]}}),g({id:l});return}if(c.command==="triggerPanel.removeButton"){d({triggerPanel:{...e.triggerPanel,buttons:e.triggerPanel.buttons.filter(l=>l.id!==s.id)}}),g();return}if(c.command==="triggerPanel.fire"){A(`\u30DD\u30F3\u51FA\u3057: ${e.triggerPanel.buttons.find(l=>l.id===s.id)?.label??s.id}`),g({sent:!0,sentCount:1,skippedHostIds:[],reason:"None"});return}if(c.command==="logs.clear"){d({logsReset:[]}),g();return}if(c.command==="cueSync.configure"){d({cueSync:{...e.cueSync,...s}}),g();return}if(c.command==="cueSync.send"){A("Cue-Sync \u3092\u9001\u4FE1\u3057\u307E\u3057\u305F"),g({sent:!0,sentCount:2,skippedHostIds:[]});return}if(c.command==="cue.add"||c.command==="cue.update"){let l=s.cue,_={...te(l.frameRate??"30"),...l,additionalOscAddresses:(l.additionalOscAddresses??[]).join(` +`),argumentsText:(l.arguments??[]).map(y=>`${y.type}:${y.value}`).join(` +`),sendTimecode:l.sendTimecode??"",triggerOffset:l.triggerOffset??"",autoUnmuteAfter:l.autoUnmuteAfter??""},f=me(_);if(!f.draft){h(Object.fromEntries(Object.entries(f.errors).map(([y,w])=>[`cue.${y}`,w])));return}let b=c.command==="cue.add"?`cue-${++o}`:String(s.id),T={...Ue(b,f.draft.name,f.draft.triggerTime,f.draft.oscAddress),...f.draft,id:b,effectiveTriggerTime:f.draft.triggerTime};d({cues:c.command==="cue.add"?[...e.cues,T]:e.cues.map(y=>y.id===b?T:y),project:{...e.project,dirty:!0,canUndo:!0}}),g({id:b});return}if(c.command==="cue.remove"){d({cues:e.cues.filter(l=>!s.ids.includes(l.id))}),g();return}if(c.command==="cue.duplicate"){let l=e.cues.find(f=>f.id===s.id),_=[];if(l){let f=Array.from({length:Number(s.count??1)},(b,T)=>{let y=`cue-${++o}`;return _.push(y),{...l,id:y,name:`${l.name} (\u30B3\u30D4\u30FC${T?` ${T+1}`:""})`}});d({cues:[...e.cues,...f]})}g({ids:_});return}if(c.command==="cue.batchUpdate"){d({cues:e.cues.map(l=>s.ids.includes(l.id)?{...l,...s.changes}:l)}),g({updated:s.ids.length,offsetSkipped:0});return}if(c.command.startsWith("project.")){d({...c.command==="project.new"?{cues:[]}:{},project:{...e.project,displayName:c.command==="project.new"?"\u540D\u79F0\u672A\u8A2D\u5B9A.tcb3":e.project.displayName,dirty:!1,canUndo:!1,canRedo:!1}}),g({cancelled:!1});return}if(c.command==="app.undo"||c.command==="app.redo"){d({project:{...e.project,canUndo:c.command==="app.redo",canRedo:c.command==="app.undo"}}),g();return}c.command==="mute.set"&&d({transport:{...e.transport,triggerMuted:!!s.muted}}),c.command==="cue.setEnabled"&&d({cues:e.cues.map(l=>l.id===s.id?{...l,enabled:!!s.enabled}:l)}),g()};return window.invokeCSharpAction=m,{dispose:()=>{i=!1,a!==null&&window.clearInterval(a),window.invokeCSharpAction===m&&delete window.invokeCSharpAction}}}var Ne=!1,$e=!1;function Hn(){$e=!0,!Ne&&(Ne=!0,requestAnimationFrame(()=>{Ne=!1,$e&&($e=!1,S.notify())}))}var je=()=>Y({protocolVersion:1,type:"ready",clientVersion:"3.0.0",capabilities:["clock-latest-only","wave-minmax","m1","m2a","m2b","m3"]});function Vt(e=800){let t=!1,r=null,o=window.setTimeout(()=>{t||window.invokeCSharpAction||(r=Bt(),je())},e);return window.tcb={receive:i=>{let a=Lt(i);if(!a)return;if(a.type==="result"){vt(a);return}bt(S.value,a)==="resync"&&Y({protocolVersion:1,type:"resync",currentRevision:S.value.host.revision,reason:"patch baseRevision mismatch"}),Hn()},hostAttached:()=>{t=!0,window.clearTimeout(o),r?.dispose(),r=null,je()}},je(),{dispose:()=>{t=!0,window.clearTimeout(o),r?.dispose(),r=null}}}Vt();var Jt=document.getElementById("app");if(!Jt)throw new Error("Missing #app mount point");rt(n($t,{}),Jt);})(); diff --git a/src/TimecodeBridge.Web/src/components/generator-panel.tsx b/src/TimecodeBridge.Web/src/components/generator-panel.tsx index 1540be3..3efdab1 100644 --- a/src/TimecodeBridge.Web/src/components/generator-panel.tsx +++ b/src/TimecodeBridge.Web/src/components/generator-panel.tsx @@ -2,8 +2,11 @@ import type {JSX} from "preact"; import {useEffect,useRef,useState} from "preact/hooks"; import {command} from "../commands"; import type {FrameRate} from "../protocol"; -import {defaultLoopEnd} from "../generator-loop"; +import {defaultLoopEnd,loopRangeValid} from "../generator-loop"; import {appStore} from "../store"; -import {TimecodeInput} from "./timecode-input"; +import {clampTimecode,TimecodeInput} from "./timecode-input"; type Draft={startTime:string;loopEndTime:string|null;frameRate:FrameRate;outputDeviceId:string;volume:number}; -export function GeneratorPanel({notice}:{notice:(text:string)=>void}):JSX.Element {const g=appStore.value.host.state!.generator;const initial=():Draft=>({startTime:g.startTime,loopEndTime:g.loopEndTime,frameRate:g.frameRate,outputDeviceId:g.selectedOutputDeviceId??"",volume:g.volume});const[d,setD]=useState(initial);const timer=useRef(null);useEffect(()=>setD(initial()),[g.startTime,g.loopEndTime,g.frameRate,g.selectedOutputDeviceId,g.volume]);const send=(next:Draft)=>void command("generator.configure",next).catch((e:{message:string})=>notice(e.message));const change=(key:K,value:Draft[K])=>{const next={...d,[key]:value};setD(next);send(next)};const loopToggle=(on:boolean)=>change("loopEndTime",on?(d.loopEndTime??defaultLoopEnd(d.startTime,d.frameRate)):null);const volume=(value:number,now=false)=>{const next={...d,volume:value};setD(next);if(timer.current!==null)window.clearTimeout(timer.current);if(now)send(next);else timer.current=window.setTimeout(()=>send(next),100)};return
TC 入出力内部生成設定
○ 入力 停止生成 {g.running?"再生中":"停止"}出力 {g.ltcOutputActive?"送出中":"停止"}音量 {Math.round(d.volume*100)}%
{d.loopEndTime!==null&&}
{g.running&&g.settingsPendingReset&&設定は再生し直すと反映されます}
} +// 終了 TC が開始 TC 以前の間は TC を送らず、欄の下に反映していないことを出す。 +// Host はその組み合わせを丸ごと弾くので、送ると一緒に送った音量や出力先まで変わらなくなる。打っている途中で一時的にそうなることもある +// FPS を変えたら、新しいレートにないフレーム番号を丸めてから送る(そのままだと Host が弾く) +export function GeneratorPanel({notice}:{notice:(text:string)=>void}):JSX.Element {const g=appStore.value.host.state!.generator;const initial=():Draft=>({startTime:g.startTime,loopEndTime:g.loopEndTime??null,frameRate:g.frameRate,outputDeviceId:g.selectedOutputDeviceId??"",volume:g.volume});const[d,setD]=useState(initial);const timer=useRef(null);useEffect(()=>setD(initial()),[g.startTime,g.loopEndTime,g.frameRate,g.selectedOutputDeviceId,g.volume]);const send=(next:Draft)=>{const{startTime:_start,loopEndTime:_end,...rest}=next;void command("generator.configure",loopRangeValid(next.startTime,next.loopEndTime)?next:rest).catch((e:{message:string})=>notice(e.message))};const change=(key:K,value:Draft[K])=>{const next={...d,[key]:value};setD(next);send(next)};const rate=(value:FrameRate)=>{const next={...d,frameRate:value,startTime:clampTimecode(d.startTime,value),loopEndTime:d.loopEndTime===null?null:clampTimecode(d.loopEndTime,value)};setD(next);send(next)};const loopToggle=(on:boolean)=>change("loopEndTime",on?(d.loopEndTime??defaultLoopEnd(d.startTime,d.frameRate)):null);const volume=(value:number,now=false)=>{const next={...d,volume:value};setD(next);if(timer.current!==null)window.clearTimeout(timer.current);if(now)send(next);else timer.current=window.setTimeout(()=>send(next),100)};return
TC 入出力内部生成設定
○ 入力 停止生成 {g.running?"再生中":"停止"}出力 {g.ltcOutputActive?"送出中":"停止"}音量 {Math.round(d.volume*100)}%
{d.loopEndTime!==null&&}{!loopRangeValid(d.startTime,d.loopEndTime)&&終了 TC を開始 TC より後にしてください。直すまで TC の変更は反映されません}
{g.running&&g.settingsPendingReset&&設定は再生し直すと反映されます}
} diff --git a/src/TimecodeBridge.Web/src/components/receive-panel.tsx b/src/TimecodeBridge.Web/src/components/receive-panel.tsx index e271cd5..ad525b8 100644 --- a/src/TimecodeBridge.Web/src/components/receive-panel.tsx +++ b/src/TimecodeBridge.Web/src/components/receive-panel.tsx @@ -8,7 +8,7 @@ export const selectReceiveDevice=(value:string):void=>run("receive.selectDevice" /** 再スキャン。Host は裏のスレッドで列挙し終えてから result を返すので、それまでスキャン中を表示する(失敗は Host のエラー表示に出る) */ export async function rescanDevices(setScanning:(scanning:boolean)=>void):Promise{setScanning(true);try{await command("audio.refreshDevices",{direction:"capture"})}catch{/* 表示は Host 側 */}finally{setScanning(false)}} -export function lastLtcText(status:string,lastReceived:string|null,now=Date.now()):string|null { +export function lastLtcText(status:string,lastReceived:string|null|undefined,now=Date.now()):string|null { if(status!=="signalLost"&&status!=="freerun") return null; if(!lastReceived) return "最終受信なし"; const received=Date.parse(lastReceived); diff --git a/src/TimecodeBridge.Web/src/components/timecode-input.tsx b/src/TimecodeBridge.Web/src/components/timecode-input.tsx index 006f56d..6b9dda7 100644 --- a/src/TimecodeBridge.Web/src/components/timecode-input.tsx +++ b/src/TimecodeBridge.Web/src/components/timecode-input.tsx @@ -34,6 +34,15 @@ export function timecodeFocusForKey(key:string,index:number,isEmpty:boolean):num return null; } +// 欄に入ったら 2 桁を選び、打った数字で置き換える。選ばないと埋まった欄(maxlength=2)にカーソルが立つだけで、数字を打っても何も変わらない。 +// クリックは mousedown の既定動作(カーソルを置く)を止めて自分で選ぶ。focus で選んでも WebKit は続く mouseup で選択を解く +export function selectTimecodePartOnMouseDown(event:{button:number;preventDefault:()=>void},input:{focus:()=>void;select:()=>void}):void { + if(event.button!==0)return; + event.preventDefault(); + input.focus(); + input.select(); +} + export const frameMaximum=(frameRate:FrameRate):number=>frameRate==="24"?23:frameRate==="25"?24:29; export function clampTimecode(value:string,frameRate:FrameRate,signed=false):string { @@ -57,7 +66,7 @@ export function TimecodeInput({value,onChange,onCommit,frameRate,signed=false,re const blur=(index:number)=>{const next=[...latest.current] as TimecodeParts;next[index]=clampTimecodePart(next[index]??"",index,frameRate);publish(next);onCommit?.(joinTimecode(next,sign,signed))}; return {signed&&} - {parts.map((part,index)=>{refs.current[index]=el}} class="timecode-part" inputMode="numeric" pattern="[0-9]*" maxlength={2} required={required} disabled={disabled} value={part} aria-label={`${ariaLabel} ${["時","分","秒","フレーム"][index]??""}`} onBeforeInput={e=>{const data=(e as unknown as InputEvent).data;if(data&&/[^0-9]/.test(data))e.preventDefault()}} onCompositionStart={e=>{const el=e.currentTarget;el.blur();window.setTimeout(()=>el.focus(),0)}} onInput={e=>{const result=enterTimecodeDigits(latest.current,index,e.currentTarget.value);publish(result.parts);focus(result.focus)}} onPaste={e=>{e.preventDefault();const result=enterTimecodeDigits(latest.current,index,e.clipboardData?.getData("text")??"");publish(result.parts);focus(result.focus)}} onBlur={()=>blur(index)} onKeyDown={e=>{if(e.key==="ArrowUp"||e.key==="ArrowDown"){e.preventDefault();const maximum=index===0?23:index===1||index===2?59:frameMaximum(frameRate),next=[...latest.current] as TimecodeParts,current=Number(next[index]||0);next[index]=String(Math.max(0,Math.min(maximum,current+(e.key==="ArrowUp"?1:-1)))).padStart(2,"0");publish(next);return}const target=timecodeFocusForKey(e.key,index,part==="");if(target!==null){e.preventDefault();focus(target)}}}/>{index<3&&})} + {parts.map((part,index)=>{refs.current[index]=el}} class="timecode-part" inputMode="numeric" pattern="[0-9]*" maxlength={2} required={required} disabled={disabled} value={part} aria-label={`${ariaLabel} ${["時","分","秒","フレーム"][index]??""}`} onBeforeInput={e=>{const data=(e as unknown as InputEvent).data;if(data&&/[^0-9]/.test(data))e.preventDefault()}} onCompositionStart={e=>{const el=e.currentTarget;el.blur();window.setTimeout(()=>el.focus(),0)}} onInput={e=>{const result=enterTimecodeDigits(latest.current,index,e.currentTarget.value);publish(result.parts);focus(result.focus)}} onPaste={e=>{e.preventDefault();const result=enterTimecodeDigits(latest.current,index,e.clipboardData?.getData("text")??"");publish(result.parts);focus(result.focus)}} onFocus={e=>e.currentTarget.select()} onMouseDown={e=>selectTimecodePartOnMouseDown(e,e.currentTarget)} onBlur={()=>blur(index)} onKeyDown={e=>{if(e.key==="ArrowUp"||e.key==="ArrowDown"){e.preventDefault();const maximum=index===0?23:index===1||index===2?59:frameMaximum(frameRate),next=[...latest.current] as TimecodeParts,current=Number(next[index]||0);next[index]=String(Math.max(0,Math.min(maximum,current+(e.key==="ArrowUp"?1:-1)))).padStart(2,"0");publish(next);return}const target=timecodeFocusForKey(e.key,index,part==="");if(target!==null){e.preventDefault();focus(target)}}}/>{index<3&&})} FF 00–{String(frameMaximum(frameRate)).padStart(2,"0")} ; } diff --git a/src/TimecodeBridge.Web/src/generator-loop.ts b/src/TimecodeBridge.Web/src/generator-loop.ts index 22bca27..ef93cab 100644 --- a/src/TimecodeBridge.Web/src/generator-loop.ts +++ b/src/TimecodeBridge.Web/src/generator-loop.ts @@ -17,3 +17,20 @@ export function defaultLoopEnd(startTime:string,frameRate:FrameRate,seconds=10): const pad=(n:number)=>String(n).padStart(2,"0"); return [pad(Math.floor(capped/(3600*rate))),pad(Math.floor(capped/(60*rate))%60),pad(Math.floor(capped/rate)%60),pad(capped%rate)].join(":"); } + +// 前後だけ比べられればよいので、フレームは 100 進で並べる(レートに依らない) +const order=(timecode:string):number|null=>{ + const parts=timecode.split(/[:;]/).map(n=>Number(n)); + if (parts.length!==4||parts.some(n=>!Number.isFinite(n))) return null; + return ((parts[0]!*60+parts[1]!)*60+parts[2]!)*100+parts[3]!; +}; + +/** + * 終了 TC が開始 TC より後か。ループなしは常に成り立つ。 + * 読めない値は Host に判断を任せる(形式の誤りは Host が返す)。 + */ +export function loopRangeValid(startTime:string,loopEndTime:string|null):boolean { + if (loopEndTime===null) return true; + const start=order(startTime),end=order(loopEndTime); + return start===null||end===null||end>start; +} diff --git a/src/TimecodeBridge.Web/src/mute-countdown.ts b/src/TimecodeBridge.Web/src/mute-countdown.ts index ff9c12e..929329b 100644 --- a/src/TimecodeBridge.Web/src/mute-countdown.ts +++ b/src/TimecodeBridge.Web/src/mute-countdown.ts @@ -1,5 +1,5 @@ /** 自動解除までの残り時間。MUTE ボタンに出すので、本番で一目で読める短い表記にする。 */ -export function muteCountdown(untilUtc: string | null, nowMs: number): string { +export function muteCountdown(untilUtc: string | null | undefined, nowMs: number): string { if (!untilUtc) return ""; const until = Date.parse(untilUtc); if (Number.isNaN(until)) return ""; diff --git a/src/TimecodeBridge.Web/src/protocol.ts b/src/TimecodeBridge.Web/src/protocol.ts index 58d146c..89737d5 100644 --- a/src/TimecodeBridge.Web/src/protocol.ts +++ b/src/TimecodeBridge.Web/src/protocol.ts @@ -17,15 +17,17 @@ export type WebMessage = export type FrameRate = "24" | "25" | "29.97df" | "30"; +// Host は null の項目をキーごと省いて送る(Protocol.Json の WhenWritingNull)。null になりうる項目は `?: X | null` にして、 +// 届かない(undefined)ときも null と同じに扱う。`!== null` で判定すると undefined を素通りさせて描画が例外で止まる export interface AppState { sessionId: string; - project: { displayName: string; filePath: string | null; dirty: boolean; canUndo: boolean; canRedo: boolean; recentFiles: string[] }; + project: { displayName: string; filePath?: string | null; dirty: boolean; canUndo: boolean; canRedo: boolean; recentFiles: string[] }; mode: "ltc" | "generate"; - transport: { status: "stopped" | "receiving" | "freerun" | "signalLost" | "error"; statusText: string; detailText: string; signalErrorRatePercent: number | null; locked: boolean; triggerMuted: boolean; autoMuteEnabled: boolean; autoMuteOnManualTrigger: boolean; autoMutedCueId: string | null; autoUnmuteAtUtc: string | null; lastLtcReceivedAtUtc: string | null }; - receive: { selectedDeviceId: string | null; devices: AudioDevice[]; offset: string; triggerWindowFrames: number; freerunDurationSeconds: number }; - generator: { running: boolean; startTime: string; loopEndTime: string | null; frameRate: FrameRate; selectedOutputDeviceId: string | null; outputDevices: AudioDevice[]; volume: number; ltcOutputActive: boolean; settingsPendingReset: boolean }; + transport: { status: "stopped" | "receiving" | "freerun" | "signalLost" | "error"; statusText: string; detailText: string; signalErrorRatePercent?: number | null; locked: boolean; triggerMuted: boolean; autoMuteEnabled: boolean; autoMuteOnManualTrigger: boolean; autoMutedCueId?: string | null; autoUnmuteAtUtc?: string | null; lastLtcReceivedAtUtc?: string | null }; + receive: { selectedDeviceId?: string | null; devices: AudioDevice[]; offset: string; triggerWindowFrames: number; freerunDurationSeconds: number }; + generator: { running: boolean; startTime: string; loopEndTime?: string | null; frameRate: FrameRate; selectedOutputDeviceId?: string | null; outputDevices: AudioDevice[]; volume: number; ltcOutputActive: boolean; settingsPendingReset: boolean }; currentClock: ClockState; - nextCue: NextCueState | null; + nextCue?: NextCueState | null; cues: CueDto[]; hosts: HostDto[]; cueSync: { oscAddress: string; targetHostIds: string[] }; @@ -37,7 +39,7 @@ export interface AppState { export interface ClockState { raw: string; display: string; totalFrames: number; frameRate: FrameRate; dropFrame: boolean; receivedAtMonotonicMs: number; nextCueId?: string | null; framesUntilNextCue?: number | null } export interface NextCueState { id: string; name: string; triggerTime: string; effectiveTriggerTime: string; framesUntil: number } export interface AudioDevice { id: string; name: string; loopback: boolean } -export interface CueDto { id: string; name: string; memo: string; triggerTime: string; effectiveTriggerTime: string; frameRate: FrameRate; oscAddress: string; additionalOscAddresses: string[]; arguments: OscArgumentDto[]; targetHostIds: string[]; enabled: boolean; sendTriggerTimeAsSeconds: boolean; sendTimecode: string | null; triggerOffset: string | null; autoMuteOnFire: boolean; autoUnmuteAfter: string | null; runtime: { lastTriggeredAtUtc: string | null; flashToken: number } } +export interface CueDto { id: string; name: string; memo: string; triggerTime: string; effectiveTriggerTime: string; frameRate: FrameRate; oscAddress: string; additionalOscAddresses: string[]; arguments: OscArgumentDto[]; targetHostIds: string[]; enabled: boolean; sendTriggerTimeAsSeconds: boolean; sendTimecode?: string | null; triggerOffset?: string | null; autoMuteOnFire: boolean; autoUnmuteAfter?: string | null; runtime: { lastTriggeredAtUtc?: string | null; flashToken: number } } export type OscArgumentDto = { type: "int32"; value: number } | { type: "float32"; value: number } | { type: "string"; value: string }; export interface CueDraft { name:string; memo?:string; triggerTime:string; frameRate?:FrameRate; oscAddress:string; additionalOscAddresses?:string[]; arguments?:OscArgumentDto[]|undefined; targetHostIds?:string[]; enabled?:boolean; sendTriggerTimeAsSeconds?:boolean; sendTimecode?:string|null; triggerOffset?:string|null; autoMuteOnFire?:boolean; autoUnmuteAfter?:string|null } export interface CueBatchDraft { oscAddress?:string; additionalOscAddresses?:string[]; arguments?:OscArgumentDto[]; targetHostIds?:string[]; memo?:string; enabled?:boolean; sendTriggerTimeAsSeconds?:boolean; autoMuteOnFire?:boolean; sendTimecode?:string|null; triggerOffset?:string|null; autoUnmuteAfter?:string|null } @@ -66,7 +68,7 @@ export type CommandName = | "triggerPanel.configureGrid" | "triggerPanel.upsertButton" | "triggerPanel.removeButton" | "triggerPanel.fire" | "logs.clear"; /** Waveform samples are normalized to -1..1. */ -export interface WaveState { sampleRate: number; windowMs: number; min: number[]; max: number[]; levelDbfs: number | null } +export interface WaveState { sampleRate: number; windowMs: number; min: number[]; max: number[]; levelDbfs?: number | null } const object = (value: unknown): value is Record => typeof value === "object" && value !== null && !Array.isArray(value); const finite = (value: unknown): value is number => typeof value === "number" && Number.isFinite(value); @@ -77,7 +79,7 @@ export function isClockState(value: unknown): value is ClockState { export function isHostMessage(value: unknown): value is HostMessage { if (!object(value) || value.protocolVersion !== 1 || typeof value.type !== "string") return false; if (value.type === "clock") return finite(value.seq) && isClockState(value.clock); - if (value.type === "wave") return finite(value.seq) && object(value.wave) && finite(value.wave.sampleRate) && finite(value.wave.windowMs) && Array.isArray(value.wave.min) && Array.isArray(value.wave.max) && value.wave.min.every(finite) && value.wave.max.every(finite) && (value.wave.levelDbfs === null || finite(value.wave.levelDbfs)); + if (value.type === "wave") return finite(value.seq) && object(value.wave) && finite(value.wave.sampleRate) && finite(value.wave.windowMs) && Array.isArray(value.wave.min) && Array.isArray(value.wave.max) && value.wave.min.every(finite) && value.wave.max.every(finite) && (value.wave.levelDbfs == null || finite(value.wave.levelDbfs)); if (value.type === "snapshot") return finite(value.revision) && object(value.state) && typeof value.state.sessionId === "string" && Array.isArray(value.state.cues) && object(value.state.transport) && isClockState(value.state.currentClock); if (value.type === "patch") return finite(value.revision) && finite(value.baseRevision) && object(value.changes); if (value.type === "result") return typeof value.requestId === "string" && typeof value.ok === "boolean" && (value.ok || object(value.error)); diff --git a/src/TimecodeBridge.Web/src/testing/fake-host.ts b/src/TimecodeBridge.Web/src/testing/fake-host.ts index a976353..c44130f 100644 --- a/src/TimecodeBridge.Web/src/testing/fake-host.ts +++ b/src/TimecodeBridge.Web/src/testing/fake-host.ts @@ -2,9 +2,12 @@ import type {AppState,CueDraft,HostMessage,WebMessage} from "../protocol"; import {buildCueDraft,emptyCueForm} from "../cue-draft"; const base=(id:string,name:string,time:string,address:string)=>({id,name,memo:"",triggerTime:time,effectiveTriggerTime:time,frameRate:"30" as const,oscAddress:address,additionalOscAddresses:[],arguments:[],targetHostIds:["qlab"],enabled:true,sendTriggerTimeAsSeconds:false,sendTimecode:null,triggerOffset:null,autoMuteOnFire:false,autoUnmuteAfter:null,runtime:{lastTriggeredAtUtc:null,flashToken:0}}); -export function fakeState():AppState {const clock={raw:"01:24:16:00",display:"01:24:16:08",totalFrames:151688,frameRate:"30" as const,dropFrame:false,receivedAtMonotonicMs:0,nextCueId:"cue-2",framesUntilNextCue:112};return {sessionId:"fake-session",project:{displayName:"show_A.tcb3",filePath:null,dirty:false,canUndo:false,canRedo:false,recentFiles:[]},mode:"ltc",transport:{status:"receiving",statusText:"受信中",detailText:"CH 1 · 48 kHz",signalErrorRatePercent:0,locked:true,triggerMuted:false,autoMuteEnabled:false,autoMuteOnManualTrigger:false,autoMutedCueId:null,autoUnmuteAtUtc:null,lastLtcReceivedAtUtc:null},receive:{selectedDeviceId:"in",devices:[{id:"in",name:"UR44 — Input 1 / 2",loopback:false}],offset:"+00:00:00:08",triggerWindowFrames:3,freerunDurationSeconds:1},generator:{running:false,startTime:"01:00:00:00",loopEndTime:null,frameRate:"30",selectedOutputDeviceId:"out",outputDevices:[{id:"out",name:"UR44 — Output 1 / 2",loopback:false}],volume:.4,ltcOutputActive:false,settingsPendingReset:false},currentClock:clock,nextCue:{id:"cue-2",name:"タイトル OUT",triggerTime:"01:24:20:00",effectiveTriggerTime:"01:24:20:00",framesUntil:112},cues:[base("cue-1","本編 IN","01:23:40:00","/qlab/go"),base("cue-2","タイトル OUT","01:24:20:00","/video/title/out")],hosts:[{id:"qlab",name:"QLab — Main",ipAddress:"192.168.1.20",port:53000,enabled:true,reachability:"reachable"},{id:"reso",name:"Resolume — Stage",ipAddress:"192.168.1.31",port:7000,enabled:true,reachability:"reachable"}],cueSync:{oscAddress:"/cuesync",targetHostIds:["qlab","reso"]},triggerPanel:{rows:4,columns:4,buttons:[{id:"go",row:0,column:0,label:"GO",oscAddress:"/go",arguments:[],targetHostIds:["qlab"]}]},logs:[{id:"log-1",timestampUtc:new Date(Date.now()-1000).toISOString(),message:"fake-host を開始しました",success:true}],uiCapabilities:{supportsNativeOpenDialog:false,supportsNativeSaveDialog:false,platform:"macos"}}} +// 本物の Host は null の項目をキーごと省いて送る(Protocol.Json の WhenWritingNull)。偽 Host も同じ形で渡さないと、本番でだけ壊れる画面がテストを通ってしまう +const omitNulls=(_key:string,value:unknown)=>value===null?undefined:value; +const asHostSends=(value:T):T=>JSON.parse(JSON.stringify(value,omitNulls)); +export function fakeState():AppState {const clock={raw:"01:24:16:00",display:"01:24:16:08",totalFrames:151688,frameRate:"30" as const,dropFrame:false,receivedAtMonotonicMs:0,nextCueId:"cue-2",framesUntilNextCue:112};return asHostSends({sessionId:"fake-session",project:{displayName:"show_A.tcb3",filePath:null,dirty:false,canUndo:false,canRedo:false,recentFiles:[]},mode:"ltc",transport:{status:"receiving",statusText:"受信中",detailText:"CH 1 · 48 kHz",signalErrorRatePercent:0,locked:true,triggerMuted:false,autoMuteEnabled:false,autoMuteOnManualTrigger:false,autoMutedCueId:null,autoUnmuteAtUtc:null,lastLtcReceivedAtUtc:null},receive:{selectedDeviceId:"in",devices:[{id:"in",name:"UR44 — Input 1 / 2",loopback:false}],offset:"+00:00:00:08",triggerWindowFrames:3,freerunDurationSeconds:1},generator:{running:false,startTime:"01:00:00:00",loopEndTime:null,frameRate:"30",selectedOutputDeviceId:"out",outputDevices:[{id:"out",name:"UR44 — Output 1 / 2",loopback:false}],volume:.4,ltcOutputActive:false,settingsPendingReset:false},currentClock:clock,nextCue:{id:"cue-2",name:"タイトル OUT",triggerTime:"01:24:20:00",effectiveTriggerTime:"01:24:20:00",framesUntil:112},cues:[base("cue-1","本編 IN","01:23:40:00","/qlab/go"),base("cue-2","タイトル OUT","01:24:20:00","/video/title/out")],hosts:[{id:"qlab",name:"QLab — Main",ipAddress:"192.168.1.20",port:53000,enabled:true,reachability:"reachable"},{id:"reso",name:"Resolume — Stage",ipAddress:"192.168.1.31",port:7000,enabled:true,reachability:"reachable"}],cueSync:{oscAddress:"/cuesync",targetHostIds:["qlab","reso"]},triggerPanel:{rows:4,columns:4,buttons:[{id:"go",row:0,column:0,label:"GO",oscAddress:"/go",arguments:[],targetHostIds:["qlab"]}]},logs:[{id:"log-1",timestampUtc:new Date(Date.now()-1000).toISOString(),message:"fake-host を開始しました",success:true}],uiCapabilities:{supportsNativeOpenDialog:false,supportsNativeSaveDialog:false,platform:"macos"}})} export interface FakeHostHandle{dispose:()=>void} -export function installFakeHost():FakeHostHandle {let state=fakeState(),rev=1,seq=0,serial=10,active=true,timer:number|null=null;const emit=(m:HostMessage)=>queueMicrotask(()=>active&&window.tcb.receive(JSON.stringify(m)));const patch=(changes:Record)=>{const{logsAppend,logsReset,...replace}=changes;state={...state,...replace};if(logsReset)state.logs=logsReset;if(logsAppend)state.logs=[...state.logs,...logsAppend];emit({protocolVersion:1,type:"patch",baseRevision:rev,revision:++rev,changes})};const invoke=(json:string)=>{const m=JSON.parse(json) as WebMessage;if(m.type==="ready"||m.type==="resync"){emit({protocolVersion:1,type:"snapshot",revision:rev,state});if(timer===null)timer=window.setInterval(()=>emit({protocolVersion:1,type:"clock",seq:++seq,clock:{...state.currentClock,receivedAtMonotonicMs:performance.now()}}),100);return}if(m.type!=="command")return;const a=m.args as Record;const ok=(data?:unknown)=>emit({protocolVersion:1,type:"result",requestId:m.requestId,ok:true,data,revision:rev});const fail=(fieldErrors:Record)=>emit({protocolVersion:1,type:"result",requestId:m.requestId,ok:false,error:{code:"validation",message:"入力を確認してください",retryable:false,fieldErrors}});const log=(message:string,success=true)=>patch({logsAppend:[{id:`log-${++serial}`,timestampUtc:new Date().toISOString(),message,success}]}); +export function installFakeHost():FakeHostHandle {let state=fakeState(),rev=1,seq=0,serial=10,active=true,timer:number|null=null;const emit=(m:HostMessage)=>queueMicrotask(()=>active&&window.tcb.receive(JSON.stringify(m,omitNulls)));const patch=(changes:Record)=>{const{logsAppend,logsReset,...replace}=changes;state={...state,...replace};if(logsReset)state.logs=logsReset;if(logsAppend)state.logs=[...state.logs,...logsAppend];emit({protocolVersion:1,type:"patch",baseRevision:rev,revision:++rev,changes})};const invoke=(json:string)=>{const m=JSON.parse(json) as WebMessage;if(m.type==="ready"||m.type==="resync"){emit({protocolVersion:1,type:"snapshot",revision:rev,state});if(timer===null)timer=window.setInterval(()=>emit({protocolVersion:1,type:"clock",seq:++seq,clock:{...state.currentClock,receivedAtMonotonicMs:performance.now()}}),100);return}if(m.type!=="command")return;const a=m.args as Record;const ok=(data?:unknown)=>emit({protocolVersion:1,type:"result",requestId:m.requestId,ok:true,data,revision:rev});const fail=(fieldErrors:Record)=>emit({protocolVersion:1,type:"result",requestId:m.requestId,ok:false,error:{code:"validation",message:"入力を確認してください",retryable:false,fieldErrors}});const log=(message:string,success=true)=>patch({logsAppend:[{id:`log-${++serial}`,timestampUtc:new Date().toISOString(),message,success}]}); if(m.command==="mode.set"){const mode=a.mode,ltcStarted=mode==="ltc"&&Boolean(state.receive.selectedDeviceId);patch({mode,transport:{...state.transport,status:ltcStarted?"receiving":"stopped",statusText:ltcStarted?"受信中":mode==="ltc"?"停止中":"生成待機",locked:ltcStarted}});ok({ltcStarted});return} if(m.command==="ltc.stop"){patch({transport:{...state.transport,status:"stopped",statusText:"停止",locked:false}});ok();return} if(m.command==="receive.selectDevice"&&!(a.deviceId??"")){patch({receive:{...state.receive,selectedDeviceId:null},transport:{...state.transport,status:"stopped",statusText:"停止中",locked:false}});ok();return} @@ -12,7 +15,7 @@ export function installFakeHost():FakeHostHandle {let state=fakeState(),rev=1,se if(m.command==="ltc.start"||m.command==="ltc.reconnect"){patch({receive:{...state.receive,selectedDeviceId:a.deviceId??state.receive.selectedDeviceId},transport:{...state.transport,status:"receiving",statusText:"受信中",locked:true}});ok();return} if(m.command==="receive.setFreerunDuration"){patch({receive:{...state.receive,freerunDurationSeconds:Number(a.seconds)}});ok();return} if(m.command==="audio.refreshDevices"){patch(a.direction==="capture"?{receive:{...state.receive}}:{generator:{...state.generator}});ok();return} - if(m.command==="generator.configure"){patch({generator:{...state.generator,startTime:a.startTime,loopEndTime:a.loopEndTime??null,frameRate:a.frameRate,selectedOutputDeviceId:a.outputDeviceId||null,volume:a.volume,settingsPendingReset:state.generator.running}});ok();return} + if(m.command==="generator.configure"){patch({generator:{...state.generator,startTime:a.startTime??state.generator.startTime,loopEndTime:"loopEndTime" in a?a.loopEndTime||null:state.generator.loopEndTime??null,frameRate:a.frameRate,selectedOutputDeviceId:a.outputDeviceId||null,volume:a.volume,settingsPendingReset:state.generator.running}});ok();return} if(m.command==="generator.start"||m.command==="generator.stop"){const running=m.command.endsWith("start");patch({generator:{...state.generator,running,ltcOutputActive:running&&Boolean(state.generator.selectedOutputDeviceId),settingsPendingReset:false},transport:{...state.transport,status:running?"receiving":"stopped",statusText:running?"生成中":"停止"}});ok();return} if(m.command==="generator.reset"){patch({generator:{...state.generator,running:false,ltcOutputActive:false,settingsPendingReset:false},currentClock:{...state.currentClock,raw:state.generator.startTime,display:state.generator.startTime}});ok();return} if(m.command==="host.add"||m.command==="host.update"){const h=a.host,e={...(!h.name?{"host.name":"必須"}:{}),...(!h.ipAddress?{"host.ipAddress":"必須"}:{}),...(!(h.port>=1&&h.port<=65535)?{"host.port":"1〜65535"}:{})};if(Object.keys(e).length){fail(e);return}const id=m.command==="host.add"?`host-${++serial}`:String(a.id),host={id,name:h.name,ipAddress:h.ipAddress,port:h.port,enabled:h.enabled??true,reachability:"unknown"};patch({hosts:m.command==="host.add"?[...state.hosts,host]:state.hosts.map(x=>x.id===id?host:x)});ok({id});return} diff --git a/src/TimecodeBridge.Web/tests/generator-loop-panel.test.ts b/src/TimecodeBridge.Web/tests/generator-loop-panel.test.ts index 1411e93..2297450 100644 --- a/src/TimecodeBridge.Web/tests/generator-loop-panel.test.ts +++ b/src/TimecodeBridge.Web/tests/generator-loop-panel.test.ts @@ -13,9 +13,28 @@ test("the end field is hidden until the loop is turned on",()=>{ assert.doesNotMatch(html,/終了 TC/); }); +// Host は null の項目を JSON から省く(WhenWritingNull)。ループ無しの loopEndTime は null でなくキーごと無い +test("a generator state without loopEndTime renders with the loop off",()=>{ + const state=fakeState(); + const {loopEndTime:_omitted,...generator}=state.generator; + appStore.value.host.state=JSON.parse(JSON.stringify({...state,generator})); + const html=render(h(GeneratorPanel,{notice:()=>{}})); + assert.match(html,/ループ/); + assert.doesNotMatch(html,/終了 TC/); +}); + test("turning the loop on reveals the end field with the stored value",()=>{ const html=panel("08:00:30:00"); assert.match(html,/終了 TC/); assert.match(html,/value="08"/); assert.match(html,/value="30"/); + assert.doesNotMatch(html,/反映されません/); +}); + +// 開始 TC が終了 TC 以降の組み合わせは Host に送らない。画面で反映していないことを伝える +test("an end at or before the start is flagged as not applied",()=>{ + const state=fakeState(); + appStore.value.host.state={...state,generator:{...state.generator,startTime:"03:45:11:20",loopEndTime:"01:03:10:00"}}; + const html=render(h(GeneratorPanel,{notice:()=>{}})); + assert.match(html,/終了 TC を開始 TC より後にしてください/); }); diff --git a/src/TimecodeBridge.Web/tests/generator-loop.test.ts b/src/TimecodeBridge.Web/tests/generator-loop.test.ts index 9a71eb0..ea97a49 100644 --- a/src/TimecodeBridge.Web/tests/generator-loop.test.ts +++ b/src/TimecodeBridge.Web/tests/generator-loop.test.ts @@ -1,4 +1,4 @@ -import assert from "node:assert/strict";import test from "node:test";import {defaultLoopEnd} from "../src/generator-loop"; +import assert from "node:assert/strict";import test from "node:test";import {defaultLoopEnd,loopRangeValid} from "../src/generator-loop"; test("places the end ten seconds after the start",()=>{ assert.equal(defaultLoopEnd("08:00:00:00","30"),"08:00:10:00"); @@ -18,3 +18,16 @@ test("leaves an unparseable start alone",()=>{ assert.equal(defaultLoopEnd("","30"),""); assert.equal(defaultLoopEnd("おかしな値","30"),"おかしな値"); }); + +test("a loop range holds only when the end comes after the start",()=>{ + assert.equal(loopRangeValid("01:00:00:00","01:03:10:00"),true); + assert.equal(loopRangeValid("03:45:11:20","01:03:10:00"),false); + assert.equal(loopRangeValid("01:03:10:00","01:03:10:00"),false); + assert.equal(loopRangeValid("01:03:09:29","01:03:10:00"),true); + assert.equal(loopRangeValid("01:00:00;10","01:00:00;09"),false); +}); + +test("without a loop any start is fine, and unreadable values are left to the host",()=>{ + assert.equal(loopRangeValid("23:59:59:29",null),true); + assert.equal(loopRangeValid("","01:00:00:00"),true); +}); diff --git a/src/TimecodeBridge.Web/tests/protocol.test.ts b/src/TimecodeBridge.Web/tests/protocol.test.ts index b2e7c19..4e204a0 100644 --- a/src/TimecodeBridge.Web/tests/protocol.test.ts +++ b/src/TimecodeBridge.Web/tests/protocol.test.ts @@ -1,3 +1,5 @@ import assert from "node:assert/strict";import test from "node:test";import {isHostMessage,parseHostMessage} from "../src/protocol";import {fakeState} from "../src/testing/fake-host"; test("accepts valid envelopes and rejects malformed input",()=>{assert.equal(isHostMessage({protocolVersion:1,type:"snapshot",revision:1,state:fakeState()}),true);assert.equal(isHostMessage({protocolVersion:2,type:"clock",seq:1,clock:{}}),false);assert.equal(parseHostMessage("{"),null)}); test("validates clock and wave payloads",()=>{assert.equal(isHostMessage({protocolVersion:1,type:"clock",seq:1,clock:fakeState().currentClock}),true);assert.equal(isHostMessage({protocolVersion:1,type:"wave",seq:1,wave:{sampleRate:48000,windowMs:100,min:[-.2],max:[.2],levelDbfs:-12.5}}),true);assert.equal(isHostMessage({protocolVersion:1,type:"wave",seq:1,wave:{sampleRate:48000,windowMs:100,min:["x"],max:[],levelDbfs:null}}),false)}); +// 無音(ピーク 0)だと Host は levelDbfs を null にし、null の項目は JSON から省く。これを捨てると波形が最後の形のまま止まる +test("accepts a silent wave whose level the Host left out",()=>{assert.equal(isHostMessage(JSON.parse('{"protocolVersion":1,"type":"wave","seq":1,"wave":{"sampleRate":48000,"windowMs":100,"min":[0],"max":[0]}}')),true)}); diff --git a/src/TimecodeBridge.Web/tests/timecode-input.test.ts b/src/TimecodeBridge.Web/tests/timecode-input.test.ts index c041c5f..76e1664 100644 --- a/src/TimecodeBridge.Web/tests/timecode-input.test.ts +++ b/src/TimecodeBridge.Web/tests/timecode-input.test.ts @@ -1,6 +1,6 @@ import assert from "node:assert/strict"; import test from "node:test"; -import {clampTimecode,clampTimecodePart,enterTimecodeDigits,joinTimecode,normalizeTimecodeDigits,splitTimecode,timecodeFocusForKey} from "../src/components/timecode-input"; +import {clampTimecode,clampTimecodePart,enterTimecodeDigits,joinTimecode,normalizeTimecodeDigits,selectTimecodePartOnMouseDown,splitTimecode,timecodeFocusForKey} from "../src/components/timecode-input"; test("normalizes full-width digits and discards every other character",()=>{ assert.equal(normalizeTimecodeDigits("12a3:四4"),"1234"); @@ -38,3 +38,17 @@ test("clampTimecode limits every field to the frame rate and keeps the sign",()= assert.equal(clampTimecode("","24"),""); assert.equal(clampTimecode("00:00:00:29","29.97df"),"00:00:00:29"); }); + + +// 埋まった欄を 1 回クリックして打っても変わらなかった(2026-10-26 Windows 実機)。クリックで 2 桁を選べば打った数字で置き換わる +test("a left click on a TC field selects both digits instead of placing the caret",()=>{ + const calls:string[]=[],input={focus:()=>calls.push("focus"),select:()=>calls.push("select")}; + let prevented=false; + selectTimecodePartOnMouseDown({button:0,preventDefault:()=>{prevented=true}},input); + assert.equal(prevented,true); + assert.deepEqual(calls,["focus","select"]); + calls.length=0;prevented=false; + selectTimecodePartOnMouseDown({button:2,preventDefault:()=>{prevented=true}},input); + assert.equal(prevented,false); + assert.deepEqual(calls,[]); +}); diff --git a/tests/TimecodeBridge.Host.Tests/GeneratorLoopCommandTests.cs b/tests/TimecodeBridge.Host.Tests/GeneratorLoopCommandTests.cs index 1cc3115..4340795 100644 --- a/tests/TimecodeBridge.Host.Tests/GeneratorLoopCommandTests.cs +++ b/tests/TimecodeBridge.Host.Tests/GeneratorLoopCommandTests.cs @@ -72,6 +72,45 @@ private static HostHarness Started() Assert.Null(h.State.Generator.LoopEndTime); } + // Web は入力のたびに開始 TC と終了 TC を両方送る。弾いたのに開始 TC だけ書き換わると、終了が開始より前のループが残っていた + [Fact] + public void 開始TCが終了TC以降になる組み合わせは弾いて何も変えない() + { + var h = new HostHarness(); + h.Run("generator.configure", """{"startTime":"01:00:00:00","loopEndTime":"01:03:10:00","frameRate":"30"}"""); + + var result = h.Run("generator.configure", """{"startTime":"03:45:11:20","loopEndTime":"01:03:10:00","frameRate":"30"}"""); + + Assert.Equal(ErrorCode.Validation, result.Error!.Code); + Assert.Equal("01:00:00:00", h.State.Generator.StartTime.ToString()); + Assert.Equal("01:03:10:00", h.State.Generator.LoopEndTime!.Value.ToString()); + } + + [Fact] + public void 新しいレートにない開始TCはレートごと弾く() + { + var h = Started(); + h.Run("generator.configure", """{"startTime":"08:00:00:29"}"""); + + var result = h.Run("generator.configure", """{"startTime":"08:00:00:29","frameRate":"24"}"""); + + Assert.Equal(ErrorCode.Validation, result.Error!.Code); + Assert.Equal(FrameRate.Fps30, h.State.Generator.FrameRate); + Assert.Equal("08:00:00:29", h.State.Generator.StartTime.ToString()); + } + + [Fact] + public void 音量が範囲外なら一緒に送った開始TCとループも変えない() + { + var h = Started(); + + var result = h.Run("generator.configure", """{"startTime":"09:00:00:00","loopEndTime":"09:00:30:00","volume":2}"""); + + Assert.Equal(ErrorCode.Validation, result.Error!.Code); + Assert.Equal("08:00:00:00", h.State.Generator.StartTime.ToString()); + Assert.Null(h.State.Generator.LoopEndTime); + } + [Fact] public void フレームレートを下げると終了TCのフレーム番号を丸める() { diff --git a/tools/tcb3/smoke-windows.ps1 b/tools/tcb3/smoke-windows.ps1 index 784ce31..cb2076b 100644 --- a/tools/tcb3/smoke-windows.ps1 +++ b/tools/tcb3/smoke-windows.ps1 @@ -134,6 +134,13 @@ try { if ($s.logs | Where-Object { $_.success -and $_.message -like '/smoke/manual*' }) { Ok '送信ログに成功が残る' } else { Ng '送信ログに /smoke/manual がありません' } if ((Eval $Port "document.body.innerText.includes('smoke-manual')") -eq 'true') { Ok 'キューが画面に出ている' } else { Ng 'キューが画面に出ていません' } + # 内部生成へ切り替えて生成パネルが描かれるか。v3.2.0〜v3.2.1 は生成パネルの描画が例外で止まり、以後画面が一切更新されなかった + [void](Cmd $Port mode.set @{ mode = 'generate' }) + $deadline = (Get-Date).AddSeconds(5) + do { Start-Sleep -Milliseconds 250; $shown = Eval $Port "document.body.innerText.includes('内部生成設定') && document.body.innerText.includes('LTC GENERATOR')" } while ($shown -ne 'true' -and (Get-Date) -lt $deadline) + if ($shown -eq 'true') { Ok '内部生成に切り替えると生成パネルが出る' } else { Ng '内部生成に切り替えても生成パネルが出ない(画面が更新されていない)' } + [void](Cmd $Port mode.set @{ mode = 'ltc' }) + if ($LoopbackDevice) { # 2 つ目の Host で LTC を生成してその出力へ流し、1 つ目はその出力のループバック取り込みで受ける $gen = Start-Host ($Port + 1) 'gen'