import { useState, useEffect, useRef } from "react"; import {Howl, Howler} from 'howler'; import { invoke } from "@tauri-apps/api/core"; import { listen } from '@tauri-apps/api/event'; import "./App.css"; import { OSC_ADDRESS } from "./utils/constant"; const DefaultFadeDuration = 3; // 1 second const CLIENT_COUNT=12; const CueType={ Bg: 'bg', Announce: 'announce', Light: 'light' } const EmojiType={ bg: '🎵', announce: '📢', light: '💡' } function App() { const [cuelist, setCuelist] = useState([]); const [currentCue, setCurrentCue] = useState(null); const [fadeDuration, setFadeDuration] = useState(DefaultFadeDuration); // Default fade duration in seconds const [timestamp, setTimestamp] = useState(); const [clientStatus, setClientStatus] = useState({}); const refCue = useRef(null); const refNextCue = useRef(null); function sendOsc(addr, message, id){ invoke('send_osc_message', { key: addr, message: `${id}#${message}`, host:'0.0.0.0:0', target:'192.168.234.255:8000', }); } function sendOscToSound(addr, message){ invoke('send_osc_message', { key: addr, message, host:'0.0.0.0:0', target:'192.168.234.255:58100', }); } function onOsc(message){ const [id, status, name]= message.args[0]?.split('#'); if(clientStatus[id]){ setClientStatus(prev=>({ ...prev, [id]:[ { status, name, timestamp: new Date().toLocaleTimeString(), }, ...prev[id], ] })); }else{ setClientStatus(prev=>({ ...prev, [id]:[{ status, name, timestamp: new Date().toLocaleTimeString(), }] })); } } function playCue({id, name, description, type, auto, audioFile, ...props}) { console.log('Playing cue:', {id, name, description, type, auto, audioFile, ...props}); // Handle other cue types and properties here if(props.audioCue){ sendOscToSound(OSC_ADDRESS.SCS_GO_CUE, props.audioCue); } if(props.clientCue){ sendOsc(OSC_ADDRESS.PLAYCUE, props.clientCue,'all'); } if(props.lightCue){ // sendOsc(OSC_ADDRESS.CLIENT_INPUT, props.lightCue); } } function stop() { console.log('Stop all'); sendOsc(OSC_ADDRESS.STOPCUE,'','all'); sendOscToSound(OSC_ADDRESS.SCS_STOP_ALL, ''); } function secondToTime(seconds) { const minutes = Math.floor(seconds / 60); const secs = Math.floor(seconds % 60); return `${minutes}:${secs < 10 ? '0' : ''}${secs}`; } function getAudioDuration(){ const type= refCue.current?.type; // console.log('getAudioDuration', type, refCue.current); // switch(type) { // case CueType.Bg: if(refAudioBg.current) { return `${secondToTime(refAudioBg.current.seek())} / ${secondToTime(refAudioBg.current.duration())} ${refAudioBg.current?.volume()}`; } else { return 'N/A'; } // case CueType.Announce: // return refAudioAnnounce.current ? `${secondToTime(refAudioAnnounce.current.seek())} / ${secondToTime(refAudioAnnounce.current.duration())}` : 'N/A'; // default: // return 'N/A'; // } } useEffect(()=>{ if(currentCue) { refCue.current = currentCue; // console.log('Current Cue:', currentCue); } },[currentCue]); useEffect(()=>{ fetch('/cuelist.json') .then(response => response.json()) .then(data => { console.log('Cuelist data:', data); setCuelist(data.cuelist); }) .catch(error => { console.error('Error fetching cuelist:', error); }); listen('osc_message', (event) => { console.log(`Received OSC message: ${event.payload}`); onOsc(event.payload); }); },[]); return (
{currentCue ? `${currentCue.name}` : 'None'}

{timestamp}

{ const value = parseFloat(e.target.value); setFadeDuration(value); }}> {fadeDuration}s
{/* */} {cuelist?.map(({id, name, description, type, auto,...props}, index) => ( ))}
ID Name Description Type Auto Due | Light | Audio clientCue
{type==CueType.Announce && } {name} {description} {EmojiType[type]} {auto ? '⤵️' : ''} {props.duration} {props.lightCue && `L${props.lightCue}`} {props.audioCue && `S${props.audioCue}`} {props.clientCue || ''}
{Array.from(Array(CLIENT_COUNT).keys()).map((i) => { const id=i+1; const log = clientStatus[id]; return ( {<> } ); })}
id status cue timestamp control
{id}{log?.length>0 &&log[0]?.status} {log?.length>0 && log[0]?.name} {log?.length>0 &&log[0]?.timestamp} {cuelist?.filter(c=>c.clientCue).map(c=>( ))}
); } export default App;