【免费下载链接】myspotiNative Android client for Spotify, built with Jetpack Compose项目地址https://gitcode.com/gh_mirrors/my/myspoti点击查看免费下载Myspoti 是一款原生 Android 的 Spotify 客户端通过 Jetpack Compose 构建支持免广告播放、离线下载和逐字歌词。它的扩展系统允许开发者用一个 JavaScript 文件加一个manifest.json接入歌词、音源、下载、首页分区、菜单按钮甚至登录自己的服务器。本文面向新手逐项详解 Myspoti 扩展 API 中的 Actions权限、Hooks钩子与myspoti对象全部能力帮你快速上手 Myspoti 扩展开发。一、Myspoti 扩展机制总览 一个扩展就是两个文件manifest.json声明扩展的身份信息和它能做什么actions列表main.js实际逻辑运行在沙箱里。Myspoti 在沙箱中执行脚本能做的事完全由一份封闭的 Actions 目录决定。每个 action 都有固定图标、简短标签、安全级别normal / critical和它解锁的 API用户在安装前会看到每个 action 及其理由why。沙箱严格执行清单声明调用未声明的能力会直接抛错。官方完整文档docs/extensions/API.md最小可运行的扩展长这样示例来自官方 lrclib 歌词样例myspoti.provide(lyrics, function (track) { var r myspoti.http.get(https://lrclib.net/api/get? myspoti.query({ track_name: track.title, artist_name: track.artist })); if (!r.ok) return null; // 返回 null 我没有答案App 继续问其他来源 return { provider: LRCLIB, lines: parseLrc(r.json().syncedLyrics) }; });二、manifest.json 字段逐项详解 清单放在扩展包根目录未知字段会被忽略。核心字段如下完整规则见 API.md 第 2 节字段必填说明id✅反向域名式小写 id如io.github.you.lyrics发布后永不改变name/version/versionCode✅展示名版本号。versionCode越大越新是升级比较的依据author/description作者必填最多 60 / 500 字符actions✅从第 4 节目录里选每项{ name, why, hosts? }why 必填1~80 字符展示给用户settings❌用户可调的选项类型支持text、secret、toggle、number、choice、button需要settings.pageactioncategory/tags❌商店分类lyrics、playback、library、discovery、stats、look、social、tools、other与搜索标签minAppVersion❌兼容的最低 Myspoti 版本旧版本会显示需要 X 或更新replaces/conflictsWith❌替代 / 与谁互斥的扩展 id各最多 10 个changelog/welcome/homepage/icon❌更新说明、首次安装引导、主页、图标≤256px 方形 PNG打包约束zip ≤ 2 MB、≤ 30 个文件、脚本 ≤ 1 MB、图标 ≤ 256 KB且每次构建结果一致固定顺序与日期任何人可重建并比对 sha256。两个官方样例可直接参考docs/extensions/samples/lrclib-lyrics/manifest.json歌词 网络 设置页docs/extensions/samples/blocks-demo/manifest.json全部 UI 块类型演示三、Actions 权限目录逐项详解 Actions 是一份封闭目录用户安装时看到图标、标签和你的whycritical 级别会用警示色标出。逐项列表图标与级别以 API.md 第 4 节 为准Action级别解锁的能力playback.controlnormalmyspoti.player.*播放控制Spotify 播放/暂停/快进/随机/音量/倍速/切设备playback.queuenormal编辑 Spotify 播放队列加入、下一首播放、移动、移除、清空playback.eventsnormalmyspoti.player.current()、track/playback事件、播放器状态读取lyrics.providenormallyrics钩子提供歌词trackinfo.providenormaltrackinfo钩子在歌曲演职员表下方加原生块audio.sourcecriticalaudio-source钩子从外部地址播放音频顺序询问download.sourcecriticaldownload-source钩子提供可下载文件顺序询问home.sectionsnormalhome钩子在首页末尾加分区search.providenormalsearch钩子在搜索结果下方加内容menu.itemsnormalmenu钩子往歌曲/专辑/歌单/艺人 ⋯ 菜单加条目player.buttonsnormalplayer钩子在播放器控制区下加按钮settings.pagenormal独立设置页、myspoti.settings、setting事件notifynormalmyspoti.notify()屏幕短消息library.readnormal读资料库、 liked songs、用户、最近、设备列表、Blends 读取library.writecritical资料库增删、关注、隐私会话、口味屏蔽等写操作playlists.writecritical歌单编辑、Blends 邀请/加入/改名/退出spotify.catalognormalSpotify 搜索、目录、公开歌单、首页、播客等浏览spotify.rawcriticalraw.gql/raw.service/raw.request等完整访问可声明固定写操作networknormal*为 criticalmyspoti.http访问清单里列出的主机whenOnline与online事件webview.pagecritical扩展自己的锁定 WebView 页面page/message钩子webview.authcriticalmyspoti.auth.open()网站登录独立浏览器 profilestoragenormalmyspoti.storage本地存储共 512 KBattestnormalmyspoti.attest硬件密钥证明向自己的服务器证明这真是 Myspoti关键规则不能单独取消勾选要么授予扩展列出的全部 action要么不装Additive叠加型歌词、详情、首页、搜索、菜单、按钮——每个扩展都问答案按用户排序合并Ordered顺序型audio.source与download.source——按用户在设置里排的顺序逐个询问直到有人回答破坏性 Spotify 写操作删除、清空等运行时逐次弹确认框可给raw.request的写操作选Always allow。四、Hooks 钩子逐项详解 钩子是 App 主动询问扩展的固定时点用myspoti.provide(name, fn)注册。fn同步接收一个对象并同步返回答案不能返回 Promise返回null/undefined表示没有答案抛错或超时记为该扩展的最后错误。完整定义见 API.md 第 3 节。钩子所需 Action输入回答lyricslyrics.providetrack歌词对象带时间戳行 / 纯文本audio-sourceaudio.sourcetrack含ahead预取标记{ url, headers?, expiresInMs?, codec?, bitDepth?, sampleRate?, … }或 DASH manifestdownload-sourcedownload.sourcetrack qualityhi-res/cd/small文件列表最多 10 个按优劣排序支持flac、dash-flac、m4a、mp3trackinfotrackinfo.providetrack原生块列表显示在歌曲演职员表下方homehome.sections{}首页末尾的分区块每扩展最多 2 个分区searchsearch.provide{ query }搜索结果下方的块menumenu.items{ kind, uri, title, subtitle }menu块每扩展 2 条playerplayer.buttonstrackbutton块每扩展 1 个page/messagewebview.page{}/ 页面 post 的消息{ title?, html }/ 回传页面的回复tap任一 blocks action{ action, surface, context }无点击回调处理完可再刷新界面status无需 action{}{ live: true/false, detail? }5 分钟一次的存活探测live: false时音源/下载被跳过歌词lyrics要点同步歌词{ provider, synced: true, lines: [{ time, end?, text, words? }] }每行 ≤500 字符总行数 ≤3000词级时间戳每行最多 200 个词非同步歌词{ plain: 一行一句的文本 }时间单位是毫秒没有内容的歌词等同无答案。音源audio-source要点返回url后歌曲在Myspoti 自己的播放器中播放不走 Spotify 播放器也支持Lossless DASH返回 base64 的 MPEG-DASH manifest≤1 MBMyspoti 按段顺序播放、可拖动先检查myspoti.features.indexOf(audio.manifest) 0ahead: true表示提前 10 秒预取下一首expiresInMs声明地址有效期复用最长 10 分钟401/403/404/410 会自动重新询问一次声明codec/bitDepth/sampleRate会在播放时显示音质行如 FLAC · 24-bit · 96 kHz。下载download-source要点输入含用户所选quality返回的文件按你的顺序逐一校验FLAC 必须是真 FLACm4a/mp3 必须含手机可解码的音轨且时长与 Spotify 记录相差不超过 -5s/15sdash-flac用 base64 manifest 代替urlMyspoti 会抓取分段并合成完整 FLACisrcMatched: true仅当你确认这个文件就是这首歌按 ISRC 找到的时声明——Myspoti 本身不与参考录音比对。原生块Blocks扩展不画 UI只描述 JSON扩展永远不自己绘制界面而是返回原生块的 JSON由 App 用自己的字体、配色和图标绘制标注From X。块类型blocks-demo 样例 每种都演示了一个类型关键字段出现位置sectiontitle、blocks≤12不可嵌套首页 / 搜索 / 歌曲详情cardtitle、subtitle?、image?open或action同上tracks/albums/playlists/artistsitems: [{ uri, title, subtitle?, image? }]≤50歌曲可播放其余打开对应页面buttonlabel、icon、action含播放器menulabel、icon、action仅 ⋯ 菜单texttext≤1000、style:title/body/caption首页 / 搜索 / 详情imageurlhttps 公网、ratio?0.5~3、open或action首页 / 搜索 / 详情open只能打开spotify:uritrack/album/playlist/artist/show/episode不能打开网页action是 1~64 字符的自定义 id点击时触发你的tap钩子图标从固定名称表选add、download、favorite、shuffle等不认识的按extension显示myspoti.ui.refresh(home|search|menu|player|trackinfo)可请求 App 重新询问。网页page / message与网站登录authwebview.page给扩展一个免费页面≤512 KB HTML在锁定的 WebView 中展示无导航、无 cookie、无存储资源只能 GET 你network里列的主机页面与脚本之间用MyspotiPage.postMessage()与message钩子通信webview.auth是独立登录页myspoti.auth.open({ url, callback })立刻打开并返回 id到达回调自定义 scheme 或 https 地址后myspoti.on(auth)收到{ id, url }独立 profile 的 cookie 在多次登录间保留扩展拿不到 cookiehidden: true可先静默加载8 秒无人介入才全屏展示——适合通常无需人工的校验错误回调closed、timeout3 分钟、network: …。五、事件逐项详解 事件所需 Action说明trackplayback.events每首新歌开始时收到歌曲字段 origin/providerId用于区分音频来源playbackplayback.events播放全程事件流start/progress每 10s/pause/resume/seek/skip/end含positionMs、playedMs、sourcelocal/spotify、reason等onlinenetwork网络恢复时触发配合myspoti.work.whenOnline()补发离线队列30s 时限settingsettings.page用户改设置时收到{ key }button类型设置收到{ key, pressed: true }authwebview.auth网站登录完成或出错每次投递限时 3 秒setting为 30 秒监听器内报错只记日志、不抛出同一事件的后续监听器仍会执行。六、myspoti 对象逐项详解 脚本跑在 Rhino 1.8ES6 语法可用的独立线程上只能看到标准 JS 对象、myspoti和console没有require、fetch、定时器、DOMeval与从字符串构造函数一律被禁code from strings is not allowed in extensions。一切调用都是同步的。基础信息与生命周期调用说明myspoti.apiVersion当前为1myspoti.extension清单里的{ id, name, version }myspoti.features本机支持的增强能力列表audio.manifest、audio.expires、audio.quality、audio.ahead、http.all、status、attest等旧版本没有此属性检测写法myspoti.features myspoti.features.indexOf(name) 0myspoti.provide(hook, fn)/myspoti.on(event, fn)注册钩子 / 事件重复注册同名钩子会覆盖myspoti.work.whenOnline()请求一次online事件需要network网络myspoti.httpget/post/request返回{ status, headers, body, ok, json() }4xx/5xx 不抛错网络失败、主机被拒或超限才抛Error(http: ...)。规则由 App 强制只能访问清单里列出的主机*.domain匹配子域https 优先明文 http 仅限清单精确命名的主机本地地址一律拒绝localhost、内网段、IPv6 字面量无 cookie、无缓存、不自动跟随重定向默认User-Agent为Myspoti-Extension/1 (id)超时默认 15s钳制在 1~20s响应体 ≤ 5 MB120 次/分钟滑动窗口myspoti.http.all([...])一次并发最多4 个请求脚本仍保持同步失败项以{ error }占位需要http.all特性。存储、设置与工具调用说明myspoti.storage.get/set/remove(key)自己的 JSON 存储键值合计 512 KB写满抛storage full (512 KB)myspoti.settings.get(key)用户值 → 清单默认值 →undefinedbutton类型无值myspoti.notify(text)屏幕短消息≤200 字符带扩展名需要notifymyspoti.log(...)/console.log/info/warn/error同一日志≤2000 字符myspoti.query(obj)生成查询串null/undefined自动省略myspoti.util.base64Encode/Decode、md5/sha1/sha256、hmacSha256UTF-8 / 十六进制摘要myspoti.ui.refresh(place)请求刷新指定界面myspoti.page.post(data)向自己打开的页面发数据本机播放器myspoti.playercurrent()当前歌曲或null、play()/pause()/next()/previous()/seek(ms)全部经播放仲裁器执行两个扩展 2 秒内发出同类命令时Playback 区排序靠前者胜出30 秒内互相矛盾 3 次后者会被暂停其播放命令并通知用户每扩展每分钟最多 20 条命令。Spotify 账号访问myspoti.spotifymyspoti.spotify.area.method(...)直接操作 Myspoti 中登录的账号。共 13 个区域API.md 第 6 节 有完整方法表区域典型方法所需权限playerstate、queue、play、pause、seek、next、setShuffle、setRepeat、addToQueue、setVolume、setSpeed、media读 playback.events写 playback.control/playback.queuesearchall、tracks、artists、albums、genres、recent、clearRecentspotify.catalogcatalogtrack、album、albumTracks、artist、artistTopTracks、discography、appearsOn、similarAlbumsspotify.cataloglibrarycontains、items、likedTracks、add、remove、pin、文件夹增删改移读 library.read写 library.writeplaylistsplaylist、tracks、create、rename、addTracks、removeTracks、setCover等 26 个方法catalog/library.read/playlists.writehomefeed、categories、category、whatsNewspotify.catalogpodcastsshow、episodes、episode、audioUrl、audiobook、savedEpisodes读catalog写library.writeusersme、profile、followers、top、friendActivity、history、follow读library.read写library.writeextraslyrics、canvas、credits、radio、口味/封禁管理spotify.catalog/library.writedeviceslist、transfer、pullHerelibrary.read/playback.controlrecentsrecentEntrieslibrary.readblendsinvitation、group、story、invite、join、rename、leave读library.read写playlists.writerawoperations、gql、service、get、request携带账号凭据访问*.spotify.com/*.spotifycdn.comspotify.raw使用规则参数按位置传递URI 为字符串列表 ≤1000 项枚举按名称传、结果为大写名称总参数 ≤256 KB错误以Error抛出消息以spotify.area.method:开头用户拒绝或 120 秒未应答会抛the user refused记得 catch限制60 次调用/分钟、响应 ≤2 MB、必须在钩子时限内完成需确认的调用所有删除/清空类方法、raw.gql的 mutation、raw.service总是、非 GET/HEAD 的raw.request可用 Always allow 按 methodhost路径模式授权结果统一为普通 JSONPageT是{ items, offset, total, nextOffset }枚举为大写名深度截断到 12 层。硬件证明myspoti.attest用于和你的服务器通信时证明请求来自一台真的在跑该扩展的 Myspotizip 里没有秘密可言密钥只能由硬件 keystore 生成调用作用enroll(challenge)在硬件 keystoreStrongBox/TEE中为本扩展创建 EC P-256 签名密钥返回{ publicKey, certChain }每小时最多 5 次publicKey()当前公钥未注册为nullsign(text)对 ≤64 KB 文本做 ECDSA-SHA256 签名120 次/分钟reset()删除密钥卸载扩展也会删它证明密钥在硬件中、由 App 包创建、且由你的服务器发起 challenge但不能证明 App 未被篡改root 场景也不证明用户身份——建议配合按密钥限频。桌面调试器用的是软件测试密钥服务端按正式流程校验时应拒绝。七、限制一览表 项目限制脚本顶层加载3 秒钩子调用按类型lyrics8s、audio-source15s、download-source30strack/playback事件3 秒/次myspoti.http120 次/分、5 MB/响应、20s/请求、并发 4myspoti.spotify60 次/分、256 KB 参数、2 MB/响应storage512 KB歌词3000 行、每行 500 字符、每行 200 词下载10 个文件/次、DASH manifest 1 MBnotify/log200 / 2000 字符包体2 MB zip、30 文件、1 MB 脚本、256 KB 图标八、开发、测试与发布流程 官方命令行工具myspoti-ext在电脑上按 App 相同的方式运行扩展构建与用法见 docs/cli.md入口 tools/myspoti-cli命令作用check folder打印清单问题、以用户视角列出每个 action并用样例触发一遍 blocks 钩子校验块合法性run folder\|zip lyrics --title T --artist A调用指定钩子并打印 App 解析后的答案audio-source、download-source、home、menu、status、track、playback等同理pack folder校验并构建确定性 zip打印 sha256 与索引条目index zip目录 名称为扩展仓库生成index.json要点不加--cdp时所有myspoti.spotify调用会抛错适合测歌词/音源代码加上--cdp PORT后走你本机 Chrome 里已登录的 Spotify Web Player 做真实调用需确认的调用会在终端问y/Ncheck只跑顶层代码、不触发钩子、无账号无网络run才能暴露钩子内部问题发布在自己的仓库加myspoti-extension话题商店会自动发现6 小时内升级只有在不新增 action/主机/why 时才自动生效否则显示Update needs your OK卡片让用户逐项确认扩展源码实现在 base/extensions/如 Actions.kt、Hooks.kt。九、安全模型新手最容易踩的边界 ️隔离每个扩展独立线程、存储、设置、日志与登录 profileAPI 中不存在别的扩展块点击与页面消息只回到画它的扩展沙箱白名单清单没声明的能力调用即抛错x is not in this extensions manifest (actions)确认机制破坏性写操作逐次询问用户120 秒未答即拒绝raw.request写操作可被Always allow授权并可在扩展页撤销网络面收窄network主机清单之外的地址直接拒绝本地地址永不放行无 cookie受保护界面扩展无法遮挡、延迟或观测 App 的捐赠提醒、新版本卡片、安装确认框、报告按钮与关于页。总结 Myspoti 扩展 API 的设计核心可以概括为三句话Actions 声明能力边界Hooks 定义触发时机myspoti对象提供全部同步工具。想写一个歌词扩展从 lrclib 样例 复制起步只需lyrics.providenetwork两个 action想做 UI 增强参考 blocks-demo 样例 掌握 7 种原生块要读写 Spotify 账号则逐节对照第 6 节方法表选择最小权限。完整规范始终请以 docs/extensions/API.md 为准——本文覆盖的是 API version 1 的全部内容。赞分享【免费下载链接】myspotiNative Android client for Spotify, built with Jetpack Compose项目地址https://gitcode.com/gh_mirrors/my/myspoti点击查看免费下载相关推荐Starlight 前端配置Frontmatter完全参考内置字段逐项详解与 Schema 扩展实战Starlight 前端配置Frontmatter完全参考内置字段逐项详解与 Schema 扩展实战 Starlight 借助内容集合content c文档前端开发工具Lepton API 参考扩展接口详解Lepton API 参考扩展接口详解 概述 Lepton 提供了一套完整的 APIApplication Programming Interface应用桌面应用开发工具Myspoti 扩展开发快速入门5 分钟写出第一个扩展打包发布到 GitHub 商店Myspoti 扩展开发快速入门5 分钟写出第一个扩展打包发布到 GitHub 商店 Myspoti 是一款基于 Jetpack Compose 打造的原生上一篇【免费下载】 PyRadiomics 安装与使用教程下一篇MediaInfo终极指南如何快速获取多媒体文件详细信息创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考