export const realtimeChartsSource = " function drawTraffic(down, up){\n // Note: Live traffic rendering is throttled to animation frames to keep frequent socket updates smooth.\n traffic.push({down:Number(down||0), up:Number(up||0)});\n if(traffic.length>90) traffic.shift();\n if(drawTraffic.raf) return;\n drawTraffic.raf=requestAnimationFrame(()=>{\n drawTraffic.raf=0;\n const c=$('trafficChart');\n if(!c) return;\n const rect=c.getBoundingClientRect();\n const dpr=window.devicePixelRatio||1;\n const cssW=Math.max(120, Math.floor(rect.width||c.width||300));\n const cssH=Math.max(32, Math.floor(rect.height||c.height||80));\n if(c.width!==Math.floor(cssW*dpr) || c.height!==Math.floor(cssH*dpr)){\n c.width=Math.floor(cssW*dpr);\n c.height=Math.floor(cssH*dpr);\n }\n const ctx=c.getContext('2d');\n ctx.setTransform(dpr,0,0,dpr,0,0);\n ctx.clearRect(0,0,cssW,cssH);\n const max=Math.max(1,...traffic.map(p=>Math.max(p.down,p.up)));\n const pad=3;\n const drawSeries=(key,color)=>{\n ctx.beginPath();\n traffic.forEach((p,i)=>{\n const x=pad+i*((cssW-pad*2)/Math.max(1,traffic.length-1));\n const y=cssH-pad-(Number(p[key]||0)/max)*(cssH-pad*2);\n i?ctx.lineTo(x,y):ctx.moveTo(x,y);\n });\n ctx.lineWidth=1.75;\n ctx.lineJoin='round';\n ctx.lineCap='round';\n ctx.strokeStyle=color;\n ctx.stroke();\n };\n ctx.fillStyle='rgba(148,163,184,.12)';\n ctx.fillRect(0,0,cssW,cssH);\n drawSeries('down','#38bdf8');\n drawSeries('up','#f59e0b');\n });\n }\n function drawSystemUsage(cpu,ram){\n const c=$('systemChart'); if(!c) return;\n const cpuVal=Math.max(0,Math.min(100,Number(cpu||0)));\n const ramVal=Math.max(0,Math.min(100,Number(ram||0)));\n systemUsage.push({cpu:cpuVal,ram:ramVal}); if(systemUsage.length>60) systemUsage.shift();\n const ctx=c.getContext('2d'), w=c.width, h=c.height; ctx.clearRect(0,0,w,h);\n ctx.fillStyle='rgba(148,163,184,.18)'; ctx.fillRect(0,0,w,h);\n ctx.beginPath(); systemUsage.forEach((p,i)=>{const x=i*(w/Math.max(1,systemUsage.length-1)), y=h-(p.cpu/100)*h; i?ctx.lineTo(x,y):ctx.moveTo(x,y);}); ctx.strokeStyle='#a78bfa'; ctx.stroke();\n ctx.beginPath(); systemUsage.forEach((p,i)=>{const x=i*(w/Math.max(1,systemUsage.length-1)), y=h-(p.ram/100)*h; i?ctx.lineTo(x,y):ctx.moveTo(x,y);}); ctx.strokeStyle='#22c55e'; ctx.stroke();\n c.title=`CPU ${cpuVal.toFixed(1)}% / RAM ${ramVal.toFixed(1)}%`;\n }\n async function refreshUserDiskUsage(force=false){\n // Note: Profile switches force a fresh no-store disk read and ignore older in-flight responses.\n const now=Date.now();\n if(userDiskFetchInFlight && !force) return;\n if(!force && now-lastUserDiskFetchAt<15000) return;\n const seq=++userDiskFetchSeq;\n userDiskFetchInFlight=true;\n try{\n const res=await fetch(`/api/system/disk?_=${Date.now()}`, {cache:'no-store'});\n const json=await res.json();\n if(seq!==userDiskFetchSeq) return;\n if(json.ok && json.disk){\n lastUserDiskFetchAt=Date.now();\n drawDiskUsage(json.disk);\n }\n }catch(_){\n }finally{\n if(seq===userDiskFetchSeq) userDiskFetchInFlight=false;\n }\n }\n\n function diskUsageTooltip(disk){\n // Note: The footer tooltip explains the active disk source and every monitored path.\n const mode=disk.mode==='aggregate'?'Aggregate':disk.mode==='selected'?'Selected path':'Default rTorrent path';\n const lines=[mode, `Used: ${disk.used_h||'-'} / ${disk.total_h||'-'}`, `Free: ${disk.free_h||'-'}`];\n if(disk.path && disk.path!=='aggregate') lines.unshift(`Path: ${disk.path}`);\n if(disk.fallback) lines.push(`Measured on: ${disk.source_path||'-'}`);\n const paths=Array.isArray(disk.paths)?disk.paths:[];\n if(paths.length){\n lines.push('', 'Monitored paths:');\n paths.forEach(p=>{\n const marker=(disk.mode==='selected' && p.path===disk.path) ? '*' : '+';\n const measured=p.fallback && p.source_path ? `, measured on ${p.source_path}` : '';\n const pct=Number(p.percent||0);\n const shownPct=Number.isFinite(pct)?pct.toFixed(pct%1?1:0):'0';\n const status=p.ok ? `${shownPct}% used, ${p.free_h||'-'} free${measured}` : `unavailable${p.error?`: ${p.error}`:''}`;\n lines.push(`${marker} ${p.path}: ${status}`);\n });\n }\n return lines.join('\\n');\n }\n\n function drawDiskUsage(disk){\n const box=$('diskStatus'), label=$('statDisk'), c=$('diskChart');\n if(!box||!label||!c)return;\n const ctx=c.getContext('2d'), w=c.width, h=c.height;\n ctx.clearRect(0,0,w,h);\n const ok=disk&&disk.ok;\n const pct=ok?Math.max(0,Math.min(100,Number(disk.percent||0))):0;\n label.textContent=ok?`${pct.toFixed(pct%1?1:0)}%`:'-';\n box.classList.toggle('disk-warn', !ok || pct>=90);\n box.title=ok?diskUsageTooltip(disk):`Disk usage unavailable${disk?.error?`\n${disk.error}`:''}`;\n ctx.fillStyle='rgba(148,163,184,.22)'; ctx.fillRect(0,5,w,14);\n ctx.fillStyle=pct>=90?'#ef4444':pct>=75?'#f59e0b':'#22c55e'; ctx.fillRect(0,5,Math.round(w*pct/100),14);\n ctx.strokeStyle='rgba(148,163,184,.55)'; ctx.strokeRect(.5,5.5,w-1,13);\n }\n";