feat: 初始化画个标仓库 - AI驱动设计系统(BYOK模式) - 224源/371504图标+25海报源+130技能

This commit is contained in:
sgp
2026-10-03 21:44:18 +08:00
commit 9e222877ea
497 changed files with 43611 additions and 0 deletions
+72
View File
@@ -0,0 +1,72 @@
/**
* 临时调研:Iconify 官方集合 vs 本地已收录,找出未收录且许可证合规的候选源
* 输出:未收录集合清单(id / 图标数 / license / 是否合规 / 收录价值初判)
*/
'use strict';
const https = require('https');
const fs = require('fs');
const path = require('path');
const ROOT = process.cwd();
const SOURCES = require(path.join(ROOT, 'js', 'data', 'icon-sources.js'));
// 本地已收录的 iconify prefix(npm: '@iconify-json/xxx' 的 xxx)
const localPrefixes = new Set();
for (const s of SOURCES) {
const m = String(s.npm || '').match(/@iconify-json\/([\w-]+)/);
if (m) localPrefixes.add(m[1]);
// 有些源 id 即 prefix
localPrefixes.add(s.id);
}
function fetch(url, redirects) {
return new Promise((resolve, reject) => {
const req = https.get(url, { timeout: 60000 }, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
const next = res.headers.location;
if (next.startsWith('/')) return resolve(fetch('https://api.iconify.design' + next, (redirects || 0) + 1));
return resolve(fetch(next, (redirects || 0) + 1));
}
if (res.statusCode !== 200) { reject(new Error('HTTP ' + res.statusCode)); res.resume(); return; }
const chunks = [];
res.on('data', (c) => chunks.push(c));
res.on('end', () => resolve(Buffer.concat(chunks).toString('utf8')));
});
req.on('error', reject);
req.setTimeout(60000, () => { req.destroy(new Error('timeout')); });
});
}
(async () => {
console.log('拉取 Iconify 官方集合列表…');
const raw = await fetch('https://api.iconify.design/collections');
const json = JSON.parse(raw);
const all = Object.entries(json.collections || json);
console.log('顶层键:', Object.keys(json).slice(0, 10).join(', '));
// 许可证过滤:排除 BY-SA / BY-NC / BY-ND / GPL / -NC-(兼容空格分隔形式)
const badRe = /by[\s-]?sa|by[\s-]?nc|by[\s-]?nd|gpl|nc-|cc[\s-]?by[\s-]?nc/i;
const missing = [];
for (const [prefix, info] of all) {
if (localPrefixes.has(prefix)) continue;
const license = info.license ? info.license.title : 'unknown';
const bad = badRe.test(license);
missing.push({ prefix, total: info.total, license, bad, author: info.author && info.author.name });
}
// 未收录 + 合规(或 license unknown 单独列出)
const good = missing.filter(m => !m.bad);
const bad = missing.filter(m => m.bad);
good.sort((a, b) => b.total - a.total);
bad.sort((a, b) => b.total - a.total);
console.log(`\n=== 官方集合总数: ${all.length} | 本地已收录 iconify prefix: ${localPrefixes.size} ===`);
console.log(`\n=== 未收录 + 许可证合规(${good.length} 个)===\n`);
for (const m of good) {
console.log(` ${m.prefix.padEnd(28)} ${String(m.total).padStart(6)} ${m.license.padEnd(28)} ${m.author || ''}`);
}
console.log(`\n=== 未收录 + 许可证不合规(${bad.length} 个,仅供参考)===\n`);
for (const m of bad.slice(0, 60)) {
console.log(` ${m.prefix.padEnd(28)} ${String(m.total).padStart(6)} ${m.license.padEnd(28)} ${m.author || ''}`);
}
})().catch((e) => { console.error('❌', e.message); process.exit(1); });