feat: add live countdown and daily usage history for Poe
Build and Push Docker Image / build-and-push (push) Canceled after 0s

This commit is contained in:
Jannik committed 2026-08-28 22:08:21 +02:00
1 parent 029e8e923f
commit 0043008020
10 files changed
+96 -5

No files matched your search

+15
View File
@@ -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) {
+1 -1
View File
@@ -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"}
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
+1
View File
@@ -12,5 +12,6 @@ export interface QuotaEntry {
export declare function initDb(): Promise<void>;
export declare function insertQuota(entry: QuotaEntry): Promise<any>;
export declare function getLatestQuotas(): Promise<any[]>;
export declare function getTodayStartQuota(provider: string): Promise<any>;
export declare function getQuotaHistory(days?: number): Promise<any[]>;
//# sourceMappingURL=db.d.ts.map
+1 -1
View File
@@ -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"}
{"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"}
+13
View File
@@ -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 *
+1 -1
View File
@@ -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"}
{"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"}
+33 -2
View File
@@ -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 = `
<div><span>Übrig:</span> <strong style="color: #fff">${available.toLocaleString()}</strong></div>
<div><span>Refresh:</span> <strong style="color: var(--success)">+${dailyRefresh.toLocaleString()} (00:00 UTC)</strong></div>
<div><span>Heute Verbraucht:</span> <strong style="color: #fff">${(todayUsed || 0).toLocaleString()}</strong></div>
<div><span>Verfällt:</span> <strong style="color: ${expiringPoints > 0 ? 'var(--danger)' : 'var(--text-muted)'}">${expiringPoints.toLocaleString()}</strong></div>
<div><span>Tage bis Cap:</span> <strong style="color: #fff">${daysUntilCap}</strong></div>
<div><span>Refresh in:</span> <strong id="poe-countdown" style="color: var(--success)">--:--:--</strong></div>
`;
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');
+2
View File
@@ -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;
+16
View File
@@ -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);
+13
View File
@@ -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 *