const CMD='/data/adb/modules/virtualcam/control.sh';
let lc=0, _ps='', _pp=0, _pf=0;
function log(m,t){const e=document.getElementById('console');if(!e)return;const d=new Date();e.innerHTML+=`
[${d.toLocaleTimeString()}] ${m}
`;e.scrollTop=e.scrollHeight;lc++;const l=document.getElementById('log-count');if(l)l.textContent=`(${lc})`}
function run(a){try{ksu.exec(CMD+' '+a);log(a+' OK','ok')}catch(e){log(a+' error: '+e.message,'err')}updateDash()}
function updateDash(){try{
const r=typeof ksu!=='undefined'?ksu.exec(CMD+' status'):null;
if(!r||typeof r!=='string'){document.getElementById('status-dash').innerHTML='No data
';return}
const s=JSON.parse(r);
const d=document.getElementById('status-dash');if(!d)return;
const colorMap={active:'green',partial:'yellow',stopped:'red',idle:'red'};
const sc=colorMap[s.status]||'yellow';
const st=s.status.toUpperCase();
d.innerHTML=[['Status',sc,st],['Provider',s.provider_pid>0?'green':'red',s.provider_pid>0?'PID '+s.provider_pid:'Stopped'],['Feeder',s.feeder_pid>0?'green':'red',s.feeder_pid>0?'PID '+s.feeder_pid:'Stopped'],['Service',s.service_registered==1?'green':'red',s.service_registered==1?'Registered':'Missing'],['v4l2',s.v4l2_loaded==1?'green':'red',s.v4l2_loaded==1?'Loaded':'Missing'],['Device','yellow',s.video0||'N/A']].map(i=>`${i[0]}${i[2]}
`).join('');
document.getElementById('subtitle').textContent=s.status==='active'?'Physical cameras replaced':s.status==='partial'?'Starting up...':'Not running';
// Toggle buttons based on state
document.getElementById('btn-start').style.display=s.provider_pid>0?'none':'block';
document.getElementById('btn-stop').style.display=s.provider_pid>0?'block':'none';
document.getElementById('btn-restart').style.display=s.provider_pid>0?'block':'none';
document.getElementById('btn-feed').style.display=s.feeder_pid>0?'none':'block';
document.getElementById('btn-unfeed').style.display=s.feeder_pid>0?'block':'none';
if(s.status!==_ps||s.provider_pid!==_pp||s.feeder_pid!==_pf){_ps=s.status;_pp=s.provider_pid;_pf=s.feeder_pid;log('Status: '+st+' pid='+s.provider_pid+' feeder='+s.feeder_pid,'ok')}
}catch(e){log('Dash error: '+e.message,'err')}}
document.getElementById('btn-start')?.addEventListener('click',()=>run('start'));
document.getElementById('btn-stop')?.addEventListener('click',()=>run('stop'));
document.getElementById('btn-restart')?.addEventListener('click',()=>run('restart'));
document.getElementById('btn-feed')?.addEventListener('click',()=>run('start_feeder'));
document.getElementById('btn-unfeed')?.addEventListener('click',()=>run('stop_feeder'));
document.getElementById('btn-refresh')?.addEventListener('click',updateDash);
document.getElementById('btn-save')?.addEventListener('click',()=>{
const src=document.querySelector('.src-btn.active')?.dataset.src||'mp4';
const json=JSON.stringify({source_type:src,rtsp_url:document.getElementById('rtsp-url').value,tcp_url:document.getElementById('tcp-url').value,mp4_path:document.getElementById('mp4-path').value,res_w:parseInt(document.getElementById('res-w').value)||1920,res_h:parseInt(document.getElementById('res-h').value)||1080,fps:parseInt(document.getElementById('fps').value)||30,rotation:parseInt(document.getElementById('rotation').value)||0});
ksu.exec("echo '"+json+"' > /data/local/tmp/virtualcam_config.json");
log('Config saved','ok');
// Restart feeder with new config if running
try {
const st = JSON.parse(ksu.exec(CMD+' status')||'{}');
if (st.feeder_pid > 0) {
ksu.exec(CMD+' stop_feeder');
setTimeout(function(){ksu.exec(CMD+' start_feeder');log('Feeder restarted','ok');},2000);
}
} catch(e) {}
});
document.querySelectorAll('.src-btn').forEach(b=>b.addEventListener('click',()=>{
document.querySelectorAll('.src-btn').forEach(x=>x.classList.remove('active'));
b.classList.add('active');
document.getElementById('rtsp-config').classList.toggle('hidden',b.dataset.src!=='rtsp');
document.getElementById('tcp-config').classList.toggle('hidden',b.dataset.src!=='tcp');
document.getElementById('mp4-config').classList.toggle('hidden',b.dataset.src!=='mp4');
}));
// Load saved config into UI fields
try {
const cfg = JSON.parse(ksu.exec(CMD+' get_config')||'{}');
if (cfg.source_type) {
document.querySelectorAll('.src-btn').forEach(b => b.classList.toggle('active', b.dataset.src === cfg.source_type));
document.getElementById('rtsp-config').classList.toggle('hidden', cfg.source_type !== 'rtsp');
document.getElementById('tcp-config').classList.toggle('hidden', cfg.source_type !== 'tcp');
document.getElementById('mp4-config').classList.toggle('hidden', cfg.source_type !== 'mp4');
}
if (cfg.rtsp_url) document.getElementById('rtsp-url').value = cfg.rtsp_url;
if (cfg.tcp_url) document.getElementById('tcp-url').value = cfg.tcp_url;
if (cfg.mp4_path) document.getElementById('mp4-path').value = cfg.mp4_path;
if (cfg.res_w) document.getElementById('res-w').value = cfg.res_w;
if (cfg.res_h) document.getElementById('res-h').value = cfg.res_h;
if (cfg.fps) document.getElementById('fps').value = cfg.fps;
if (cfg.rotation) document.getElementById('rotation').value = cfg.rotation;
} catch(e) {}
updateDash();
setInterval(updateDash,5000);