maotoumao/musicfree-skills/musicfree-plugin-dev

Claude Code and agent skill by maotoumao/musicfree-skills

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

从零开始开发 MusicFree 音乐播放器插件的完整指南。 当用户要求编写、创建、开发 MusicFree 插件,或要求将某个音乐网站、API 适配为 MusicFree 插件时触发。 涵盖:插件协议、媒体类型定义、方法签名、沙箱环境、站点分析、本地调试、发布更新等完整流程。 本 Skill 面向 AI 执行,指导 AI 与零基础用户协作完成插件开发。

Install

npx vskill@latest install maotoumao/musicfree-skills/musicfree-plugin-dev

SKILL.md

MusicFree 插件开发

严格行为准则

以下规则在整个插件开发过程中始终生效,违反将导致开发失败:

  1. 禁止盲猜 URL:不要凭空试 /api/search、/v1/song 等路径。每个 URL 必须来自页面内容或 Playwright 捕获的网络请求
  2. 禁止搜索网络寻找 API:不要搜索"XX音乐 API"、"免费音乐接口"等。所有数据来源必须通过对目标站点的直接观察获得,不能来自网络搜索
  3. 禁止批量探测:不要同时发多个请求试不同的参数组合
  4. 禁止重复请求:每个 URL 只请求一次,结果保存到本地文件后基于本地数据分析
  5. 禁止放弃说"需要浏览器环境":axios 失败但浏览器可以访问,差别一定在请求头上,用 Playwright 捕获真实请求头后在 axios 中补全

当遇到困难时,唯一正确的做法是:用 Playwright 观察浏览器的真实行为。不要猜测,不要搜索,去观察。

角色与协作模式

  • AI(你):分析目标站点、编写插件代码、编写并执行测试脚本、迭代修复
  • 用户:提供目标站点/API 信息,仅在 AI 无法独立完成时执行辅助操作
核心原则:最小化用户操作

能自己做的,绝不让用户做。 遵循以下优先级:

  1. AI 独立完成:直接用工具抓取页面、分析 HTML/JS、在终端运行脚本
  2. AI 做 + 用户确认:AI 分析后给出结论,请用户确认是否正确
  3. 用户操作(最后手段):仅当 AI 的工具无法获取到所需数据时,才让用户在浏览器中操作
与用户交互原则
  • 用户可能是零基础,不要使用未解释的技术术语
  • 需要用户操作时,给出精确到按键级别的逐步指令,每次只下达一个操作
  • 主动告知用户当前进度和下一步计划
  • 不确定时必须询问:当对站点行为、API 含义、数据字段映射不确定时,先问再做

工作流程

1. 收集信息 → 2. 判断路径 → 3. 分析数据源 → 4. 确定方法集合
→ 5. 逐个实现 → 6. 测试验证 → 7. 迭代修复 → 8. 输出最终插件
步骤 1:收集信息并检查环境

先检查开发环境(在做任何其他事之前):

  1. 检查 Node.js 是否可用:node --version
  2. 询问用户:电脑上是否安装了 Chrome 或 Edge 浏览器?安装路径是什么?(Playwright 可以复用已安装的浏览器,避免下载)
  3. 安装 Playwright:npm install -D playwright(不需要下载 Chromium,后续用 channel: 'chrome' 复用用户的 Chrome)

然后收集需求:

  • 目标是什么?(某个音乐网站?已有的 API 文档?自建的服务?)
  • 插件作者名?(会写入插件的 author 字段)
步骤 2:判断路径

根据收集到的信息,选择对应路径:

路径 A:用户提供了 API 文档或接口规格 → 阅读文档 → 将端点映射到插件方法 → 直接编写代码

路径 B:用户提供了网站 URL(页面内容直接可抓取) → 用工具抓取页面 HTML → 分析 DOM 结构 → 用 cheerio 编写解析逻辑 → 详见 references/site-analysis-playbook.md "静态站点分析"

路径 C:用户提供了网站 URL(需逆向分析内部 API) 页面通过内部 API 异步加载数据,没有公开文档。需要观察浏览器的实际行为,然后用 axios 精确复现。

核心方法论——观察 → 分析 → 复现 → 验证:

  1. 观察:用 Playwright 加载页面,捕获所有网络请求,保存到本地
  2. 分析:基于本地缓存的数据做离线分析,找到关键的 API 端点和音频请求
  3. 复现:用 axios 复现相同的请求(包括完整的 Headers)
  4. 验证:在终端测试,如果失败则对比 Playwright 捕获的请求头与 axios 请求头的差异

→ 详见 references/site-analysis-playbook.md

步骤 3:分析数据源

快速预判站点类型:用工具抓取目标 URL 的 HTML,检查内容:

  • 如果 HTML 中包含完整的数据内容(歌曲列表、歌手名等文本) → 静态站点,用 cheerio 解析
  • 如果 HTML 很小(骨架 HTML)、包含大量 <script> 标签、或核心内容区域为空 → SPA 站点,直接使用 Playwright,不要在 axios 上浪费时间

遵循"观察-分析-复现-验证"方法论(详见 references/site-analysis-playbook.md)。

关键规则:

  • 所有抓取内容先保存到本地文件,后续基于本地文件分析,避免重复请求
  • 不要盲猜 URL——每个 API 端点必须来自页面内容或网络请求的实际观察
  • 推断出的 API 和数据结构不确定时 → 向用户确认
步骤 4-8:实现循环

确定数据源后:

  1. 根据站点分析结果,自动识别站点支持的功能(搜索、排行榜、歌单、歌词等),能适配的全部实现,适配不了的不写入插件——不需要询问用户实现哪些功能
  2. 从 search 和 getMediaSource 开始(最核心的两个方法)
  3. 每完成一个方法,编写测试脚本并在终端中执行验证
  4. 通过后再实现下一个方法
  5. 全部完成后,添加元数据,输出最终 .js 文件

插件骨架

javascript
// 引入需要的模块(均为沙箱内置,无需安装)
const axios = require('axios');
const cheerio = require('cheerio');
module.exports = {
// ===== 必填属性 =====
platform: '插件名称',
// ===== 可选属性 =====
version: '0.0.1', // 语义化版本号
author: '作者名',
description: '插件说明',
srcUrl: 'https://example.com/plugin.js', // 远程更新地址
cacheControl: 'no-cache', // "cache" | "no-cache" | "no-store"
supportedSearchType: ['music', 'album', 'artist', 'sheet'],
userVariables: [{ key: 'cookie', name: 'Cookie', hint: '请输入你的 Cookie' }],
hints: {
importMusicSheet: ['支持以下格式的链接:...', 'https://example.com/playlist/123'],
},
// ===== 方法 =====
async search(query, page, type) {
/* ... */
},
async getMediaSource(musicItem, quality) {
/* ... */
},
// ... 更多方法
};
属性速查
属性必填说明
platform是插件名称,不可为"本地"
version否语义化版本号,默认 "0.0.0"
author否插件作者
description否说明文字
srcUrl否远程 .js 文件直链,用于应用内更新
cacheControl否getMediaSource 结果的缓存策略
supportedSearchType否声明支持的搜索类型数组,不填则认为全部支持
userVariables否用户可配置变量数组,每项含 key(必填)、name、hint
hints否提示文案,键为方法名,值为字符串数组
userVariables 用法

定义:

javascript
userVariables: [{ key: 'cookie', name: 'Cookie', hint: '在浏览器登录后获取' }];

运行时读取:

javascript
const cookie = env.getUserVariables().cookie;

方法速查

所有方法均为 async,遇到错误应直接 throw。 完整签名、参数与返回值详见 references/plugin-protocol.md。 基本媒体类型字段详见 references/media-types.md。

方法功能核心入参核心返回值
search搜索(query, page, type){ isEnd, data: [] }
getMediaSource获取播放链接(musicItem, quality){ url, headers? }
getLyric获取歌词(musicItem){ rawLrc?, translation? }
getAlbumInfo专辑详情(albumItem, page){ isEnd, musicList, albumItem? }
getMusicSheetInfo歌单详情(sheetItem, page){ isEnd, musicList, sheetItem? }
getArtistWorks歌手作品(artistItem, page, type){ isEnd, data: [] }
getMusicInfo补全歌曲信息(musicItem)Partial<IMusicItem>
importMusicItem导入单曲(urlLike)IMusicItem
importMusicSheet导入歌单(urlLike)IMusicItem[]
getTopLists排行榜列表无[{ title?, data: [] }]
getTopListDetail排行榜详情(topListItem, page){ isEnd, musicList }
getRecommendSheetTags推荐歌单标签无{ pinned?, data: [] }
getRecommendSheetsByTag按标签获取歌单(tag, page){ isEnd, data: [] }
getMusicComments歌曲评论(musicItem, page){ isEnd, data: [] }
关键约定
  • 分页:page 从 1 开始;isEnd 为 true 表示到达最后一页,不填默认 true
  • `platform` 自动注入:返回的媒体项无需设置 platform,框架会自动添加
  • `id` 必须有:每个媒体项必须包含 id 字段
  • 可扩展字段:IMusicItem 等类型支持任意可序列化的扩展字段,这些字段会在后续方法调用时被传入。利用这一特性在 search 中附带后续方法所需的额外数据
  • 错误处理:遇到错误直接 throw,不要返回 null

沙箱环境

插件运行在隔离沙箱中(vm.createContext),有 10 秒执行超时。

可用模块(通过 require 引入)
模块用途
axiosHTTP 请求
cheerioHTML 解析(类 jQuery 语法)
crypto-js加解密
dayjs日期时间处理
big-integer大整数运算
qsURL 参数序列化
heHTML 实体编码/解码
webdavWebDAV 操作

注意:不在此列表中的模块无法 require。如需使用其它库(如 lodash),必须用 webpack 等工具将源码打包到插件文件中。

全局可用 API
  • fetch, URL, URLSearchParams, AbortController
  • Buffer, TextEncoder, TextDecoder
  • btoa, atob, encodeURIComponent, decodeURIComponent
  • JSON, console.log/warn/error
  • setTimeout, setInterval, Promise
  • env.getUserVariables() — 读取用户变量
  • env.os — 操作系统
  • env.appVersion — 应用版本
  • env.lang — 当前语言

开发模式示例

模式一:JSON API 对接

已知某服务的 API 接口,直接请求并转换数据格式:

javascript
const axios = require('axios');
module.exports = {
platform: '示例API源',
version: '0.0.1',
supportedSearchType: ['music'],
async search(query, page, type) {
if (type !== 'music') return { isEnd: true, data: [] };
const res = await axios.get('https://api.example.com/search', {
params: { keyword: query, page, limit: 20 },
});
const list = res.data.songs || [];
return {
isEnd: list.length < 20,
data: list.map((item) => ({
id: item.songId,
title: item.songName,
artist: item.singerName,
album: item.albumName,
artwork: item.coverUrl,
duration: item.duration,
// 扩展字段:后续 getMediaSource 会用到
extraId: item.fileHash,
})),
};
},
async getMediaSource(musicItem, quality) {
const res = await axios.get('https://api.example.com/play', {
params: { hash: musicItem.extraId, quality },
});
if (!res.data.url) throw new Error('无法获取播放链接');
return { url: res.data.url };
},
};
模式二:HTML 页面解析

目标网站没有公开 API,直接抓取 HTML 并用 cheerio 解析:

javascript
const axios = require('axios');
const cheerio = require('cheerio');
module.exports = {
platform: '示例HTML源',
version: '0.0.1',
supportedSearchType: ['music'],
async search(query, page, type) {
if (type !== 'music') return { isEnd: true, data: [] };
const rawHtml = (
await axios.get('https://example.com/search', {
params: { q: query, page },
})
).data;
const $ = cheerio.load(rawHtml);
const results = [];
$('.search-result-item').each((i, el) => {
results.push({
id: $(el).attr('data-id'),
title: $(el).find('.song-title').text().trim(),
artist: $(el).find('.artist-name').text().trim(),
artwork: $(el).find('img').attr('src'),
url: $(el).find('audio').attr('src'), // 如果页面直接包含音源
});
});
return {
isEnd: $('.next-page').length === 0,
data: results,
};
},
};
模式三:直接拼接(无需网络请求)

音源 URL 可直接由已知信息拼接得出:

javascript
module.exports = {
platform: '示例拼接源',
version: '0.0.1',
cacheControl: 'no-store',
async getMediaSource(musicItem, quality) {
return {
url: 'https://cdn.example.com/audio/' + musicItem.id + '.mp3',
};
},
};

测试流程

完成插件编写后,创建一个测试脚本在终端中运行:

javascript
// test-plugin.js
const plugin = require('./my-plugin.js');
async function test() {
console.log('=== 测试 search ===');
try {
const searchResult = await plugin.search('测试关键词', 1, 'music');
console.log('搜索结果数量:', searchResult.data.length);
console.log('是否最后一页:', searchResult.isEnd);
if (searchResult.data.length > 0) {
console.log('第一条结果:', JSON.stringify(searchResult.data[0], null, 2));
console.log('\n=== 测试 getMediaSource ===');
const source = await plugin.getMediaSource(searchResult.data[0], 'standard');
console.log('播放链接:', source?.url ? '✓ 获取成功' : '✗ 获取失败');
console.log('详细信息:', JSON.stringify(source, null, 2));
}
} catch (e) {
console.error('测试失败:', e.message);
}
}
test();

执行方式:

bash
node test-plugin.js

测试要点:

  • 每个方法单独测试,确认返回值结构正确
  • 验证 id 字段存在且有效
  • 验证分页逻辑(测试 page=1 和 page=2)
  • 验证 getMediaSource 返回的 URL 可访问

注意:本地 Node.js 测试时,env.getUserVariables() 不可用。如果插件使用了 userVariables,需要在测试脚本中模拟:

javascript
// 在 require 插件之前模拟 env
global.env = {
getUserVariables: () => ({ cookie: '测试用cookie值' }),
os: 'win32',
appVersion: '0.0.1',
lang: 'zh-CN',
};
const plugin = require('./my-plugin.js');

发布与更新

托管到 GitHub
  1. 创建一个 GitHub 仓库(或使用已有仓库)
  2. 将插件 .js 文件上传到仓库
  3. 获取文件的 raw 链接(格式:https://raw.githubusercontent.com/用户名/仓库名/分支/文件名.js)
  4. 将此链接填入插件的 srcUrl 字段
用户安装

用户在 MusicFree 中通过 "从 URL 安装插件" 功能,粘贴插件的 raw 链接即可安装。

版本更新

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Refreshed 16 Mar 2026, 7 months ago.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/maotoumao/musicfree-skills/musicfree-plugin-dev/badge)](https://verified-skill.com/skills/maotoumao/musicfree-skills/musicfree-plugin-dev)

Something wrong with this skill or its page? Tell us.