glintbar 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- glintbar/__init__.py +3 -0
- glintbar/__main__.py +6 -0
- glintbar/away.html +69 -0
- glintbar/detail.html +88 -0
- glintbar/monitor.py +1282 -0
- glintbar/settings.html +144 -0
- glintbar/ui.html +205 -0
- glintbar-1.0.0.dist-info/METADATA +242 -0
- glintbar-1.0.0.dist-info/RECORD +13 -0
- glintbar-1.0.0.dist-info/WHEEL +5 -0
- glintbar-1.0.0.dist-info/entry_points.txt +2 -0
- glintbar-1.0.0.dist-info/licenses/LICENSE +21 -0
- glintbar-1.0.0.dist-info/top_level.txt +1 -0
glintbar/__init__.py
ADDED
glintbar/__main__.py
ADDED
glintbar/away.html
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<meta charset="utf-8">
|
|
2
|
+
<style>
|
|
3
|
+
:root{ --bg:#12161c; --line:#2b3542; --text:#e6edf3; --dim:#9aa4af;
|
|
4
|
+
--ok:#58a6ff; --warn:#d29922; --crit:#f85149; }
|
|
5
|
+
*{ box-sizing:border-box; margin:0; padding:0; }
|
|
6
|
+
html,body{ height:100%; }
|
|
7
|
+
body{ background:transparent; color:var(--text);
|
|
8
|
+
font:12px/1.35 "Segoe UI",system-ui,sans-serif; overflow:hidden; }
|
|
9
|
+
.card{ height:100vh; background:var(--bg); border:1px solid var(--line);
|
|
10
|
+
border-radius:10px; padding:12px 14px; box-shadow:0 8px 26px #000a;
|
|
11
|
+
display:flex; flex-direction:column; }
|
|
12
|
+
.hdr{ font-size:14px; font-weight:700; }
|
|
13
|
+
.sub{ font-size:11px; color:var(--dim); margin:1px 0 10px; }
|
|
14
|
+
.row{ display:flex; justify-content:space-between; font-size:12px; padding:2px 0; }
|
|
15
|
+
.row .k{ color:var(--dim); }
|
|
16
|
+
.row .v{ font-weight:600; font-variant-numeric:tabular-nums; }
|
|
17
|
+
.v.hot{ color:var(--crit); }
|
|
18
|
+
.lbl{ font-size:10px; text-transform:uppercase; letter-spacing:.06em;
|
|
19
|
+
color:var(--dim); margin:10px 0 4px; }
|
|
20
|
+
.proc{ display:flex; justify-content:space-between; font-size:12px; padding:2px 0;
|
|
21
|
+
border-top:1px solid #ffffff10; }
|
|
22
|
+
.proc .p{ overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
23
|
+
.proc .c{ color:var(--warn); font-weight:600; font-variant-numeric:tabular-nums;
|
|
24
|
+
padding-left:8px; }
|
|
25
|
+
.actions{ display:flex; gap:8px; margin-top:auto; padding-top:10px; }
|
|
26
|
+
.actions button{ flex:1; padding:7px; border-radius:6px; font-size:12px; cursor:pointer;
|
|
27
|
+
border:1px solid var(--line); background:#1b2430; color:var(--text); }
|
|
28
|
+
.actions .go{ border-color:var(--ok); color:var(--ok); }
|
|
29
|
+
</style>
|
|
30
|
+
|
|
31
|
+
<div class="card">
|
|
32
|
+
<div class="hdr">While you were away</div>
|
|
33
|
+
<div class="sub" id="sub">—</div>
|
|
34
|
+
<div class="row"><span class="k">Peak CPU</span><span class="v" id="cpu">—</span></div>
|
|
35
|
+
<div class="row"><span class="k">Peak system temp</span><span class="v" id="temp">—</span></div>
|
|
36
|
+
<div class="lbl">Busiest processes</div>
|
|
37
|
+
<div id="procs"></div>
|
|
38
|
+
<div class="actions">
|
|
39
|
+
<button id="logs">Open log</button>
|
|
40
|
+
<button class="go" id="dismiss">Got it</button>
|
|
41
|
+
</div>
|
|
42
|
+
</div>
|
|
43
|
+
|
|
44
|
+
<script>
|
|
45
|
+
async function tick(){
|
|
46
|
+
let r; try{ r = await window.pywebview.api.get(); }catch(e){ return; }
|
|
47
|
+
if(!r) return;
|
|
48
|
+
document.getElementById("sub").textContent = `${r.when}, away for ${r.duration_min} min`;
|
|
49
|
+
const cpu = document.getElementById("cpu");
|
|
50
|
+
cpu.textContent = r.peak_cpu + "%"; cpu.className = "v" + (r.peak_cpu >= 60 ? " hot" : "");
|
|
51
|
+
const temp = document.getElementById("temp");
|
|
52
|
+
temp.textContent = r.peak_temp ? r.peak_temp + " °C" : "n/a";
|
|
53
|
+
temp.className = "v" + (r.peak_temp >= 90 ? " hot" : "");
|
|
54
|
+
const host = document.getElementById("procs"); host.innerHTML = "";
|
|
55
|
+
const list = r.offenders || [];
|
|
56
|
+
if(list.length){
|
|
57
|
+
for(const [name, c] of list){
|
|
58
|
+
const d = document.createElement("div"); d.className = "proc";
|
|
59
|
+
d.innerHTML = `<span class="p">${name}</span><span class="c">${c}%</span>`;
|
|
60
|
+
host.appendChild(d);
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
63
|
+
host.innerHTML = `<div class="proc"><span class="p">nothing stood out</span></div>`;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
document.getElementById("logs").onclick = ()=> window.pywebview.api.open_logs();
|
|
67
|
+
document.getElementById("dismiss").onclick = ()=> window.pywebview.api.dismiss();
|
|
68
|
+
window.addEventListener("pywebviewready", ()=>{ tick(); setInterval(tick, 1000); });
|
|
69
|
+
</script>
|
glintbar/detail.html
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
<meta charset="utf-8">
|
|
2
|
+
<style>
|
|
3
|
+
:root{ --bg:#12161c; --line:#2b3542; --text:#e6edf3; --dim:#9aa4af;
|
|
4
|
+
--ok:#58a6ff; --warn:#d29922; --crit:#f85149; }
|
|
5
|
+
*{ box-sizing:border-box; margin:0; padding:0; }
|
|
6
|
+
html,body{ height:100%; }
|
|
7
|
+
body{ background:transparent; color:var(--text);
|
|
8
|
+
font:12px/1.2 "Segoe UI",system-ui,sans-serif; overflow:hidden; }
|
|
9
|
+
.card{ height:100vh; background:var(--bg); border:1px solid var(--line);
|
|
10
|
+
border-radius:10px; padding:9px 11px; box-shadow:0 6px 22px #000a; }
|
|
11
|
+
.top{ display:flex; justify-content:space-between; align-items:baseline; }
|
|
12
|
+
.lbl{ font-size:11px; text-transform:uppercase; letter-spacing:.06em; color:var(--dim); }
|
|
13
|
+
.val{ font-size:22px; font-weight:700; font-variant-numeric:tabular-nums; }
|
|
14
|
+
.val .u{ font-size:12px; color:var(--dim); font-weight:400; }
|
|
15
|
+
.stats{ font-size:11px; color:var(--dim); margin-top:1px; }
|
|
16
|
+
canvas{ width:100%; height:96px; margin-top:6px; display:block; }
|
|
17
|
+
.val.ok{ color:var(--text); } .val.warn{ color:var(--warn); } .val.crit{ color:var(--crit); }
|
|
18
|
+
</style>
|
|
19
|
+
<div class="card">
|
|
20
|
+
<div class="top"><span class="lbl" id="lbl">—</span>
|
|
21
|
+
<span class="val ok" id="val">—</span></div>
|
|
22
|
+
<div class="stats" id="stats"></div>
|
|
23
|
+
<canvas id="cv" width="600" height="220"></canvas>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<script>
|
|
27
|
+
const META = {
|
|
28
|
+
gpu_temp:{lbl:"GPU Temperature",unit:"°C",warn:80,crit:87,max:100},
|
|
29
|
+
gpu_util:{lbl:"GPU Load",unit:"%",warn:1e9,crit:1e9,max:100},
|
|
30
|
+
gpu_mem_pct:{lbl:"VRAM Used",unit:"%",warn:85,crit:95,max:100},
|
|
31
|
+
gpu_power:{lbl:"GPU Power",unit:"W",warn:1e9,crit:1e9,max:130},
|
|
32
|
+
gpu_clock:{lbl:"GPU Clock",unit:"MHz",warn:1e9,crit:1e9,max:2200},
|
|
33
|
+
sys_temp:{lbl:"System Temp (ACPI zone)",unit:"°C",warn:85,crit:97,max:110},
|
|
34
|
+
cpu_temp:{lbl:"CPU Temperature",unit:"°C",warn:85,crit:97,max:110},
|
|
35
|
+
fan_rpm:{lbl:"Fan Speed",unit:"RPM",warn:1e9,crit:1e9,max:6000},
|
|
36
|
+
cpu:{lbl:"CPU Load",unit:"%",warn:85,crit:95,max:100},
|
|
37
|
+
ram_pct:{lbl:"RAM Used",unit:"%",warn:85,crit:95,max:100},
|
|
38
|
+
net_mbps:{lbl:"Network",unit:"MB/s",warn:1e9,crit:1e9,max:50,dyn:true},
|
|
39
|
+
disk_mbps:{lbl:"Disk",unit:"MB/s",warn:1e9,crit:1e9,max:200,dyn:true},
|
|
40
|
+
};
|
|
41
|
+
function cls(m,v){ if(v==null)return"ok"; if(v>=m.crit)return"crit"; if(v>=m.warn)return"warn"; return"ok"; }
|
|
42
|
+
function fmt(v,id){ if(v==null)return"—";
|
|
43
|
+
if(id==="net_mbps"||id==="disk_mbps"||id==="gpu_power")return v.toFixed(1); return Math.round(v); }
|
|
44
|
+
function gv(n){ return getComputedStyle(document.documentElement).getPropertyValue(n).trim(); }
|
|
45
|
+
function color(c){ return c==="crit"?gv("--crit"):c==="warn"?gv("--warn"):gv("--ok"); }
|
|
46
|
+
|
|
47
|
+
function draw(cv,data,m,colr){
|
|
48
|
+
const ctx=cv.getContext("2d"), w=cv.width, h=cv.height, pad=6;
|
|
49
|
+
ctx.clearRect(0,0,w,h);
|
|
50
|
+
// baseline grid
|
|
51
|
+
ctx.strokeStyle="#ffffff14"; ctx.lineWidth=1;
|
|
52
|
+
for(let i=0;i<=2;i++){ const y=pad+(h-2*pad)*i/2; ctx.beginPath(); ctx.moveTo(0,y); ctx.lineTo(w,y); ctx.stroke(); }
|
|
53
|
+
if(!data.length) return;
|
|
54
|
+
let top = m.dyn ? Math.max(...data,1)*1.2 : m.max;
|
|
55
|
+
const n=data.length, sx=w/Math.max(n-1,1);
|
|
56
|
+
ctx.beginPath();
|
|
57
|
+
data.forEach((v,i)=>{ const y=h-pad-(Math.min((v==null?0:v),top)/top)*(h-2*pad); const x=i*sx;
|
|
58
|
+
i===0?ctx.moveTo(x,y):ctx.lineTo(x,y); });
|
|
59
|
+
ctx.strokeStyle=colr; ctx.lineWidth=2.5; ctx.lineJoin="round"; ctx.stroke();
|
|
60
|
+
ctx.lineTo((n-1)*sx,h); ctx.lineTo(0,h); ctx.closePath(); ctx.fillStyle=colr+"22"; ctx.fill();
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
let lastMetric = null;
|
|
64
|
+
async function tick(){
|
|
65
|
+
let d; try{ d=await window.pywebview.api.get(); }catch(e){ return; }
|
|
66
|
+
if(!d || !d.metric){ lastMetric=null; return; }
|
|
67
|
+
const m=META[d.metric]; if(!m) return;
|
|
68
|
+
if(d.metric !== lastMetric){ // new tile: wipe the previous frame before drawing this one
|
|
69
|
+
lastMetric = d.metric;
|
|
70
|
+
document.getElementById("stats").textContent = "";
|
|
71
|
+
const c0=document.getElementById("cv"); c0.getContext("2d").clearRect(0,0,c0.width,c0.height);
|
|
72
|
+
}
|
|
73
|
+
const v=d.latest, c=cls(m,v);
|
|
74
|
+
document.getElementById("lbl").textContent = m.lbl;
|
|
75
|
+
const val=document.getElementById("val"); val.className="val "+c;
|
|
76
|
+
val.innerHTML = fmt(v,d.metric)+` <span class="u">${m.unit}</span>`;
|
|
77
|
+
const s=d.stats||{};
|
|
78
|
+
let extra="";
|
|
79
|
+
if(d.metric==="gpu_mem_pct"&&d.extra&&d.extra.gpu_mem_used!=null)
|
|
80
|
+
extra=` · ${Math.round(d.extra.gpu_mem_used)}/${Math.round(d.extra.gpu_mem_total)} MB`;
|
|
81
|
+
if(d.metric==="ram_pct"&&d.extra&&d.extra.ram_used_gb!=null)
|
|
82
|
+
extra=` · ${d.extra.ram_used_gb.toFixed(1)}/${d.extra.ram_total_gb.toFixed(0)} GB`;
|
|
83
|
+
document.getElementById("stats").textContent =
|
|
84
|
+
(s.min!=null?`min ${fmt(s.min,d.metric)} · max ${fmt(s.max,d.metric)} · avg ${fmt(s.avg,d.metric)} · last 60s`:"") + extra;
|
|
85
|
+
draw(document.getElementById("cv"), d.hist||[], m, color(c));
|
|
86
|
+
}
|
|
87
|
+
window.addEventListener("pywebviewready", ()=>{ tick(); setInterval(tick, 100); });
|
|
88
|
+
</script>
|