// 列 OSS audio/ 下,按月分桶,看每个月的 key 模式分布 const fs = require('fs'); const path = require('path'); const envTxt = fs.readFileSync(path.join(__dirname, '..', '..', 'server', '.env.production'), 'utf8'); const env = {}; for (const line of envTxt.split(/\r?\n/)) { const m = line.match(/^\s*([A-Z0-9_]+)\s*=\s*(.*)\s*$/); if (m) env[m[1]] = m[2].replace(/^["']|["']$/g, ''); } const OSS = require(path.join(__dirname, '..', '..', 'server', 'node_modules', 'ali-oss')); const client = new OSS({ accessKeyId: env.OSS_ACCESS_KEY_ID, accessKeySecret: env.OSS_ACCESS_KEY_SECRET, bucket: 'rrbrr-book-audio', endpoint: 'oss-cn-shanghai.aliyuncs.com', secure: true }); async function listAll(prefix) { const all = []; let marker = null; do { const r = await client.list({ prefix, 'max-keys': 1000, marker }); all.push(...(r.objects || [])); marker = r.nextMarker || null; } while (marker); return all; } function fmt(b) { return (b/1024/1024).toFixed(1) + ' MB'; } (async () => { const all = await listAll('audio/'); // 按月 + key pattern 分类 const byMonthPattern = new Map(); for (const o of all) { const m = (o.lastModified || '').slice(0, 7); // YYYY-MM const key = o.name; // 提取关键模式 let pattern; if (key.startsWith('audio/merged/')) pattern = 'audio/merged/...'; else { const parts = key.split('/'); const second = parts[1] || ''; if (second.startsWith('preview-')) pattern = 'audio/preview-uuid/...'; else if (second.startsWith('sync-')) pattern = 'audio/sync-uuid/...'; else if (/^[0-9a-f-]{36}$/.test(second)) { const fname = parts[2] || ''; if (fname.includes('_merged')) pattern = 'audio/uuid/{uuid}_merged.{ext}'; else if (fname.includes('output')) pattern = 'audio/uuid/output.{ext}'; else if (fname.includes('cloud_segment')) pattern = 'audio/uuid/cloud_segment_*.{ext}'; else pattern = `audio/uuid/${fname.split('.')[0]}.{ext}`; } else if (/^\d+$/.test(second)) pattern = 'audio/{numeric}/...'; // 比如 chapterId? else pattern = `audio/${second.substring(0,20)}/...`; } const k = `${m}|${pattern}`; const cur = byMonthPattern.get(k) || { count: 0, bytes: 0 }; cur.count++; cur.bytes += o.size || 0; byMonthPattern.set(k, cur); } // 按月输出 const months = [...new Set([...byMonthPattern.keys()].map(k => k.split('|')[0]))].sort(); for (const mo of months) { console.log(`\n=== ${mo} ===`); const arr = [...byMonthPattern.entries()].filter(([k]) => k.startsWith(mo)).sort((a, b) => b[1].bytes - a[1].bytes); for (const [k, v] of arr) { const pat = k.split('|')[1]; console.log(` ${String(v.count).padStart(7)} ${fmt(v.bytes).padStart(10)} ${pat}`); } } })();