
后端音视频前端【免费下载链接】navidrome Your Personal Streaming Service项目地址https://gitcode.com/gh_mirrors/na/navidrome点击查看免费下载导读本指南以 Navidrome 仓库中的 plugins/examples/README.md 为骨架系统讲解官方提供的 8 个示例插件覆盖 Go、Python、Rust 三种语言与 MetadataAgent、Scrobbler、Scheduler、WebSocket 等多种能力并深入源码级实现细节。读完本文你将掌握用make一键构建.ndp插件包、用 Extism CLI 在脱离 Navidrome 的情况下单测能力函数、通过navidrome.toml安装启用插件以及从 minimal 示例或 XTP CLI 脚手架出发创建属于你自己的跨语言插件。Navidrome 的插件体系基于 WebAssemblyWasm与 Extism 框架构建插件在沙箱中运行通过 插件系统主文档 定义的能力Capabilities 宿主服务Host Services模型与 Navidrome 交互。plugins/examples/目录就是官方精心挑选的标准答案集合每个示例都刻意聚焦一到几个核心知识点是学习插件开发的最佳起点。示例总览8 个插件各自演示什么plugins/examples/下共有 8 个官方示例按语言与能力维度可以划分为三类插件语言能力Capabilities核心演示点minimalGoMetadataAgent最基础的插件结构与注册模式wikimediaGoMetadataAgentWikidata/Wikipedia 元数据抓取真实世界级实现crypto-tickerGoLifecycle、SchedulerCallback、WebSocketCallback实时加密货币行情演示类coverartarchive-pyPythonMetadataAgentCover Art Archive 封面抓取nowplaying-pyPythonLifecycle、SchedulerCallback定时记录当前播放Now Playing 日志webhook-rsRustScrobbler播放 scrobble 时触发 HTTP Webhooklibrary-inspector-rsRustLifecycle、SchedulerCallback定时输出音乐库统计信息discord-rich-presence-rsRustScrobbler、SchedulerCallback、WebSocketCallback与 Discord 集成Rust 完整案例从这张表可以看出官方刻意设计的矩阵式覆盖语言维度上GoTinyGo适合追求开发体验Rust 适合追求性能与最小二进制Python 适合快速原型能力维度上MetadataAgent元数据代理、Scrobbler刮擦上报、SchedulerCallback定时任务、WebSocketCallback长连接事件均有代表复杂度维度上从单文件单函数的 minimal 到多能力多宿主服务的 discord-rich-presence-rs 一应俱全。补充能力与宿主服务的对应关系理解示例前建议先建立两个基本概念详见 插件系统主文档能力Capability插件能做什么由导出的函数自动检测一个插件可实现多个能力。例如 MetadataAgent 能力对应nd_get_artist_biography、nd_get_album_images等nd_*导出函数Scrobbler 能力要求实现nd_scrobbler_is_authorized、nd_scrobbler_now_playing、nd_scrobbler_scrobble、nd_scrobbler_playback_report全部四个方法均必选。宿主服务Host Service插件反向调用 Navidrome 提供的 HTTP、Scheduler、Cache、KVStore、Storage、Task、WebSocket、Library、Matcher、Artwork、SubsonicAPI、Config、Users、ScrobbleRetriever 等服务除 Config 外均需在 manifest 中声明对应权限。上表中 crypto-ticker 与 discord-rich-presence-rs 之所以标注多项能力正是多能力、多宿主服务组合的示范如 Discord 插件同时使用 HTTP、WebSocket、Cache、Scheduler、Artwork、Config 六个宿主服务。构建示例插件前置条件与 Makefile前置工具链按语言不同构建示例需要以下工具Go 插件TinyGo 0.30推荐产出更小的 Wasm 二进制无 TinyGo 时 Makefile 会退化为GOOSwasip1 GOARCHwasm go buildPython 插件extism-py实验性支持Rust 插件Rust 工具链并安装wasm32-wasip1目标Rust 示例全部使用 WASI 以支持文件系统等能力一键构建全部插件make all该命令会为每个插件产出.ndp包文件即zip 压缩包内包含manifest.jsonplugin.wasm的插件分发格式。在 plugins/examples/Makefile 中all被拆分为三个子目标all-go、all-python、all-rust分别对应$(PLUGINS:%%.ndp)、$(PYTHON_PLUGINS:%%.ndp)、$(RUST_PLUGINS:%%.ndp)因此也可以按语言分批构建。构建单个插件make minimal.ndp make wikimedia.ndp make discord-rich-presence-rs.ndpMakefile 的设计有几个值得留意的工程细节见 Makefile插件自动发现不依赖手工维护列表。Go 插件通过扫描包含go.mod的目录$(wildcard */go.mod)、Python 插件通过扫描含plugin/__init__.py的目录、Rust 插件通过扫描含Cargo.toml的目录来识别。TinyGo 优先TINYGO : $(shell command -v tinygo ...)存在 TinyGo 时用tinygo build -target wasip1 -buildmodec-shared否则用 Go 官方工具链交叉编译。PDK 变更触发重建PDK_GO_SOURCES、PDK_PY_SOURCES、PDK_RS_SOURCES递归收集plugins/pdk/下的源码作为依赖修改 PDK 会自动触发示例重建。.ndp打包规则Go 插件通过zip -j $ $*/manifest.json plugin.wasm将 manifest 与 wasm 压入包内Python 与 Rust 同理。另外不带扩展名直接执行make minimal也会被.PHONY规则映射到make minimal.ndp。清理构建产物使用make clean该目标会删除所有.ndp与.wasm文件并对 Rust 插件执行cargo clean。手工构建不依赖 Makefile如果你想脱离 Makefile 手工复现例如在自己的插件项目中使用Go 插件的标准流程是go mod tidy tinygo build -o plugin.wasm -target wasip1 -buildmodec-shared . zip -j minimal.ndp manifest.json plugin.wasm测试插件两种方式方式一Extism CLI不启动 Navidrome任何插件都可以在不运行 Navidrome 的情况下单独测试。步骤是先从.ndp包中解出plugin.wasm再用extism call调用其导出函数# 解出 wasm.ndp 本质是 zip unzip -p minimal.ndp plugin.wasm minimal.wasm # 调用能力函数以元数据代理为例 extism call minimal.wasm nd_get_artist_biography --wasi \ --input {id:1,name:The Beatles}对于需要发起 HTTP 请求的插件如 wikimedia必须用--allow-host显式放行目标域名这与 Navidrome 沙箱的主机白名单机制一致unzip -p wikimedia.ndp plugin.wasm wikimedia.wasm extism call wikimedia.wasm nd_get_artist_biography --wasi \ --input {id:1,name:Yussef Dayes} \ --allow-host query.wikidata.org \ --allow-host en.wikipedia.org--wasi标志启用 WASI 支持Go 插件以wasip1目标编译依赖 WASI 接口--input传入 JSON 格式的能力函数入参。方式二在 Navidrome 内联机测试将.ndp文件复制到你的插件目录默认data-folder/plugins/在navidrome.toml中启用插件[Plugins] Enabled true Folder /path/to/plugins对元数据代理类插件把它加入 agents 列表Agents lastfm,spotify,wikimedia补充说明Agents是有序的Navidrome 会按顺序询问各代理因此插件排在越靠前越优先被采用。若Enabled未开启或插件未放入Folder指定目录插件不会出现在管理界面中。创建你自己的插件三种起步路径方案一从 minimal 复制改造cp -r minimal my-plugin cd my-plugin # 编辑 main.go 和 manifest.json tinygo build -o plugin.wasm -target wasip1 -buildmodec-shared . zip -j my-plugin.ndp manifest.json plugin.wasm这是最快的起步方式。以 minimal 为例其核心代码见 plugins/examples/minimal/main.go展示了 Navidrome 推荐的Register()注册模式package main import ( github.com/navidrome/navidrome/plugins/pdk/go/metadata ) // minimalPlugin 实现 metadata provider 接口 type minimalPlugin struct{} // init 中注册插件实现 func init() { metadata.Register(minimalPlugin{}) } // 编译期断言确保实现了 ArtistBiographyProvider 接口 var _ metadata.ArtistBiographyProvider (*minimalPlugin)(nil) // GetArtistBiography 返回占位传记 func (p *minimalPlugin) GetArtistBiography(input metadata.ArtistRequest) (*metadata.ArtistBiographyResponse, error) { return metadata.ArtistBiographyResponse{ Biography: This is a placeholder biography for input.Name ., }, nil } func main() {}配套的 manifest.json 只有四个字段这也是.ndp包元数据的最低要求{ name: Minimal Example, author: Navidrome, version: 1.0.0, description: A minimal example plugin }关于metadata.Register()模式需要理解两点详见 minimal/README.md它替代了手工//go:wasmexport导出函数的方式由 PDK 的metadata包自动生成所有nd_*导出metadata包中可实现的 provider 接口是增量式的ArtistMBIDProviderMusicBrainz ID、ArtistURLProvider外部 URL、ArtistBiographyProvider传记、SimilarArtistsProvider相似艺人、ArtistImagesProvider艺人图片、ArtistTopSongsProvider热门单曲、AlbumInfoProvider专辑信息、AlbumImagesProvider专辑图片等只实现你数据源支持的即可其余方法不必实现。向 minimal 扩展更多能力时只需让minimalPlugin实现更多 provider 接口例如ArtistMBIDProvider- 获取艺人 MusicBrainz IDArtistURLProvider- 获取艺人外部 URLSimilarArtistsProvider- 获取相似艺人ArtistImagesProvider- 获取艺人图片ArtistTopSongsProvider- 获取艺人热门单曲AlbumInfoProvider- 获取专辑信息AlbumImagesProvider- 获取专辑图片方案二用 XTP CLI 脚手架生成从能力 schema 生成样板代码适合从规范出发、按模板工程的思路开发# 安装 XTP CLI 后执行 xtp plugin init \ --schema-file ../capabilities/metadata_agent.yaml \ --template go \ --path ./my-plugin \ --name my-plugin # 然后创建 manifest.json 并打包 cd my-plugin xtp plugin build zip -j my-plugin.ndp manifest.json dist/plugin.wasm在仓库根目录视角下schema 文件应写作plugins/capabilities/metadata_agent.yaml。plugins/capabilities/目录下提供了官方的能力 schemametadata_agent.yaml– 艺人/专辑元数据scrobbler.yaml– 刮擦集成lifecycle.yaml– 初始化回调scheduler_callback.yaml– 定时任务websocket_callback.yaml– WebSocket 事件方案三使用其他语言参考语言专属示例Python 看 coverartarchive-pyRust 看 webhook-rs。三种语言的实际写法差异将在下一节深入拆解。示例深度拆解从能跑到会写MinimalGo最简骨架演示要点manifest 导出、单一能力函数、基础输入输出处理。如上节所示核心是空main()init()注册 编译期接口断言 实现 provider 方法四件套。注意func main() {}是 Wasm 插件必需的占位入口。WikimediaGo真实世界的元数据代理这是最值得精读的 Go 示例它把元数据代理的实战要素全部串了起来见 plugins/examples/wikimedia/main.go对外部 API 发 HTTP 请求通过宿主服务host.HTTPSend调用而不是直接使用 Go 标准库或 Extism 自带 HTTPNavidrome 禁用了 Extism 内置 HTTPhost.HTTPSend是唯一受支持的方式。请求封装为host.HTTPRequest{Method, URL, Headers, Body, TimeoutMs}例如sparqlQuery函数向 Wikidata 发送 POST 请求并声明Accept: application/sparql-resultsjsonmain.go#L77-L109。SPARQL 查询Wikidata构造SELECT ?sitelink WHERE { ?artist wdt:P434 mbid ... }之类的查询优先用 MBIDwdt:P434属性定位其次回退到rdfs:label名称匹配同时还会向 DBpedia 的 SPARQL 端点查询并调用 MediaWiki APIen.wikipedia.org/w/api.php获取页面摘要作为艺人传记。错误处理与降级链GetArtistURL的查找顺序是 Wikidata → DBpedia → 维基百科搜索 URL 兜底main.go#L251-L282GetArtistBiography则是先定位 Wikipedia URL取页面摘要失败后再回退 DBpedia 的rdfs:comment短简介main.go#L285-L334。配合pdk.Log输出 Debug/Info 级别的日志辅助排查。主机白名单Host Allowlisting在 manifest.json 中声明permissions.http.requiredHosts为query.wikidata.org、dbpedia.org、en.wikipedia.org。沙箱只放行这些域名本地 CLI 测试时则用--allow-host等价放行。这也是为什么该插件需要三个数据源域名都列入白名单——任一遗漏都会导致请求被沙箱拦截。Crypto TickerGo多能力的实时数据演示演示了 Lifecyclend_on_init插件加载完成后初始化连接、SchedulerCallback心跳与超时管理与 WebSocketCallback维持与行情服务的实时长连接的组合用法是理解多能力并存的最小完整案例初始化时建立 WebSocket定时器驱动心跳与断线重连推送行情更新。Cover Art ArchivePythonPython 元数据代理演示 extism-py 插件的结构Python 源码位于plugin/__init__.py通过extism.plugin_fn导出nd_*能力函数通过extism.import_fn(extism:host/user, ...)导入宿主函数发起 HTTP 请求、处理 JSON 响应最后打包为 wasm。它同时示范了 Python 插件与 Go 插件在宿主函数导入方式上的根本差异Go 用 PDK 封装Python 需手工声明导入并自行处理内存偏移与 JSON 编解码。Now Playing LoggerPythonScheduler SubsonicAPI这个示例见 plugins/examples/nowplaying-py/plugin/init.py值得单独精读因为它展示了 Python 侧调用宿主服务的完整样板导入宿主函数extism.import_fn(extism:host/user, scheduler_schedulerecurring)与extism.import_fn(extism:host/user, subsonicapi_call)init.py#L28-L37说明宿主服务统一挂在extism:host/user命名空间下。封装层手写 wrapper 完成请求 JSON →extism.memory.alloc分配内存 → 传入 offset → 读取返回 offset →extism.memory.string取回 JSON → 检查error字段的标准调用链init.py#L47-L96。Lifecycle 中注册定时任务nd_on_init中读取配置项cron默认*/1 * * * *每分钟调用scheduler_schedule_recurring注册循环任务scheduleId固定为nowplaying-checkinit.py#L104-L120。SchedulerCallback 中消费事件nd_scheduler_callback里校验scheduleId后以配置项user默认admin调用getNowPlaying?uuser子sonic API解析subsonic-response.nowPlaying.entry并逐条打印谁在听什么歌init.py#L123-L168。注意subsonicapi_call是进程内调用Subsonic API无网络往返。WebhookRustRust Scrobbler展示 Rust 插件的完整结构见 plugins/examples/webhook-rs/src/lib.rs宏注册导出nd_pdk::register_scrobbler!(WebhookPlugin)一行生成全部 Scrobbler WASM 导出lib.rs#L23。实现Scrobblertrait必须实现is_authorized、now_playing、scrobble、playback_report四个方法前文提到 Scrobbler 四个方法均必选。极简依赖仅依赖extism-pdk与nd-pdk宿主 HTTP 通过nd_pdk::host::http::send调用配置通过extism_pdk::config::get(urls)读取逗号分隔的 webhook 地址列表scrobble 事件到达时对每个 URL 发起带查询参数的 GET 请求lib.rs#L59-L115。配置示例[PluginConfig.webhook-rs] urls https://example.com/webhook1,https://example.com/webhook2Library InspectorRustLibrary Scheduler 组合在nd_on_init中注册周期任务nd_scheduler_callback触发时通过library::get_all_libraries()宿主服务读取全部音乐库的统计信息歌曲数、专辑数、艺人数、总大小、总时长等并输出日志展示定时轮询 库元数据只读访问这一典型运维型插件模式。Discord Rich PresenceRust最复杂的综合案例官方把它当作多能力插件的标杆覆盖了Scrobbler– 接收播放事件WebSocket– 维持与 Discord Gateway 的长连接Scheduler– 心跳与超时管理Cache– 连接状态存储进程内 TTL 缓存Artwork– 获取专辑封面 URL 用于展示它同时使用 HTTP、WebSocket、Cache、Scheduler、Artwork、Config 六个宿主服务是理解插件如何与外部实时服务集成的最佳全景参考。注意其 manifest 中 WebSocket 权限的requiredHosts是必填的如*.discord.gg这与 HTTP 权限未声明requiredHosts时仅允许公网地址的行为不同。深入学习资源插件系统完整文档能力函数签名表MetadataAgent 的 11 个函数、Scrobbler、Lyrics、SonicSimilarity、TaskWorker、Lifecycle、SchedulerCallback、WebSocketCallback、全部宿主服务HTTP/Scheduler/Cache/KVStore/Storage/Task/WebSocket/Library/Matcher/Artwork/SubsonicAPI/Config/Users/ScrobbleRetriever的参数与 Go/Rust 用法示例、navidrome plugin命令行管理工具、安全模型主机白名单、受限文件系统、禁止监听端口、配置隔离、用户范围授权。plugins/capabilities/能力 schemaYAML供 XTP CLI 脚手架与参考实现使用。plugins/pdk/官方 PDK 源码Go、Rust、Python、JS其中 Go 侧提供metadata、scrobbler、lyrics、sonicsimilarity、taskworker、lifecycle、scheduler、websocket、host、types、pdk等类型安全包是编写 Go 插件时最重要的标准库。各示例目录内的 README 与源码minimal/README.md、wikimedia/README.md、crypto-ticker/README.md、coverartarchive-py/README.md、nowplaying-py/README.md、webhook-rs/README.md、library-inspector-rs/README.md、discord-rich-presence-rs/README.md每个都包含该示例独有的构建与配置说明。小结一条完整的插件开发链路综合官方示例一条完整的插件开发链路是选语言Go 体验最佳 / Rust 性能最优 / Python 原型最快→选起点复制 minimal 或xtp plugin init脚手架→声明 manifestname、author、version必填权限按需声明并遵循最小权限原则→实现能力函数Go 用metadata.Register()等 PDK 注册模式Rust 用register_scrobbler!宏Python 用extism.plugin_fn→按需调用宿主服务host.HTTPSend、scheduler_schedule_recurring、subsonicapi_call等→构建打包tinygo buildzip -j x.ndp manifest.json plugin.wasm或用make系列目标→先测后装Extism CLI 带--allow-host单测再复制.ndp到插件目录并在navidrome.toml启用。按这条链路从plugins/examples/出发你可以在数小时内产出第一个可运行的 Navidrome 插件。赞分享后端音视频前端【免费下载链接】navidrome Your Personal Streaming Service项目地址https://gitcode.com/gh_mirrors/na/navidrome点击查看免费下载相关推荐TiKV 协处理器插件示例编写指南从 dylib 构建到插件注册TiKV 协处理器插件示例编写指南从 dylib 构建到插件注册 导读 TiKV 在 v2 协处理器框架 coprocessor v2 中提供了可插拔的插数据库KV存储分布式数据库云原生HunterPie为《怪物猎人世界》打造的专业级实时监控与数据可视化增强工具HunterPie为《怪物猎人世界》打造的专业级实时监控与数据可视化增强工具 你是否曾在《怪物猎人世界》的激烈狩猎中因为无法准确掌握怪物血量状态而错失最后端音视频前端Penpot 插件开发实战指南运行官方示例插件与从零构建自定义插件Penpot 插件开发实战指南运行官方示例插件与从零构建自定义插件 Penpot 的插件体系Penpot Plugins为开源设计平台提供了一个可扩展的运前端设计系统图形学协同办公上一篇xcit_tiny_12_p8_384.fb_dist_in1k模型蒸馏技术详解知识蒸馏在图像分类中的应用下一篇RVC 低资源语音转换终极指南10 分钟录音训练 AI 语音克隆手把手跑通全流程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考