From 0043008020c8b5710c332c204bd0d8a8692fc286 Mon Sep 17 00:00:00 2001 From: orfelorfel23 Date: Fri, 28 Aug 2026 22:08:21 +0200 Subject: [PATCH] feat: add live countdown and daily usage history for Poe --- dist/server.js | 15 +++++++++++++++ dist/server.js.map | 2 +- dist/services/db.d.ts | 1 + dist/services/db.d.ts.map | 2 +- dist/services/db.js | 13 +++++++++++++ dist/services/db.js.map | 2 +- public/app.js | 35 +++++++++++++++++++++++++++++++++-- public/style.css | 2 ++ src/server.ts | 16 ++++++++++++++++ src/services/db.ts | 13 +++++++++++++ 10 files changed, 96 insertions(+), 5 deletions(-) diff --git a/dist/server.js b/dist/server.js index 566e1ac..e78924d 100644 --- a/dist/server.js +++ b/dist/server.js @@ -15,6 +15,21 @@ app.use(express_1.default.json()); app.get('/api/quotas', async (req, res) => { try { const quotas = await (0, providers_1.fetchAllQuotas)(); + // Add DB-based stats + const { getTodayStartQuota } = require('./services/db'); + for (const quota of quotas) { + if (quota.provider.toLowerCase() === 'poe' && quota.meta) { + const todayStart = await getTodayStartQuota('POE'); + if (todayStart) { + const startAvailable = todayStart.meta?.available ?? (todayStart.total - todayStart.used); + const currentAvailable = quota.meta.available; + quota.meta.todayUsed = Math.max(0, startAvailable - currentAvailable); + } + else { + quota.meta.todayUsed = 0; + } + } + } res.json(quotas); } catch (error) { diff --git a/dist/server.js.map b/dist/server.js.map index 9385cf9..f50feec 100644 --- a/dist/server.js.map +++ b/dist/server.js.map @@ -1 +1 @@ -{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";;;;;AAAA,sDAA8B;AAC9B,gDAAwB;AACxB,sCAAwD;AACxD,oDAAsD;AACtD,kBAAgB,CAAC,sBAAsB;AAEvC,MAAM,GAAG,GAAG,IAAA,iBAAO,GAAE,CAAC;AACtB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC;AAEtC,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,MAAM,CAAC,cAAI,CAAC,IAAI,CAAC,SAAS,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;AAC3D,GAAG,CAAC,GAAG,CAAC,iBAAO,CAAC,IAAI,EAAE,CAAC,CAAC;AAExB,GAAG,CAAC,GAAG,CAAC,aAAa,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACtC,IAAI,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,IAAA,0BAAc,GAAE,CAAC;QACtC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;QAC/C,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC7D,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAC,cAAc,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE;IACvC,IAAI,CAAC;QACD,MAAM,OAAO,GAAG,MAAM,IAAA,oBAAe,GAAE,CAAC;QACxC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACtB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,uBAAuB,EAAE,CAAC,CAAC;IAC7D,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,IAAI,CAAC,0BAA0B,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;IAC9C,IAAI,CAAC;QACD,MAAM,EAAE,sBAAsB,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;QACnE,sBAAsB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,2BAA2B,EAAE,CAAC,CAAC;IACtE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,yCAAyC,EAAE,KAAK,CAAC,CAAC;QAChE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,CAAC,CAAC;IACxD,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,MAAM,CAAC,IAAc,EAAE,SAAS,EAAE,KAAK,IAAI,EAAE;IAC7C,MAAM,IAAA,WAAM,GAAE,CAAC;IACf,OAAO,CAAC,GAAG,CAAC,qCAAqC,IAAI,EAAE,CAAC,CAAC;AAC7D,CAAC,CAAC,CAAC"} \ No newline at end of file +{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/dist/services/db.d.ts b/dist/services/db.d.ts index 47ddb29..81c0cb7 100644 --- a/dist/services/db.d.ts +++ b/dist/services/db.d.ts @@ -12,5 +12,6 @@ export interface QuotaEntry { export declare function initDb(): Promise; export declare function insertQuota(entry: QuotaEntry): Promise; export declare function getLatestQuotas(): Promise; +export declare function getTodayStartQuota(provider: string): Promise; export declare function getQuotaHistory(days?: number): Promise; //# sourceMappingURL=db.d.ts.map \ No newline at end of file diff --git a/dist/services/db.d.ts.map b/dist/services/db.d.ts.map index 4b8a866..f20235c 100644 --- a/dist/services/db.d.ts.map +++ b/dist/services/db.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAK1B,eAAO,MAAM,IAAI,MAMf,CAAC;AAEH,MAAM,WAAW,UAAU;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;CACd;AAED,wBAAsB,MAAM,kBAiB3B;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,UAAU,gBASlD;AAED,wBAAsB,eAAe,mBAQpC;AAED,wBAAsB,eAAe,CAAC,IAAI,GAAE,MAAU,kBASrD"} \ No newline at end of file +{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,IAAI,CAAC;AAK1B,eAAO,MAAM,IAAI,MAMf,CAAC;AAEH,MAAM,WAAW,UAAU;IACvB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,IAAI,CAAC;IACjB,IAAI,CAAC,EAAE,GAAG,CAAC;CACd;AAED,wBAAsB,MAAM,kBAiB3B;AAED,wBAAsB,WAAW,CAAC,KAAK,EAAE,UAAU,gBASlD;AAED,wBAAsB,eAAe,mBAQpC;AAED,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,gBAWxD;AAED,wBAAsB,eAAe,CAAC,IAAI,GAAE,MAAU,kBASrD"} \ No newline at end of file diff --git a/dist/services/db.js b/dist/services/db.js index d441763..eeb0344 100644 --- a/dist/services/db.js +++ b/dist/services/db.js @@ -7,6 +7,7 @@ exports.pool = void 0; exports.initDb = initDb; exports.insertQuota = insertQuota; exports.getLatestQuotas = getLatestQuotas; +exports.getTodayStartQuota = getTodayStartQuota; exports.getQuotaHistory = getQuotaHistory; const pg_1 = require("pg"); const dotenv_1 = __importDefault(require("dotenv")); @@ -56,6 +57,18 @@ async function getLatestQuotas() { const res = await exports.pool.query(query); return res.rows; } +async function getTodayStartQuota(provider) { + const query = ` + SELECT * + FROM quotas + WHERE provider = $1 + AND timestamp >= date_trunc('day', NOW() AT TIME ZONE 'UTC') + ORDER BY timestamp ASC + LIMIT 1; + `; + const res = await exports.pool.query(query, [provider]); + return res.rows[0]; +} async function getQuotaHistory(days = 7) { const query = ` SELECT * diff --git a/dist/services/db.js.map b/dist/services/db.js.map index 267995a..f310165 100644 --- a/dist/services/db.js.map +++ b/dist/services/db.js.map @@ -1 +1 @@ -{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":";;;;;;;;;;AAAA,2BAA0B;AAC1B,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEH,QAAA,IAAI,GAAG,IAAI,SAAI,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;IACzB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;IACzB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;IAC7B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;IACjC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC;CAChD,CAAC,CAAC;AAYI,KAAK;IACR,MAAM,MAAM,GAAG,MAAM,QAAA,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;SASlB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;YAAS,CAAC;QACP,MAAM,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACL,CAAC;AAEM,KAAK,sBAAsB,KAAiB;IAC/C,MAAM,KAAK,GAAG;;;;KAIb,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3E,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAEM,KAAK;IACR,MAAM,KAAK,GAAG;;;;KAIb,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,GAAG,CAAC,IAAI,CAAC;AACpB,CAAC;AAEM,KAAK,0BAA0B,IAAI,GAAW,CAAC;IAClD,MAAM,KAAK,GAAG;;;;;KAKb,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,IAAI,CAAC;AACpB,CAAC"} \ No newline at end of file +{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/services/db.ts"],"names":[],"mappings":";;;;;;;;;;;AAAA,2BAA0B;AAC1B,oDAA4B;AAE5B,gBAAM,CAAC,MAAM,EAAE,CAAC;AAEH,QAAA,IAAI,GAAG,IAAI,SAAI,CAAC;IACzB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;IACzB,IAAI,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;IACzB,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,OAAO;IAC7B,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW;IACjC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,OAAO,IAAI,MAAM,CAAC;CAChD,CAAC,CAAC;AAYI,KAAK;IACR,MAAM,MAAM,GAAG,MAAM,QAAA,IAAI,CAAC,OAAO,EAAE,CAAC;IACpC,IAAI,CAAC;QACD,MAAM,MAAM,CAAC,KAAK,CAAC;;;;;;;;;SASlB,CAAC,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;IACxC,CAAC;YAAS,CAAC;QACP,MAAM,CAAC,OAAO,EAAE,CAAC;IACrB,CAAC;AACL,CAAC;AAEM,KAAK,sBAAsB,KAAiB;IAC/C,MAAM,KAAK,GAAG;;;;KAIb,CAAC;IACF,MAAM,MAAM,GAAG,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAC3E,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAEM,KAAK;IACR,MAAM,KAAK,GAAG;;;;KAIb,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IACpC,OAAO,GAAG,CAAC,IAAI,CAAC;AACpB,CAAC;AAEM,KAAK,6BAA6B,QAAgB;IACrD,MAAM,KAAK,GAAG;;;;;;;KAOb,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;IAChD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACvB,CAAC;AAEM,KAAK,0BAA0B,IAAI,GAAW,CAAC;IAClD,MAAM,KAAK,GAAG;;;;;KAKb,CAAC;IACF,MAAM,GAAG,GAAG,MAAM,QAAA,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,OAAO,GAAG,CAAC,IAAI,CAAC;AACpB,CAAC"} \ No newline at end of file diff --git a/public/app.js b/public/app.js index 0993c33..19fbcb9 100644 --- a/public/app.js +++ b/public/app.js @@ -73,13 +73,15 @@ function updateRow(providerId, quota) { const detailsEl = document.getElementById(`details-poe`); if (detailsEl) { - const { available, dailyRefresh, expiringPoints, daysUntilCap } = quota.meta; + const { available, dailyRefresh, expiringPoints, daysUntilCap, todayUsed } = quota.meta; detailsEl.innerHTML = `
Übrig: ${available.toLocaleString()}
-
Refresh: +${dailyRefresh.toLocaleString()} (00:00 UTC)
+
Heute Verbraucht: ${(todayUsed || 0).toLocaleString()}
Verfällt: ${expiringPoints.toLocaleString()}
Tage bis Cap: ${daysUntilCap}
+
Refresh in: --:--:--
`; + startPoeCountdown(); } } else { statusText.innerText = `${(quota.used).toLocaleString()} / ${(quota.total).toLocaleString()}`; @@ -96,6 +98,35 @@ function updateRow(providerId, quota) { } } +let poeCountdownInterval = null; +function startPoeCountdown() { + if (poeCountdownInterval) clearInterval(poeCountdownInterval); + + const updateCountdown = () => { + const now = new Date(); + const nextMidnightUTC = new Date(); + nextMidnightUTC.setUTCHours(24, 0, 0, 0); + + let diffMs = nextMidnightUTC.getTime() - now.getTime(); + if (diffMs < 0) { + // Already passed, next midnight is +24h (edge case just after midnight) + diffMs += 24 * 60 * 60 * 1000; + } + + const h = Math.floor(diffMs / (1000 * 60 * 60)); + const m = Math.floor((diffMs % (1000 * 60 * 60)) / (1000 * 60)); + const s = Math.floor((diffMs % (1000 * 60)) / 1000); + + const el = document.getElementById('poe-countdown'); + if (el) { + el.innerText = `${h.toString().padStart(2, '0')}:${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`; + } + }; + + updateCountdown(); + poeCountdownInterval = setInterval(updateCountdown, 1000); +} + async function fetchHistory() { try { const response = await fetch('/api/history'); diff --git a/public/style.css b/public/style.css index 9505e24..152d232 100644 --- a/public/style.css +++ b/public/style.css @@ -98,6 +98,8 @@ header p { .provider-details { display: flex; justify-content: space-between; + flex-wrap: wrap; + gap: 10px; font-size: 0.85em; color: var(--text-muted); padding-top: 10px; diff --git a/src/server.ts b/src/server.ts index 7cb203b..443d07f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -13,6 +13,22 @@ app.use(express.json()); app.get('/api/quotas', async (req, res) => { try { const quotas = await fetchAllQuotas(); + + // Add DB-based stats + const { getTodayStartQuota } = require('./services/db'); + for (const quota of quotas) { + if (quota.provider.toLowerCase() === 'poe' && quota.meta) { + const todayStart = await getTodayStartQuota('POE'); + if (todayStart) { + const startAvailable = todayStart.meta?.available ?? (todayStart.total - todayStart.used); + const currentAvailable = quota.meta.available; + quota.meta.todayUsed = Math.max(0, startAvailable - currentAvailable); + } else { + quota.meta.todayUsed = 0; + } + } + } + res.json(quotas); } catch (error) { console.error('Error fetching quotas:', error); diff --git a/src/services/db.ts b/src/services/db.ts index cddca21..ccefc7c 100644 --- a/src/services/db.ts +++ b/src/services/db.ts @@ -61,6 +61,19 @@ export async function getLatestQuotas() { return res.rows; } +export async function getTodayStartQuota(provider: string) { + const query = ` + SELECT * + FROM quotas + WHERE provider = $1 + AND timestamp >= date_trunc('day', NOW() AT TIME ZONE 'UTC') + ORDER BY timestamp ASC + LIMIT 1; + `; + const res = await pool.query(query, [provider]); + return res.rows[0]; +} + export async function getQuotaHistory(days: number = 7) { const query = ` SELECT *