chore: update Angular cache and TypeScript build info
This commit is contained in:
+76
-8
@@ -572,25 +572,93 @@ function formatListFromMeta(meta) {
|
||||
// Routes under /api
|
||||
|
||||
// -------------------- YouTube simple cache (GET) --------------------
|
||||
// Cache TTL defaults to 15 minutes, configurable via env YT_CACHE_TTL_MS
|
||||
const YT_CACHE_TTL_MS = Number(process.env.YT_CACHE_TTL_MS || 15 * 60 * 1000);
|
||||
/** @type {Map<string, { ts: number, data: any }>} */
|
||||
const ytCache = new Map();
|
||||
// YouTube API key rotation and error handling (similar to Angular service)
|
||||
const ytKeys = (() => {
|
||||
try {
|
||||
const keys = process.env.YOUTUBE_API_KEYS;
|
||||
if (keys && keys !== 'undefined' && keys !== 'null') {
|
||||
return JSON.parse(keys);
|
||||
}
|
||||
} catch {}
|
||||
const single = process.env.YOUTUBE_API_KEY;
|
||||
return single ? [single] : [];
|
||||
})();
|
||||
|
||||
let ytKeyIndex = 0;
|
||||
const ytKeyBans = new Map(); // key -> bannedUntil epoch ms
|
||||
// Ban duration (default 6h) can be overridden via env YT_KEY_BAN_MS
|
||||
const YT_KEY_BAN_MS = Number(process.env.YT_KEY_BAN_MS || 6 * 60 * 60 * 1000);
|
||||
|
||||
function getActiveYouTubeKey() {
|
||||
if (!ytKeys || ytKeys.length === 0) return null;
|
||||
const now = Date.now();
|
||||
|
||||
// Find a non-banned key
|
||||
for (let i = 0; i < ytKeys.length; i++) {
|
||||
const key = ytKeys[ytKeyIndex % ytKeys.length];
|
||||
ytKeyIndex = (ytKeyIndex + 1) % ytKeys.length;
|
||||
|
||||
const bannedUntil = ytKeyBans.get(key);
|
||||
if (!bannedUntil || now > bannedUntil) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
return ytKeys[0]; // fallback to first key
|
||||
}
|
||||
|
||||
function banYouTubeKey(key) {
|
||||
if (!key) return;
|
||||
const bannedUntil = Date.now() + YT_KEY_BAN_MS;
|
||||
ytKeyBans.set(key, bannedUntil);
|
||||
console.warn(`[YouTube API] Banned key ending with ...${key.slice(-4)} until ${new Date(bannedUntil).toISOString()}`);
|
||||
}
|
||||
|
||||
function logYouTubeApiUsage(key, status, path) {
|
||||
const shortKey = key ? `...${key.slice(-4)}` : 'none';
|
||||
const logLevel = status >= 400 ? 'warn' : 'info';
|
||||
console[logLevel](`[YouTube API] Key ${shortKey} - ${status} - ${path}`);
|
||||
}
|
||||
|
||||
// Example: /api/yt/youtube/v3/videos?... -> https://www.googleapis.com/youtube/v3/videos?...
|
||||
r.get('/yt/*', async (req, res) => {
|
||||
try {
|
||||
const googlePath = req.originalUrl.replace(/^\/api\/yt/, '');
|
||||
const targetUrl = `https://www.googleapis.com${googlePath}`;
|
||||
const now = Date.now();
|
||||
const cached = ytCache.get(targetUrl);
|
||||
|
||||
// Check if we have cached data and it's still valid
|
||||
if (cached && (now - cached.ts) < YT_CACHE_TTL_MS) {
|
||||
return res.json(cached.data);
|
||||
}
|
||||
const response = await axios.get(targetUrl, { timeout: 15000, validateStatus: s => s >= 200 && s < 400 });
|
||||
|
||||
const key = getActiveYouTubeKey();
|
||||
if (!key) {
|
||||
console.warn('[YouTube API] No API key available');
|
||||
return res.status(503).json({ error: 'youtube_api_key_unavailable' });
|
||||
}
|
||||
|
||||
// Add API key to the URL
|
||||
const url = new URL(targetUrl);
|
||||
url.searchParams.set('key', key);
|
||||
const finalUrl = url.toString();
|
||||
|
||||
const response = await axios.get(finalUrl, { timeout: 15000, validateStatus: s => s >= 200 && s < 500 });
|
||||
const status = response.status;
|
||||
const data = response.data;
|
||||
ytCache.set(targetUrl, { ts: now, data });
|
||||
return res.status(response.status || 200).json(data);
|
||||
|
||||
// Log the usage
|
||||
logYouTubeApiUsage(key, status, googlePath);
|
||||
|
||||
// Cache the result
|
||||
ytCache.set(targetUrl, {
|
||||
ts: now,
|
||||
data: data,
|
||||
status: status,
|
||||
isError: status >= 400
|
||||
});
|
||||
|
||||
return res.status(status).json(data);
|
||||
} catch (e) {
|
||||
const status = e?.response?.status || 500;
|
||||
const data = e?.response?.data || { error: 'yt_cache_upstream_error', details: String(e?.message || e) };
|
||||
|
||||
Reference in New Issue
Block a user