First commit

This commit is contained in:
2026-03-08 15:55:50 +00:00
parent c767499254
commit 6d9a042ccb
20 changed files with 7145 additions and 10 deletions

65
src/extension.ts Normal file
View File

@@ -0,0 +1,65 @@
import * as vscode from 'vscode';
import { getVisitorCount } from './http';
import { initStatusBar, refresh } from './statusBar';
const OPEN = 4;
const CLOSE = 23;
const INTERVAL_MS = 2 * 60 * 1000;
let timer: NodeJS.Timeout | undefined;
export async function activate(context: vscode.ExtensionContext) {
const subscriptions = context.subscriptions;
const commandId = 'vsc-adda.refresh';
const item = initStatusBar(getVisitorCount, commandId);
subscriptions.push(item);
subscriptions.push(
vscode.commands.registerCommand(commandId, async () => {
await refresh();
})
);
await refresh();
scheduleNext();
subscriptions.push({ dispose: () => timer && clearTimeout(timer) });
}
export function deactivate() {
if (timer) {
clearTimeout(timer);
}
}
function isOpen(d: Date = new Date()): boolean {
return d.getHours() >= OPEN && d.getHours() < CLOSE;
}
function timeUntilOpenMs(from: Date = new Date()): number {
const next = new Date(from);
if (from.getHours() < OPEN) {
next.setHours(OPEN, 0, 0, 0);
} else {
next.setDate(next.getDate() + 1);
next.setHours(OPEN, 0, 0, 0);
}
return next.getTime() - from.getTime();
}
function scheduleNext(): void {
if (timer) {
clearTimeout(timer);
}
if (isOpen()) {
timer = setTimeout(() => {
refresh().finally(scheduleNext);
}, INTERVAL_MS);
} else {
timer = setTimeout(() => {
refresh().finally(scheduleNext);
}, timeUntilOpenMs());
}
}

37
src/http.ts Normal file
View File

@@ -0,0 +1,37 @@
import * as https from 'https';
export function getVisitorCount(): Promise<number> {
return new Promise((resolve, reject) => {
const req = https.get('https://www.gymcontrol.se/global/checkedin/checkedin.php?uid=9094', (res) => {
if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {
res.resume();
reject(new Error(`HTTP ${res.statusCode ?? '?'}`));
return;
}
res.setEncoding('utf8');
let raw = '';
res.on('data', (chunk) => {
raw += chunk;
});
res.on('end', () => {
const text = raw.trim();
const n = Number.parseInt(text, 10);
if (Number.isFinite(n)) {
resolve(n);
} else {
reject(new Error(`Invalid response: "${text}"`));
}
});
});
req.on('error', reject);
req.setTimeout(5000, () => {
req.destroy(new Error('Timeout after 5000 ms'));
});
});
}

42
src/statusBar.ts Normal file
View File

@@ -0,0 +1,42 @@
import * as vscode from 'vscode';
const TOOLTIP_TEXT = 'Current Gym Visitors';
let item: vscode.StatusBarItem;
let getCount: (() => Promise<number>) | undefined;
export function initStatusBar(getVisitorCount: () => Promise<number>, commandId: string): vscode.StatusBarItem {
getCount = getVisitorCount;
item = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 1000);
item.command = commandId;
item.text = '$(adda-fitness) 0';
item.tooltip = TOOLTIP_TEXT;
item.show();
return item;
}
export async function refresh(): Promise<void> {
if (!item || !getCount) {
return;
}
item.text = '$(adda-fitness) $(sync~spin)';
try {
const [count] = await Promise.all([getCount(), sleep(1500)]);
item.text = `$(adda-fitness) ${count}`;
item.tooltip = TOOLTIP_TEXT;
} catch (e: any) {
item.text = '$(warning) Adda';
item.tooltip = e?.message ?? 'Unknown error';
} finally {
item.show();
}
}
function sleep(ms: number): Promise<void> {
return new Promise((resolve) => setTimeout(resolve, ms));
}