Npplication Store 实现
商店系统概述
Npplication Store 是一个插件发现和管理系统,允许浏览、安装和更新插件。它具有以下特性:
- 支持多个商店源
- 按分类浏览插件 (自动合并相同分类)
- 插件详情展示 (插件细节页: 包括截图、描述、依赖等)
商店源管理
nitaiPage 支持用户在商店管理页添加多个商店源。默认商店源配置如下:
javascript
const STORE_SOURCES_KEY = 'storeSources';
const STORE_SOURCES_DEFAULT = ['https://nppdb.nitai.cc/store'];插件数据获取与处理
核心功能:从商店源获取插件数据并合并相同分类。
javascript
// 加载并合并所有商店源并将结果写入 window.storeData 后返回
export async function loadStoreData() {
const sources = getStoreSources();
const responses = await Promise.all(sources.map(url =>
fetch(url)
.then(res => res.json().then(data => ({ url, data })))
.catch(err => {
console.error(`加载商店源 ${url} 失败:`, err);
return null;
})
));
const validData = responses.filter(data => data !== null);
const mergedData = mergeStoreData(validData);
window.storeData = mergedData;
return mergedData;
}javascript
// 多源合并
export function mergeStoreData(sources) {
const merged = { category: {} };
sources.forEach(({ url, data }) => {
if (data.category && data.category[0]) {
Object.entries(data.category[0]).forEach(([key, name]) => {
if (!merged.category[key]) merged.category[key] = name;
});
}
Object.entries(data).forEach(([key, value]) => {
if (key === 'category') return;
if (!merged[key]) merged[key] = [];
if (Array.isArray(value) && value[0] && typeof value[0] === 'object') {
const plugins = Object.values(value[0]).map(plugin => ({
url: plugin.url,
screenshots: plugin.screenshots,
source: url
}));
merged[key].push(...plugins);
}
});
});
return merged;
}商店源的数据格式见构建部署自定义商店源
插件安装
javascript
export async function installNpplication(url) {
// 1. 解析元数据
const { metadata } = await getNpp({ url });
// 2. 验证是否为有效的 JS 文件
if (!await verifyJSUrl(url)) { /* 提示安装失败 */ return; }
// 3. 检查依赖(翻译插件跳过)
const dependencies = parseDependencies(metadata.dependencies || '');
const dependencyCheckResult = await checkDependencies(dependencies);
if (metadata.type !== 'translate' && !dependencyCheckResult.status) return;
// 4. 核心插件只能从白名单源安装,不允许全新安装
if (metadata.type === 'coreNpp' && !isAllowedCoreSource(url)) return;
const existing = (await getPluginsList()).find(p => p.id === metadata.id);
if (metadata.type === 'coreNpp' && !existing) return;
// 5. 已安装插件则对比版本
if (existing) {
const versionComparison = compareVersions(existing.version, metadata.version);
if (versionComparison === 0) {
showUpdateDialog(metadata); // 版本相同,询问是否重装
} else if (versionComparison < 0) {
checkUpdates(metadata.id); // 有新版,走更新流程
}
return;
}
// 6. 全新安装:登记元数据 + 下载源码 + 提示用户刷新
if (!['head', 'body'].includes(metadata.time)) return;
await savePluginMetadata(metadata);
await saveJSFile(metadata.id, url);
showRefreshDialog();
}插件存储
javascript
// 下载 JS 文件内容并存入 nppstore/Npp
export async function saveJSFile(id, url) {
const response = await fetch(url, { cache: 'no-store' });
if (!response.ok) return false;
const content = await response.text();
await dbPut('nppstore', 'Npp', { id, content });
return true;
}