feat: add live countdown and daily usage history for Poe
Build and Push Docker Image / build-and-push (push) Canceled after 0s
Build and Push Docker Image / build-and-push (push) Canceled after 0s
This commit is contained in:
1 parent
029e8e923f
commit
0043008020
10 files changed
+96
-5
No files matched your search
Vendored
+15
@@ -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) {
|
||||
|
||||
Vendored
+1
-1
@@ -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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"}
|
||||
Vendored
+1
@@ -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
|
||||
Vendored
+1
-1
@@ -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"}
|
||||
Vendored
+13
@@ -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 *
|
||||
|
||||
Vendored
+1
-1
@@ -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
@@ -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');
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 *
|
||||
|
||||
Reference in new issue
Block a user