NPP 元数据
本文档详细介绍 NPP 插件系统中每个 MetaData 项的说明、格式以及需要注意的事项,以帮助开发者能够正确配置插件。
1. 必填元数据
1.1 @time - 加载时机
说明
@time
用于指定插件的加载时机,控制插件在页面加载过程中的执行时机。
格式
- 类型: 字符串
- 可选值:
head
或body
- 默认值:
body
示例
javascript
// ==Npplication==
// @time head
// @time body
// ==/Npplication==
说明
- head: 在页面
<head>
部分加载,适用于需要尽早执行的插件 - body: 在页面
<body>
部分加载,适用于大多数插件
注意事项
- 插件应尽量使用
body
加载 head
适用于需要修改页面初始状态的插件- 需要考虑插件对页面加载性能的影响,选择错误的加载时机可能导致功能异常
1.2 @id - 插件唯一标识符
说明
@id
是插件的唯一标识符,用于系统内部识别和管理插件,是插件存储、更新和卸载的关键标识。
格式
- 类型: 字符串
- 格式: 13位时间戳 + UUIDv4
nitaiPage 通过以下两步完成验证:
BASE
// 时间戳
D{13} > 1749401460000
// UUIDv4
/^([0-9]{13})_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/
注意事项
- ID 必须全局唯一,不能与其他插件冲突
- 一旦设置,不建议更改 (会影响安装、更新、卸载和存储)
- 建议仅使用小写字母,避免大小写混淆
1.3 @version - 插件版本
说明
@version
用于定义插件的版本号,用于版本管理、更新检查和依赖关系验证。
格式
- 类型: 字符串
- 格式: MAJOR.MINOR.PATCH (纯数字)
示例
javascript
// ==Npplication==
// @version 1.0.0
// @version 2.1.3
// ==/Npplication==
注意事项
- MAJOR: 主版本号,不兼容的API修改
- MINOR: 次版本号,向下兼容的功能性新增
- PATCH: 修订号,向下兼容的问题修正
- 纯数字: 禁止使用连字符和标识符(如-beta.1)
2. 可选元数据
2.1 @description - 插件描述
说明
@description
用于提供插件的详细描述信息,帮助用户了解插件的特点。
格式
- 类型: 字符串
- 长度: 无限制,建议10-500个字符
示例
javascript
// ==Npplication==
// @description 一个简单实用的计算器插件
// @description Weather Widget - 显示实时天气信息的小工具
// ==/Npplication==
注意事项
- 描述应简洁明了,突出插件核心功能
- 虽不必要,但强烈建议填写
2.2 @author - 插件作者
说明
@author
用于标识插件的作者。
格式
- 类型: 字符串
- 长度: 无限制,建议5-20个字符
示例
javascript
// ==Npplication==
// @author 张三
// @author John Doe
// @author NitaiDev Team
// @author example@email.com
// ==/Npplication==
注意事项
- 支持包含邮箱地址等联系方式
- 不建议使用他人的作者标识
- 建议使用一致的作者标识
- 虽不必要,但强烈建议填写
2.3 @updateUrl - 更新地址
说明
@updateUrl
用于指定插件更新检查的 URL 地址,nitaiPage 会定期访问此地址检查插件更新。
格式要求
- 类型: 字符串 (URL)
- 协议: 必须使用 http 或 https 协议
- 格式: 完整的 URL 地址
示例
javascript
// ==Npplication==
// @updateUrl https://example.com/store/myNpp.js
// @updateUrl http://example.com/store/myNpp.js
// ==/Npplication==
注意事项
- URL 必须指向可公开访问的插件文件
- 需要注意跨域 (CORS) 问题
- 确保 URL 长期有效,避免频繁变更
2.4 @name - 名称
说明
@name
用于定义插件的显示名称,这个名称将展示给用户
格式
- 类型: 字符串
- 长度: 建议不要超出 16 字符
- 字符集: 支持中文、英文、数字和符号
示例
javascript
// ==Npplication==
// @name 我的插件
// @name My_Npp
// ==/Npplication==
注意事项
- 名称应简短
- 尽量避免使用特殊字符和表情符号
- 不建议与其他插件名称重复
- 虽不必要,但强烈建议填写
2.5 @icon - 插件图标
说明
@icon
用于指定插件的图标URL,用于在用户界面中显示插件图标。
格式
- 类型: 字符串 (URL)
- 协议: http 或 https
- 格式: 图片 URL 或 Base64
示例
javascript
// ==Npplication==
// @icon https://example.com/icon.png
// @icon https://cdn.jsdelivr.net/gh/user/repo/icon.svg
// @icon data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==
// ==/Npplication==
使用注意事项
- 建议使用正方形图标 (如 48x48 或 96x96)
- 支持 PNG、JPG、SVG 等常见格式
- 图标 URL 应稳定可靠,避免失效
2.6 @dependencies - 依赖项
说明
@dependencies
用于声明插件所依赖的其他插件,在插件安装时需要满足对应条件才可安装。
格式
- 类型: 字符串
- 格式:
插件ID@版本号
,多个依赖用逗号分隔
示例代码
javascript
// ==Npplication==
// @dependencies id@1.0.0
// @dependencies id@2.1.0,id2@1.5.0
// ==/Npplication==
注意事项
- 谨慎指定依赖版本,确保兼容性
- 考虑依赖项的加载顺序 (可能需要通知用户手动更改加载顺序)
2.7 @type - 插件类型
说明
@type
用于指定插件的类型
- normal: 普通插件,默认类型,系统普通功能插件
- coreNpp: 核心插件,系统核心功能插件,不允许卸载和新安装,只能更新
格式要求
- 类型: 字符串
- 可选值:
coreNpp
- 默认值:
normal
示例
javascript
// ==Npplication==
// @type nomal
// @type [none]
// @type core
// ==/Npplication==
注意事项
- 建议不填
2.8 @setting - 是否注册设置界面
说明
@setting
用于告诉 nitaiPage 插件是否需要设置界面。
格式要求
- 类型: 布尔值
- 可选值:
true
或false
- 默认值:
false
示例
javascript
// ==Npplication==
// @setting true
// @setting false
// ==/Npplication==
具体设置及调用方法,请参考NPP 设置页面内容添加指南。
3. Metadata 验证和处理机制
3.1 Metadata 处理流程
必需字段验证
javascript
// 验证必需字段
async function extractMetadata(url) {
try {
// 提取元数据块
const urlMetadata = scriptText.match(
/\/\/\s*==Npplication==\s*\n([\s\S]*?)\n\/\/\s*==\/Npplication==/
);
if (!urlMetadata || !urlMetadata[1]) {
console.error('未找到元数据');
return;
}
// 解析元数据
const metadataLines = urlMetadata[1].split('\n');
const metadata = {};
// 验证 名字/id/版本
if (!metadata.name
|| !metadata.id
|| !metadata.version
|| !metadata.time
) {
console.error('缺少必要元数据字段');
return;
}
}
}
格式验证
javascript
// 验证 id 格式
if (metadata.type !== 'coreNpp') {
// UUID v4 格式
const idPattern = /^([0-9]{13})_[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-4[0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$/;
const idMatch = metadata.id.match(idPattern);
if (!idMatch) {
console.error('错误的 ID 格式');
return;
}
// 验证 id 有效性
const timestamp = parseInt(match[1]);
if (timestamp < 1749401460000) {
console.error('ID 无效');
return;
}
}
// 验证 加载时机
if (!metadata.time || !['head', 'body'].includes(metadata.time.toLowerCase())) {
metadata.time = 'body'; // 默认
}
其它部分
javascript
return {
name: metadata.name,
id: metadata.id,
version: metadata.version,
time: metadata.time.toLowerCase(),
updateUrl: metadata.updateUrl || url,
description: metadata.description || '未提供',
author: metadata.author || '未知',
type: metadata.type || '',
icon: metadata.icon || 'https://nitai-images.pages.dev/nitaiPage/defeatNpp.svg',
screen: metadata.screen || '',
forceUpdate: metadata.forced || 'false',
setting: metadata.setting || 'false',
dependencies: metadata.dependencies || '',
};
3.2 Metadata 存储和管理
存储结构
javascript
const pluginMetadata = {
author: "Nitai"
dependencies: ""
description: "主题扩展插件"
forceUpdate: "false"
icon: "https://nitai-images.pages.dev/nitaiPage/themeColor.svg"
id: "themeColor"
ignoreUpdatePrompt: false
installTime: 1754415490324
name: "主题色"
screen: "[`https://nitai-images.pages.dev/nitaiPage/store/themeColor_screen.webp`]"
setting: "true"
time: "head"
type: "coreNpp"
updateUrl: "https://nfdb.nitai.us.kg/themeColor.js"
version: "0.2.1"
};
存储
javascript
// 保存插件 metadata
async function savePluginMetadata(pluginId, metadata) {
return new Promise((resolve, reject) => {
const request = indexedDB.open('NpplicationDB', 1);
request.onsuccess = (event) => {
const db = event.target.result;
const transaction = db.transaction('plugins', 'readwrite');
const store = transaction.objectStore('plugins');
const putRequest = store.put({
id: pluginId,
...metadata,
lastUpdateTime: Date.now()
});
putRequest.onsuccess = () => resolve(true);
putRequest.onerror = () => reject(putRequest.error);
};
request.onerror = () => reject(request.error);
});
}
// 获取插件 metadata
async function getPluginMetadata(pluginId) {
return new Promise((resolve, reject) => {
const request = indexedDB.open('NpplicationDB', 1);
request.onsuccess = (event) => {
const db = event.target.result;
const transaction = db.transaction('plugins', 'readonly');
const store = transaction.objectStore('plugins');
const getRequest = store.get(pluginId);
getRequest.onsuccess = () => resolve(getRequest.result);
getRequest.onerror = () => reject(getRequest.error);
};
request.onerror = () => reject(request.error);
});
}