添加英语文档

This commit is contained in:
gitbobobo
2025-03-21 16:56:39 +08:00
parent c70a0cacc4
commit 696c266a75
66 changed files with 15388 additions and 15721 deletions

View File

@@ -2,6 +2,8 @@
支持 Android、iOS、MacOS、Windows 平台的 Subsonic/Navidrome/Jellyfin/Emby/AudioStation/Plex 客户端。
简体中文 | [English](./README_en.md)
![](https://oss.aqzscn.cn/resource/blog/img/2024/60b87-ca3fefb87f148b5c03ecf069fb1f95ab.png)
本项目非开源项目。

58
README_en.md Normal file
View File

@@ -0,0 +1,58 @@
# Stream Music
A Subsonic/Navidrome/Jellyfin/Emby/AudioStation/Plex client for Android, iOS, macOS, and Windows platforms.
[简体中文](./README.md) | English
![](https://oss.aqzscn.cn/resource/blog/img/2024/60b87-ca3fefb87f148b5c03ecf069fb1f95ab.png)
**This is not an open-source project.**
For bug reports or suggestions, please create an issue under **Issues** with detailed steps and screenshots if possible.
## Download
Official Website: [music.aqzscn.cn](https://music.aqzscn.cn/)
Android/macOS/Windows: [Version Updates](https://music.aqzscn.cn/docs/versions/latest)
iOS: Search **[音流](https://apps.apple.com/cn/app/%E9%9F%B3%E6%B5%81-%E8%BF%9E%E6%8E%A5%E4%BD%A0%E7%9A%84%E9%9F%B3%E4%B9%90/id6449966496)** or `Stream Music` on App Store.
Beta Channel: [devmusic.aqzscn.cn](https://devmusic.aqzscn.cn/) (Irregular updates, limited packages).
## Platform Adaptation
Stream Music aims to support multiple platforms and music services, rather than being a professional audio player (e.g., no HiFi/audio effects tuning - I'm not an audiophile 😄).
### macOS Roadmap
- [x] Menu bar support
- [x] Dynamic window title modification
- [x] Lyrics in status bar
- [ ] Dock context menu
- [ ] Desktop UI adaptation (to align with Windows)
### Windows Roadmap
- [x] Window title modification
- [x] Media notifications
- [x] Taskbar quick actions
- [ ] Desktop lyrics
- [x] System tray minimization
- [ ] Desktop UI adaptation
### Linux Roadmap
> Not yet planned.
### tvOS/watchOS Roadmap
> Implementation pending.
## Viewing Logs
Enable Developer Mode by tapping the version number repeatedly on the About page.
> Logs older than 2 weeks are automatically cleared.
## Special Thanks
Thanks to [小众软件](https://www.appinn.com/) for featuring this project!

View File

@@ -2,18 +2,18 @@
sidebar_position: 3
---
# 功能比较
# 功能比较 {#feature}
音流的基础功能免费使用,部分功能需要购买会员解锁。
## 收费方式
## 收费方式 {#pricing}
**买断制**。一次购买,终身全平台可用。
- 会员身份可同时在 7 台设备上使用,超出最大数量后,最早登录的设备的会员身份将被取消。
- 会员验证方式采用**联网验证**,每次启动时随机触发验证,因此请尽量保证设备可以连接到互联网。
## 购买及退款方式
## 购买及退款方式 {#purchase}
仅可在手机端购买:
@@ -24,7 +24,7 @@ sidebar_position: 3
**邮箱绑定成功后暂不支持修改,因此请勿使用临时邮箱**
## 功能比较
## 功能比较 {#comparison}
<table>
<tr>
@@ -170,7 +170,7 @@ sidebar_position: 3
1. DLNA 功能目前兼容性较差,购买会员时请假定此功能不可用。
2. 通过 CarPlay 及快捷指令播放音乐时,若 APP 尚未打开,之后再次打开 APP 音乐会停止播放。
## 新版本抢先体验
## 新版本抢先体验 {#test}
音流的测试频道地址是https://devmusic.aqzscn.cn/docs/versions/latest ,这里会不定期更新最新版本,安卓版需要注意:此频道只会提供通用版本的安装包,若之前安装了其他版本的,需要卸载后才能安装通用版本。

View File

@@ -1,8 +1,8 @@
{
"label": "使用说明",
"label": "guides",
"position": 4,
"link": {
"type": "generated-index",
"description": "音流安装及使用说明。"
"description": "Installation and usage instructions for StreamMusic."
}
}

View File

@@ -2,15 +2,15 @@
sidebar_position: 5
---
# CarPlay
# CarPlay {#carplay}
## 歌词显示
## 歌词显示 {#lyrics}
苹果出于安全考量,是不允许在 CarPlay 中显示歌词的。
因此音流能做的就是只显示单行歌词,此功能需要开启「歌词 - 歌词通知」开关。
## 使用限制
## 使用限制 {#limitation}
在当前版本,必须在手机上打开音流才能使用 CarPlay。

View File

@@ -2,11 +2,11 @@
sidebar_position: 1
---
# 安装
# 安装 {#installation}
Android 和 Windows 安装教程,最新安装包可在[这里](../versions/latest)找到。
## Android
## Android {#android}
Android 一共提供四个安装包,分别对应不同的芯片架构。
@@ -18,7 +18,7 @@ Android 一共提供四个安装包,分别对应不同的芯片架构。
:::
## Windows
## Windows {#windows}
Windows 版音流目前只提供 x64 架构的 msix 格式安装包,这是微软应用商店的安装格式,因此在商店外安装,需要先在电脑上安装开发者对应的证书。
@@ -27,7 +27,7 @@ import DownloadIcon from '@mui/icons-material/Download';
<Button variant="contained" startIcon={<DownloadIcon />} href="https://oss.aqzscn.cn/stream-music/stream_music_win.crt">音流证书</Button>
### 一、标准安装方式
### 一、标准安装方式 {#standard}
双击证书文件开始安装,安装位置选择`本地计算机`
@@ -45,7 +45,7 @@ import DownloadIcon from '@mui/icons-material/Download';
安装完成后,以后就可以直接双击 `msix` 格式的安装包进行安装了。
### 二、非标准安装方式
### 二、非标准安装方式 {#legacy}
msix 格式对系统的要求较高,需要 win10 以上才可使用,对于还停留在 win7 或 win8 的用户,可通过此种方式安装。

View File

@@ -2,19 +2,19 @@
sidebar_position: 4
---
# 自定义 API
# 自定义 API {#api}
某些情况下,音乐服务提供的接口可能无法返回我们需要的信息,故提供自定义 API高级用户可以自定义返回内容。
## 鉴权(可选)
## 鉴权(可选) {#auth}
| 配置项 | 位置 | 键 | 说明 |
| -------- | -------------- | -------------- | ---- |
| 授权信息 | Request Header | Authorization | |
## 接口列表
## 接口列表 {#list}
### 获取歌词
### 获取歌词 {#lyrics}
请求方式GET
@@ -47,7 +47,7 @@ sidebar_position: 4
]
```
### 确认歌词
### 确认歌词 {#confirm-lyrics}
适用于 1.2.0 及以上版本。
@@ -81,7 +81,7 @@ sidebar_position: 4
:::
### 获取封面
### 获取封面 {#cover}
请求方式GET
@@ -104,7 +104,7 @@ sidebar_position: 4
文件流。
### 歌曲详情
### 歌曲详情 {#detail}
适用于 1.2.4 及以上版本,用于在浏览器中跳转到音乐服务对应的歌曲链接。
@@ -128,9 +128,9 @@ sidebar_position: 4
/app/media/ff.flac
```
## 简易服务
## 简易服务 {#example}
### 搭配 Nginx 加载同目录下 Lrc 文件 `@ZaneYork`
### 搭配 Nginx 加载同目录下 Lrc 文件 `@ZaneYork` {#nginx}
APP 内直接配置 API 地址为 `你的服务器地址 + /lyrics/` 即可。
@@ -154,7 +154,7 @@ APP 内直接配置 API 地址为 `你的服务器地址 + /lyrics/` 即可。
}
```
### 搭配 php 返回同名 Lrc 文件 `@lingluos`
### 搭配 php 返回同名 Lrc 文件 `@lingluos` {#php}
在Linux系统上使用php方法返回lrc文件 要求lrc文件和歌曲文件名称完全相同

View File

@@ -2,9 +2,9 @@
sidebar_position: 5
---
# 其他
# 其他 {#other}
## 分区
## 分区 {#partition}
部分用户不止用音流聆听音乐,还会用音流收听有声书,而媒体库的分区功能可以很好的区分不同类型的音频,避免干扰到我们想要聆听的内容。
@@ -15,7 +15,7 @@ sidebar_position: 5
- 对于 Emby ,可以将媒体库类型设置为有声读物或音乐。
- 对于 Jellyfin 和 Plex只能将媒体库类型设置为音乐因为 Jellyfin 的书籍类型包含对文本类型书籍的支持,数据的展示方式和音乐是截然不同的。
## 列表元素
## 列表元素 {#list}
绿色序号表示您从未听过这首歌,这在听有声书时会比较有用。
@@ -29,7 +29,7 @@ sidebar_position: 5
![](https://oss.aqzscn.cn/resource/blog/img/2024/7ec2a-423ad72f94ace289a7d801936d02e3f6.png)
## 设备间同步配置信息
## 设备间同步配置信息 {#qr}
您可能会在多个设备安装音流,每次安装后都要输入一遍甚至更多遍服务器信息,想必是非常痛苦的。
@@ -44,7 +44,7 @@ sidebar_position: 5
:::
## 歌词
## 歌词 {#lyrics}
目前只支持 LRC 格式的歌词,详细可参考 [维基百科](https://zh.wikipedia.org/wiki/LRC%E6%A0%BC%E5%BC%8F)。

View File

@@ -2,13 +2,13 @@
sidebar_position: 3
---
# 播放逻辑
# 播放逻辑 {#playback}
音流的播放逻辑与常见音乐 APP 并不完全一致,加入了一些我自己的理解。
若您初次使用音流,强烈建议您阅读此章节以更加得心应手地使用音流。
## 播放模式
## 播放模式 {#mode}
音流默认是队列播放,如需循环播放,可打开此开关,对队列播放和随机播放都会生效。
@@ -33,7 +33,7 @@ sidebar_position: 3
反之,从播放列表或播放页面切换播放模式则是临时操作,仅当次生效。
## 播放控制
## 播放控制 {#control}
![](https://oss.aqzscn.cn//resource/blog/img/2023/15d11e29bb8e27f58378743eb86f6fd0.png)
@@ -41,7 +41,7 @@ sidebar_position: 3
从歌词区域向右滑动切换上一曲,向左滑动切换下一曲。
## DLNA
## DLNA {#dlna}
- 目前 DLNA 功能会将服务器的播放地址投送到 DLNA 设备上,因此请保证 DLNA 设备可以连接到服务器。
- 为提升 DLNA 兼容性,目前采用轮询方式获取 DLNA 设备的播放状态,因此部分操作可能会有 2 秒左右的延迟。

View File

@@ -2,9 +2,9 @@
sidebar_position: 2
---
# 同步模式
# 同步模式 {#sync}
## 媒体库模式
## 媒体库模式 {#library-mode}
媒体库模式下,音流需要将服务器端的歌曲列表、专辑列表和歌手列表完全同步到本地,以此获得完整的音乐库数据。
@@ -12,7 +12,7 @@ sidebar_position: 2
但凡事有利就有弊,由于需要完整同步服务端数据,**若您的曲库较大,同步过程会耗费很多的时间**。
### 自动同步
### 自动同步 {#auto}
应用启动时会检测服务端歌曲数量,如果大于本地副本歌曲数量,则增量同步缺失的数据。
@@ -24,7 +24,7 @@ sidebar_position: 2
应用启动时需要恢复上次播放列表,某些音乐服务的歌曲资源或图片资源需要登录后才能获取,因此将播放器的初始化放在了登录操作之后,若您在播放歌曲时遇到了**播放器正在初始化**的提示,请耐心等待片刻。
### 手动同步
### 手动同步 {#manual}
若自动同步无法满足您的需求,请点击音乐资料库的「立即同步」按钮手动更新本地副本。
@@ -34,7 +34,7 @@ sidebar_position: 2
:::
## 直连模式
## 直连模式 {#direct}
在直连模式下,音流不会将服务端的数据同步到本地,而是在您每次操作时单独获取数据。若您的曲库较大,可以尝试开启此选项,以提升首次进入应用时的体验。

View File

@@ -2,7 +2,7 @@
sidebar_position: 1
---
# 介绍
# 介绍 {#introduction}
音流是一款 **NAS 音乐播放器**,可以连接到您部署在 NAS 上的**音乐服务**<sup>1</sup>,能让您在**不同平台**<sup>2</sup>享受一致的音乐盛宴。
@@ -11,7 +11,7 @@ sidebar_position: 1
1. 目前支持的音乐服务: Subsonic,Navidrome,Emby,Jellyfin,AudioStation,Plex.
2. 目前支持的平台: Android 6.0, iOS 14, macOS 10.14, Windows 10.
## 要求
## 要求 {#requirements}
在使用音流之前,您必须拥有一台运行着音乐服务的 NAS因为音流是一个纯粹的音乐播放器专注于串流您已拥有的音乐并不提供任何音乐资料。
@@ -21,19 +21,19 @@ NAS 是 `家庭云存储` 的简称,如果您尚未听说过,那么音流可
:::
## 特色功能
## 特色功能 {#features}
- 🎵 兼容多种音乐服务。
- 🎙️ 支持歌词显示,通过自定义 API 还可让不提供歌词接口的音乐服务也拥有显示歌词的能力!
- 🖥️📱 使用 Flutter 构建,为您提供接近原生的使用体验,在跨平台适配上拥有无限的可能性。
## 下载
## 下载 {#download}
### iOS
### iOS {#ios}
点击跳转 [App Store 页面](https://apps.apple.com/cn/app/%E9%9F%B3%E6%B5%81-%E8%BF%9E%E6%8E%A5%E4%BD%A0%E7%9A%84%E9%9F%B3%E4%B9%90/id6449966496) 或在 App Store 搜索 `音流``Stream Music`
### Android、macOS、Windows
### Android、macOS、Windows {#other-platform}
由于音流暂未上架其他应用商店,请在[此页面](./versions/latest)查找最新版本下载。
@@ -44,7 +44,7 @@ Windows 版安装包是 msix 格式,安装方法[点此](./guides/install)查
:::
## 反馈建议
## 反馈建议 {#feedback}
请通过 GitHub 的 issue 功能提交您的宝贵意见。

View File

@@ -1,8 +1,8 @@
{
"label": "开发笔记",
"label": "developmentNotes",
"position": 9,
"link": {
"type": "generated-index",
"description": "音流开发过程的经验分享,随缘记录。"
"description": "Experience sharing during the development of StreamMusic."
}
}

View File

@@ -1,8 +1,8 @@
{
"label": "功能适配",
"label": "adaptation",
"position": 3,
"link": {
"type": "generated-index",
"description": "音流开发过程的经验分享,随缘记录。"
"description": "Experience sharing during the development of StreamMusic."
}
}

View File

@@ -8,7 +8,7 @@ sidebar_position: 1
如果您觉得音流的某个功能帮到了您,可以考虑为这些项目点亮 🌟 或提供支持。
## 界面
## 界面 {#ui}
### macos_ui
@@ -32,7 +32,7 @@ sidebar_position: 1
![](https://oss.aqzscn.cn/resource/blog/img/2024/faae1-9ad0cf3582cd7ff590b3e02645f19bc7.png)
## 平台特性
## 平台特性 {#platform}
### macos_window_utils
@@ -85,7 +85,7 @@ impl RsImage {
相比其他语言,写 Rust 代码确实会让我感到有些别扭,比如捕获异常的方式、可选值的解包、所有权借用之类的问题,但问问 GPT 大部分问题也都能解决。毕竟在多平台享受到了 Rust 的生态,这点苦吃了也无妨哈哈~
## 网络
## 网络 {#network}
### dio
@@ -125,7 +125,7 @@ dart 的 HTTP 请求是自己实现的,仅适配了标准的 HTTP 请求,处
[url_launcher](https://pub.dev/packages/url_launcher) 可用于在浏览器中打开链接。
## 音频
## 音频 {#audio}
### media_kit
@@ -534,7 +534,7 @@ if (Platform.isAndroid) {
\* The tag will be **read only**, due to lack of official support
## Flutter 社区
## Flutter 社区 {#community}
### Flutter Candies

View File

@@ -2,23 +2,23 @@
sidebar_position: 3
---
# 设计资源
# 设计资源 {#resource}
以下是 **音流 APP** 中使用到的免版权素材,若音流不小心侵犯了您的作品的权益或您有更适合在 app 中展示的免版权素材,请发送邮件至 aqzscn@qq.com 联系我进行删除或投稿,万分感谢!
## 图片背景
## 图片背景 {#image}
- [歌曲列表默认封面](https://pixabay.com/zh/vectors/record-disk-disc-music-musical-23281/) by Clker-Free-Vector-Images
- [tv端歌手详情页面默认背景](https://pixabay.com/zh/photos/concert-singer-singing-stage-2566002/) by StockSnap
## 彩色插画
## 彩色插画 {#illustrations}
- [警告](https://pixabay.com/zh/vectors/warning-caution-alert-icon-media-145066/) by OpenClipart-Vectors
- [成功](https://pixabay.com/zh/vectors/icon-symbol-confirmation-hook-ok-803718/) by Leovinus
- [错误](https://pixabay.com/zh/vectors/error-button-failure-warning-24842/) by Clker-Free-Vector-Images
- [信息](https://pixabay.com/zh/vectors/info-information-tips-icon-support-148099/) by OpenClipart-Vectors
## 单色插画
## 单色插画 {#mono}
- [tv端会员页面插画](https://pixabay.com/zh/vectors/jewelry-crown-king-royal-queen-2025491/) by OpenClipart-Vectors
- [tv端关于页面插画](https://pixabay.com/zh/vectors/found-icons-requests-1294561/) by OpenClipart-Vectors

View File

@@ -1,8 +1,8 @@
{
"label": "音乐服务",
"label": "musicServices",
"position": 2,
"link": {
"type": "generated-index",
"description": "记录音流用到的一些音乐服务接口(非全部接口,仅记录与音乐相关的),一是方便自己查阅,二是可以让有需要的人少走些弯路。可能有些地方理解不到位,欢迎大家指正和补充。"
"description": "Documenting some of the music service APIs used by Yinliu (not all APIs, only those related to music). This is to facilitate my own reference and to help others avoid some pitfalls. There may be some misunderstandings, and corrections and additions are welcome."
}
}

View File

@@ -2,13 +2,13 @@
sidebar_position: 8
---
# 开发计划
# 开发计划 {#roadmap}
## 正在进行
## 正在进行 {#working}
服务端 DLNA
## 上架安卓应用商店
## 上架安卓应用商店 {#android-distribution}
| 材料准备 | 进度 |
| --- | --- |
@@ -16,7 +16,7 @@ sidebar_position: 8
| 待定... | |
## 车机版和 TV 版
## 车机版和 TV 版 {#more-platform}
不准备单独推出车机版,现有版本适配了手机、平板的界面,只要能安装,应该就能在车机上使用。
@@ -24,7 +24,7 @@ sidebar_position: 8
Apple TV 版在调研适配可行性后,可能会在 1.4.0 开始适配,但**不保证一定会推出**。
## 适配鸿蒙next纯血版
## 适配鸿蒙next纯血版 {#ohos}
因为音流是用 Flutter 开发的Flutter 是谷歌的产品,所以 Flutter 官方支持鸿蒙的可能性极低。
@@ -36,7 +36,7 @@ Apple TV 版在调研适配可行性后,可能会在 1.4.0 开始适配,但*
:::
## 支持新的音乐服务
## 支持新的音乐服务 {#protocols}
威联通音乐套件有支持计划,敬请期待。

View File

@@ -2,7 +2,7 @@
sidebar_position: 7
---
# 常见问题
# 常见问题 {#issues}
如果软件使用过程中遇到问题或有任何建议,请在 Github 上找到 [此仓库](https://github.com/gitbobobo/StreamMusic)
@@ -15,9 +15,9 @@ sidebar_position: 7
:::
## 音乐服务
## 音乐服务 {#services}
### 无法登录
### 无法登录 {#login}
可能原因:
@@ -26,7 +26,7 @@ sidebar_position: 7
- 使用了自签名的证书或证书的证书链不完整
- 使用了代理软件,代理软件把 127.0.0.1 拦截了
### Navidrome 扫描到 50000 首歌曲后失败
### Navidrome 扫描到 50000 首歌曲后失败 {#navidrome-scan}
在 Navidrome 0.52 及之前版本,按添加时间查询歌曲的逻辑有些问题,请升级到最新版本以解决此问题。
@@ -38,15 +38,15 @@ sidebar_position: 7
:::
### 无法模糊搜索
### 无法模糊搜索 {#search}
在直连模式下,模糊搜索是否可用取决于服务端是否支持。例如,若要开启 Navidrome 的模糊搜索,需要在环境变量中开启`SearchFullString`
媒体库模式下,由客户端提供模糊搜索的特性,若您发现某个页面的模糊搜索功能失效,请及时反馈。
## 播放
## 播放 {#playback}
### 安卓后台播放自动暂停(没有声音)
### 安卓后台播放自动暂停(没有声音) {#background}
步骤 1: 音流 - 帮助 - 关闭电池优化
@@ -56,13 +56,13 @@ sidebar_position: 7
目前已在 魅族 20 和华为平板测过这样的配置就可以保持后台播放。
### 播放时总时长一直在更新
### 播放时总时长一直在更新 {#transcoding}
这表示当前歌曲正在服务端转码,播放器无法得知歌曲真实的总时长,因此会显示当前已获取的音频内容的总时长。
等待歌曲转码完成即可,这是正常现象。
### 移动网络下无法播放
### 移动网络下无法播放 {#ffmpeg}
Wi-Fi 环境可以播放,但移动网络无法播放时,首先检查资料库地址是否能够通过公网访问。
@@ -74,9 +74,9 @@ Wi-Fi 环境可以播放,但移动网络无法播放时,首先检查资料
:::
## 平台相关
## 平台相关 {#platform}
### 安卓通知栏播放控制失效
### 安卓通知栏播放控制失效 {#notification}
这似乎是安卓系统的 bug目前的解决方案是在系统设置中关闭音流的电池优化。
@@ -88,17 +88,17 @@ Wi-Fi 环境可以播放,但移动网络无法播放时,首先检查资料
:::
### 安卓车载蓝牙歌曲信息不更新或更新有延迟
### 安卓车载蓝牙歌曲信息不更新或更新有延迟 {#bluetooth}
这似乎发生在安卓手机锁屏之后,目前暂未发现解决办法,具体处理进度参见问题 [Android MediaItem is not updating on car display through bluetooth](https://github.com/ryanheise/audio_service/issues/908)。
### 安卓开启桌面歌词后 Bitwarden 应用内部分区域无法点击
### 安卓开启桌面歌词后 Bitwarden 应用内部分区域无法点击 {#overlay}
锁定桌面歌词后,正常来说,悬浮窗里的点击事件是可以传递给下面的界面的。
可能 Bitwarden 使用了不一样的方式识别点击事件,此时可以先在通知中心解锁或关闭桌面歌词,等操作完成后再恢复。
### 应用发烫或 CPU 占用过高
### 应用发烫或 CPU 占用过高 {#cpu}
这个属于 Flutter 的优化问题在界面中存在循环动画时CPU 占用就会异常的高。
@@ -110,29 +110,29 @@ Wi-Fi 环境可以播放,但移动网络无法播放时,首先检查资料
:::
### CarPlay 或通知中心无法控制上一曲下一曲
### CarPlay 或通知中心无法控制上一曲下一曲 {#carplay-notification}
请在设置中关闭 `与其他应用同时播放` 的选项。
这是 iOS 的系统特性,非软件 bug。
## 会员
## 会员 {#vip}
### 恢复购买时提示签名信息错误
### 恢复购买时提示签名信息错误 {#signature}
大概率是你的设备时间和正常时间相差太大导致的。
### 邮箱格式错误
### 邮箱格式错误 {#email}
请手动输入邮箱,避免粘贴时可能多产生的空格和回车等空白字符。
### 设备数量
### 设备数量 {#device-limit}
目前新设备上线会自动将超出设备数量的旧设备踢下线,因此无需手动管理上线的设备。
## 其他问题
## 其他问题 {#other}
### 安全问题
### 安全问题 {#security}
部分用户可能担心软件会私自传输他们的服务器账号密码,我觉得这种担心是没有必要的。原因如下:

View File

@@ -2,11 +2,11 @@
sidebar_position: 2
---
# 音乐服务
# 音乐服务 {#services}
就我个人使用体验来讲,目前并不存在完美的音乐服务,它们各有优缺点,需要根据自己的需求酌情选择。
## 支持版本
## 支持版本 {#versions}
- Navidrome 0.49.3 及以上
- Plex 1.29.2 及以上,支持 OTP 验证码登录,暂不支持登陆到共享音乐库
@@ -15,7 +15,7 @@ sidebar_position: 2
- Jellyfin 10.8.10 及以上
- Subsonic 1.15.0 及以上
## 功能比较
## 功能比较 {#comparison}
`-` 未知

View File

@@ -1,8 +1,8 @@
{
"label": "实用技巧",
"label": "tips",
"position": 5,
"link": {
"type": "generated-index",
"description": "光有好剑是不够的,你还需要好的剑谱。"
"description": "Having a good sword is not enough; you also need a good sword manual."
}
}

View File

@@ -2,11 +2,11 @@
sidebar_position: 2
---
# 重复歌曲的检测与删除
# 重复歌曲的检测与删除 {#detect}
随着曲库的增加,不可避免的会出现重复歌曲,这对于强迫症患者来讲简直太折磨了,遇到喜欢的歌曲都不知道该收藏哪个版本。
在音流中通过[媒体库模式](../guides/sync_mode#%E5%AA%92%E4%BD%93%E5%BA%93%E6%A8%A1%E5%BC%8F)连接并完全同步了服务端的数据后,在歌手详情页中,如果该歌手的歌曲存在重复项目,则会有**重复歌曲检测**功能的入口。
在音流中通过[媒体库模式](../guides/sync_mode#library-mode)连接并完全同步了服务端的数据后,在歌手详情页中,如果该歌手的歌曲存在重复项目,则会有**重复歌曲检测**功能的入口。
进入后即可按歌曲查看与其重复的各个版本,之后便可以根据页面的一些提示信息删除重复歌曲了。
@@ -16,7 +16,7 @@ sidebar_position: 2
:::
但这里有个问题,如果[连接的服务端不支持删除文件](../services#%E5%8A%9F%E8%83%BD%E6%AF%94%E8%BE%83)那该怎么办呢?
但这里有个问题,如果[连接的服务端不支持删除文件](../services#comparison)那该怎么办呢?
第一个解决办法,如果音流获取到的歌曲路径是真实路径,则可以复制页面中的删除命令,在其他软件中通过 SSH 连接并执行命令即可。

View File

@@ -2,7 +2,7 @@
sidebar_position: 1
---
# 专注于某种音频类型
# 专注于某种音频类型 {#focus}
在存放音乐之外,我们可能还会将有声读物等音频加入我们的曲库。

View File

@@ -2,7 +2,7 @@
sidebar_position: 4
---
# 通过 Last.FM 记录播放记录
# 通过 Last.FM 记录播放记录 {#lastfm}
年末的时候看到别人在发**听歌年度报告**而自己却没有?不用担心,你可以通过 Last.FM 记录你的播放记录,然后就可以在年末的时候愉快地向朋友分享了~
@@ -16,17 +16,17 @@ sidebar_position: 4
:::
## 注册 Last.FM 账号
## 注册 Last.FM 账号 {#account}
前往 https://www.last.fm/ 注册即可,**使用 QQ 邮箱可能会导致无法注册**。
## 通过 Navidrome 上报播放记录
## 通过 Navidrome 上报播放记录 {#navidrome}
在 Navidrome 的网页端启用 Last.FM 的喜好记录即可。
![](https://oss.aqzscn.cn/resource/blog/img/2024/b269c-862548c7f7e351f285de76a02c0b8389.png)
## 通过 Emby 上报播放记录
## 通过 Emby 上报播放记录 {#emby}
在 Emby 的管理页面中,安装元数据分类的 Last.fm 插件后重启服务器,即可在侧边栏进行配置。

View File

@@ -2,7 +2,7 @@
sidebar_position: 3
---
# 通过快捷指令播放音乐
# 通过快捷指令播放音乐 {#shortcuts}
音流在 1.3.4 版本支持了 iOS 的快捷指令功能,以便在不打开 APP 的情况下可以通过快捷指令或 Siri 播放音乐。
@@ -25,7 +25,7 @@ sidebar_position: 3
9. 获取播放状态
10. 从歌单中添加或移除歌曲列表
## 抛砖引玉
## 抛砖引玉 {#example}
**播放我喜欢的音乐**

View File

@@ -82,8 +82,8 @@ import AndroidIcon from '@mui/icons-material/Android';
文档更新:
- 增加直连模式说明
- 增加[音乐服务接口文档](/docs/category/音乐服务)
- 提供 [Navidrome 同步到 50000 首歌曲后无法继续同步的问题的解决方案](/docs/problems#navidrome-%E6%89%AB%E6%8F%8F%E5%88%B0-50000-%E9%A6%96%E6%AD%8C%E6%9B%B2%E5%90%8E%E5%A4%B1%E8%B4%A5)
- 增加音乐服务接口文档
- 提供 [Navidrome 同步到 50000 首歌曲后无法继续同步的问题的解决方案](/docs/problems#navidrome-scan)
- 补充了一些[常见问题](/docs/problems)
## V1.2.82024-04-17

View File

@@ -1,9 +1,9 @@
{
"label": "版本列表",
"label": "versions",
"position": 6,
"link": {
"type": "generated-index",
"description": "包含历史版本更新说明和安装包下载地址。"
"description": "Contains historical version update notes and download links for installation packages."
},
"customProps": {
"reversed": true

View File

@@ -4,52 +4,55 @@
// There are various equivalent ways to declare your Docusaurus config.
// See: https://docusaurus.io/docs/api/docusaurus-config
import {themes as prismThemes} from 'prism-react-renderer';
import { themes as prismThemes } from "prism-react-renderer";
/** @type {import('@docusaurus/types').Config} */
const config = {
title: '音流',
tagline: '连接你的音乐',
favicon: 'img/favicon.ico',
title: "音流",
tagline: "连接你的音乐",
favicon: "img/favicon.ico",
// Set the production url of your site here
url: 'https://music.aqzscn.cn/',
url: "https://music.aqzscn.cn/",
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/',
baseUrl: "/",
// GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these.
organizationName: 'gitbobobo', // Usually your GitHub org/user name.
projectName: 'StreamMusic', // Usually your repo name.
organizationName: "gitbobobo", // Usually your GitHub org/user name.
projectName: "StreamMusic", // Usually your repo name.
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
onBrokenLinks: "throw",
onBrokenMarkdownLinks: "warn",
// Even if you don't use internationalization, you can use this field to set
// useful metadata like html lang. For example, if your site is Chinese, you
// may want to replace "en" with "zh-Hans".
i18n: {
defaultLocale: 'zh-Hans',
locales: ['zh-Hans'],
defaultLocale: "zh-Hans",
locales: ["zh-Hans", "en"],
},
presets: [
[
'classic',
"classic",
/** @type {import('@docusaurus/preset-classic').Options} */
({
docs: {
sidebarPath: './sidebars.js',
sidebarPath: "./sidebars.js",
// Please change this to your repo.
// Remove this to remove the "edit this page" links.
editUrl:
'https://github.com/gitbobobo/StreamMusic/blob/main/',
async sidebarItemsGenerator({defaultSidebarItemsGenerator, ...args}) {
editUrl: "https://github.com/gitbobobo/StreamMusic/blob/main/",
async sidebarItemsGenerator({
defaultSidebarItemsGenerator,
...args
}) {
const sidebarItems = await defaultSidebarItemsGenerator(args);
return reverseSidebarItems(sidebarItems);
},
},
blog: false,
// blog: {
// showReadingTime: true,
// // Please change this to your repo.
@@ -58,7 +61,7 @@ const config = {
// 'https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/',
// },
theme: {
customCss: './src/css/custom.css',
customCss: "./src/css/custom.css",
},
}),
],
@@ -68,12 +71,12 @@ const config = {
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({
// Replace with your project's social card
image: 'img/docusaurus-social-card.jpg',
image: "img/docusaurus-social-card.jpg",
navbar: {
title: '音流',
title: "音流",
logo: {
alt: 'Stream Music\'s Logo',
src: 'img/logo.png',
alt: "Stream Music's Logo",
src: "img/logo.png",
},
items: [
// {
@@ -82,11 +85,15 @@ const config = {
// position: 'left',
// label: '文档',
// },
// {to: '/blog', label: '博客', position: 'left'},
{
type: 'html',
position: 'right',
value: '<a class="navbar__item navbar__link header-github-link" rel="noopener noreferrer" target="_blank" aria-label="GitHub repository" href="https://github.com/gitbobobo/StreamMusic"></a>',
type: "localeDropdown",
position: "right",
},
{
type: "html",
position: "right",
value:
'<a class="navbar__item navbar__link header-github-link" rel="noopener noreferrer" target="_blank" aria-label="GitHub repository" href="https://github.com/gitbobobo/StreamMusic"></a>',
},
],
},
@@ -97,7 +104,7 @@ const config = {
prism: {
theme: prismThemes.github,
darkTheme: prismThemes.dracula,
additionalLanguages: ['json', 'php', 'dart', 'toml'],
additionalLanguages: ["json", "php", "dart", "toml"],
},
}),
};
@@ -105,10 +112,10 @@ const config = {
function reverseSidebarItems(items, reverse = false) {
// Reverse items in categories
const result = items.map((item) => {
if (item.type === 'category') {
if (item.type === "category") {
// console.log(item)
const r = item.customProps && item.customProps.reversed
return {...item, items: reverseSidebarItems(item.items, r)};
const r = item.customProps && item.customProps.reversed;
return { ...item, items: reverseSidebarItems(item.items, r) };
}
// console.log(item)
return item;

313
i18n/en/code.json Normal file
View File

@@ -0,0 +1,313 @@
{
"theme.ErrorPageContent.title": {
"message": "This page crashed.",
"description": "The title of the fallback page when the page crashed"
},
"theme.BackToTopButton.buttonAriaLabel": {
"message": "Scroll back to top",
"description": "The ARIA label for the back to top button"
},
"theme.blog.archive.title": {
"message": "Archive",
"description": "The page & hero title of the blog archive page"
},
"theme.blog.archive.description": {
"message": "Archive",
"description": "The page & hero description of the blog archive page"
},
"theme.blog.paginator.navAriaLabel": {
"message": "Blog list page navigation",
"description": "The ARIA label for the blog pagination"
},
"theme.blog.paginator.newerEntries": {
"message": "Newer entries",
"description": "The label used to navigate to the newer blog posts page (previous page)"
},
"theme.blog.paginator.olderEntries": {
"message": "Older entries",
"description": "The label used to navigate to the older blog posts page (next page)"
},
"theme.blog.post.paginator.navAriaLabel": {
"message": "Blog post page navigation",
"description": "The ARIA label for the blog posts pagination"
},
"theme.blog.post.paginator.newerPost": {
"message": "Newer post",
"description": "The blog post button label to navigate to the newer/previous post"
},
"theme.blog.post.paginator.olderPost": {
"message": "Older post",
"description": "The blog post button label to navigate to the older/next post"
},
"theme.tags.tagsPageLink": {
"message": "View all tags",
"description": "The label of the link targeting the tag list page"
},
"theme.colorToggle.ariaLabel": {
"message": "Switch between dark and light mode (currently {mode})",
"description": "The ARIA label for the navbar color mode toggle"
},
"theme.colorToggle.ariaLabel.mode.dark": {
"message": "dark mode",
"description": "The name for the dark color mode"
},
"theme.colorToggle.ariaLabel.mode.light": {
"message": "light mode",
"description": "The name for the light color mode"
},
"theme.docs.DocCard.categoryDescription.plurals": {
"message": "1 item|{count} items",
"description": "The default description for a category card in the generated index about how many items this category includes"
},
"theme.docs.breadcrumbs.navAriaLabel": {
"message": "Breadcrumbs",
"description": "The ARIA label for the breadcrumbs"
},
"theme.docs.paginator.navAriaLabel": {
"message": "Docs pages",
"description": "The ARIA label for the docs pagination"
},
"theme.docs.paginator.previous": {
"message": "Previous",
"description": "The label used to navigate to the previous doc"
},
"theme.docs.paginator.next": {
"message": "Next",
"description": "The label used to navigate to the next doc"
},
"theme.docs.versionBadge.label": {
"message": "Version: {versionLabel}"
},
"theme.docs.versions.unreleasedVersionLabel": {
"message": "This is unreleased documentation for {siteTitle} {versionLabel} version.",
"description": "The label used to tell the user that he's browsing an unreleased doc version"
},
"theme.docs.versions.unmaintainedVersionLabel": {
"message": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.",
"description": "The label used to tell the user that he's browsing an unmaintained doc version"
},
"theme.docs.versions.latestVersionSuggestionLabel": {
"message": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).",
"description": "The label used to tell the user to check the latest version"
},
"theme.docs.versions.latestVersionLinkLabel": {
"message": "latest version",
"description": "The label used for the latest version suggestion link label"
},
"theme.docs.tagDocListPageTitle.nDocsTagged": {
"message": "One doc tagged|{count} docs tagged",
"description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.docs.tagDocListPageTitle": {
"message": "{nDocsTagged} with \"{tagName}\"",
"description": "The title of the page for a docs tag"
},
"theme.common.editThisPage": {
"message": "Edit this page",
"description": "The link label to edit the current page"
},
"theme.common.headingLinkTitle": {
"message": "Direct link to {heading}",
"description": "Title for link to heading"
},
"theme.lastUpdated.atDate": {
"message": " on {date}",
"description": "The words used to describe on which date a page has been last updated"
},
"theme.lastUpdated.byUser": {
"message": " by {user}",
"description": "The words used to describe by who the page has been last updated"
},
"theme.lastUpdated.lastUpdatedAtBy": {
"message": "Last updated{atDate}{byUser}",
"description": "The sentence used to display when a page has been last updated, and by who"
},
"theme.NotFound.title": {
"message": "Page Not Found",
"description": "The title of the 404 page"
},
"theme.navbar.mobileVersionsDropdown.label": {
"message": "Versions",
"description": "The label for the navbar versions dropdown on mobile view"
},
"theme.tags.tagsListLabel": {
"message": "Tags:",
"description": "The label alongside a tag list"
},
"theme.admonition.caution": {
"message": "caution",
"description": "The default label used for the Caution admonition (:::caution)"
},
"theme.admonition.danger": {
"message": "danger",
"description": "The default label used for the Danger admonition (:::danger)"
},
"theme.admonition.info": {
"message": "info",
"description": "The default label used for the Info admonition (:::info)"
},
"theme.admonition.note": {
"message": "note",
"description": "The default label used for the Note admonition (:::note)"
},
"theme.admonition.tip": {
"message": "tip",
"description": "The default label used for the Tip admonition (:::tip)"
},
"theme.admonition.warning": {
"message": "warning",
"description": "The default label used for the Warning admonition (:::warning)"
},
"theme.AnnouncementBar.closeButtonAriaLabel": {
"message": "Close",
"description": "The ARIA label for close button of announcement bar"
},
"theme.blog.sidebar.navAriaLabel": {
"message": "Blog recent posts navigation",
"description": "The ARIA label for recent posts in the blog sidebar"
},
"theme.CodeBlock.copied": {
"message": "Copied",
"description": "The copied button label on code blocks"
},
"theme.CodeBlock.copyButtonAriaLabel": {
"message": "Copy code to clipboard",
"description": "The ARIA label for copy code blocks button"
},
"theme.CodeBlock.copy": {
"message": "Copy",
"description": "The copy button label on code blocks"
},
"theme.CodeBlock.wordWrapToggle": {
"message": "Toggle word wrap",
"description": "The title attribute for toggle word wrapping button of code block lines"
},
"theme.DocSidebarItem.expandCategoryAriaLabel": {
"message": "Expand sidebar category '{label}'",
"description": "The ARIA label to expand the sidebar category"
},
"theme.DocSidebarItem.collapseCategoryAriaLabel": {
"message": "Collapse sidebar category '{label}'",
"description": "The ARIA label to collapse the sidebar category"
},
"theme.NavBar.navAriaLabel": {
"message": "Main",
"description": "The ARIA label for the main navigation"
},
"theme.NotFound.p1": {
"message": "We could not find what you were looking for.",
"description": "The first paragraph of the 404 page"
},
"theme.NotFound.p2": {
"message": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.",
"description": "The 2nd paragraph of the 404 page"
},
"theme.TOCCollapsible.toggleButtonLabel": {
"message": "On this page",
"description": "The label used by the button on the collapsible TOC component"
},
"theme.navbar.mobileLanguageDropdown.label": {
"message": "Languages",
"description": "The label for the mobile language switcher dropdown"
},
"theme.blog.post.readMore": {
"message": "Read more",
"description": "The label used in blog post item excerpts to link to full blog posts"
},
"theme.blog.post.readMoreLabel": {
"message": "Read more about {title}",
"description": "The ARIA label for the link to full blog posts from excerpts"
},
"theme.blog.post.readingTime.plurals": {
"message": "One min read|{readingTime} min read",
"description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.docs.breadcrumbs.home": {
"message": "Home page",
"description": "The ARIA label for the home page in the breadcrumbs"
},
"theme.docs.sidebar.collapseButtonTitle": {
"message": "Collapse sidebar",
"description": "The title attribute for collapse button of doc sidebar"
},
"theme.docs.sidebar.collapseButtonAriaLabel": {
"message": "Collapse sidebar",
"description": "The title attribute for collapse button of doc sidebar"
},
"theme.docs.sidebar.navAriaLabel": {
"message": "Docs sidebar",
"description": "The ARIA label for the sidebar navigation"
},
"theme.docs.sidebar.closeSidebarButtonAriaLabel": {
"message": "Close navigation bar",
"description": "The ARIA label for close button of mobile sidebar"
},
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": {
"message": "Toggle navigation bar",
"description": "The ARIA label for hamburger menu button of mobile navigation"
},
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
"message": "← Back to main menu",
"description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
},
"theme.docs.sidebar.expandButtonTitle": {
"message": "Expand sidebar",
"description": "The ARIA label and title attribute for expand button of doc sidebar"
},
"theme.docs.sidebar.expandButtonAriaLabel": {
"message": "Expand sidebar",
"description": "The ARIA label and title attribute for expand button of doc sidebar"
},
"theme.blog.post.plurals": {
"message": "One post|{count} posts",
"description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.blog.tagTitle": {
"message": "{nPosts} tagged with \"{tagName}\"",
"description": "The title of the page for a blog tag"
},
"theme.blog.author.pageTitle": {
"message": "{authorName} - {nPosts}",
"description": "The title of the page for a blog author"
},
"theme.blog.authorsList.pageTitle": {
"message": "Authors",
"description": "The title of the authors page"
},
"theme.blog.authorsList.viewAll": {
"message": "View all authors",
"description": "The label of the link targeting the blog authors page"
},
"theme.blog.author.noPosts": {
"message": "This author has not written any posts yet.",
"description": "The text for authors with 0 blog post"
},
"theme.contentVisibility.unlistedBanner.title": {
"message": "Unlisted page",
"description": "The unlisted content banner title"
},
"theme.contentVisibility.unlistedBanner.message": {
"message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.",
"description": "The unlisted content banner message"
},
"theme.contentVisibility.draftBanner.title": {
"message": "Draft page",
"description": "The draft content banner title"
},
"theme.contentVisibility.draftBanner.message": {
"message": "This page is a draft. It will only be visible in dev and be excluded from the production build.",
"description": "The draft content banner message"
},
"theme.ErrorPageContent.tryAgain": {
"message": "Try again",
"description": "The label of the button to try again rendering when the React error boundary captures an error"
},
"theme.common.skipToMainContent": {
"message": "Skip to main content",
"description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
},
"theme.tags.tagsPageTitle": {
"message": "Tags",
"description": "The title of the tag list page"
}
}

View File

@@ -0,0 +1,54 @@
{
"version.label": {
"message": "Next",
"description": "The label for version current"
},
"sidebar.tutorialSidebar.category.guides": {
"message": "Guides",
"description": "The label for category Guides in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.guides.link.generated-index.description": {
"message": "Installation and usage instructions for StreamMusic.",
"description": "The generated-index page description for category Guides in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.tips": {
"message": "Tips",
"description": "The label for category Tips in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.tips.link.generated-index.description": {
"message": "Having a good sword is not enough; you also need a good sword manual.",
"description": "The generated-index page description for category Tips in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.versions": {
"message": "Versions",
"description": "The label for category Versions in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.versions.link.generated-index.description": {
"message": "Contains historical version update notes and download links for installation packages.",
"description": "The generated-index page description for category Versions in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.developmentNotes": {
"message": "Notes",
"description": "The label for category developmentNotes in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.developmentNotes.link.generated-index.description": {
"message": "Experience sharing during the development of StreamMusic.",
"description": "The generated-index page description for category developmentNotes in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.musicServices": {
"message": "Music Services",
"description": "The label for category Music Services in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.musicServices.link.generated-index.description": {
"message": "Documenting some of the music service APIs used by Yinliu (not all APIs, only those related to music). This is to facilitate my own reference and to help others avoid some pitfalls. There may be some misunderstandings, and corrections and additions are welcome.",
"description": "The generated-index page description for category musicServices in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.adaptation": {
"message": "Adaptation",
"description": "The label for category Adaptation in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.adaptation.link.generated-index.description": {
"message": "Experience sharing during the development of StreamMusic.",
"description": "The generated-index page description for category Adaptation in sidebar tutorialSidebar"
}
}

View File

@@ -0,0 +1,188 @@
---
sidebar_position: 3
---
# Features {#feature}
Stream Music offers free basic features, while premium features require a membership purchase.
## Pricing Model {#pricing}
**One-time Purchase**. Buy once, use across all platforms for life.
- Membership can be activated on up to **7 devices**. Exceeding this limit will deactivate the earliest logged-in device.
- Membership verification uses **online validation** with random checks at startup. Ensure your device has internet access.
## Purchase & Refunds {#purchase}
Available only on mobile devices:
- **iOS**: Purchase via App Store. Refunds can be requested through App Store within 3 months (not controlled by the developer).
- **Android**: Purchase via Alipay. Refunds can be requested by emailing `aqzscn@qq.com` within 6 months. Include your Alipay order number.
After purchase, bind your email to restore membership on other devices via verification codes.
:::warning
**Bound emails cannot be modified later**. Do NOT use temporary email addresses.
:::
## Feature Comparison {#comparison}
<table>
<tr>
<th>Feature</th>
<th>Free</th>
<th>Premium</th>
<th>Feature</th>
<th>Free</th>
<th>Premium</th>
</tr>
<tr>
<td colspan="6" class="text-center text-bold">⚡️ Streaming & Playback</td>
</tr>
<tr>
<td>Cache While Playing</td>
<td></td>
<td></td>
<td>Auto Play</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Auto Download</td>
<td></td>
<td></td>
<td>Sleep Timer</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Sync via QR Code</td>
<td></td>
<td></td>
<td>Replay Gain</td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td>Download</td>
<td>⭕️</td>
<td></td>
<td>DLNA Playback<sup>1</sup></td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td colspan="6" class="text-center text-bold">🎙️ Lyrics</td>
</tr>
<tr>
<td>Lyrics Display & Edit</td>
<td></td>
<td></td>
<td>Floating Lyrics (Android)</td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td>Status Bar Lyrics (Android/macOS)</td>
<td>⭕️</td>
<td></td>
<td>PiP Lyrics (iOS)</td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td colspan="6" class="text-center text-bold">📱 System Integration</td>
</tr>
<tr>
<td>Widgets (Android/iOS)</td>
<td></td>
<td></td>
<td>Global Hotkeys (macOS/Windows)</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Mini Window (macOS/Windows)</td>
<td>⭕️</td>
<td></td>
<td>CarPlay<sup>2</sup></td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td>Shortcuts</td>
<td>⭕️</td>
<td></td>
<td colspan="3"></td>
</tr>
<tr>
<td colspan="6" class="text-center text-bold">🎈 Customization</td>
</tr>
<tr>
<td>Enhanced Gestures</td>
<td></td>
<td></td>
<td>Custom API</td>
<td></td>
<td></td>
</tr>
<tr>
<td>Custom Content</td>
<td>⭕️</td>
<td></td>
<td>Themes</td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td>Long Audio Preferences</td>
<td>⭕️</td>
<td></td>
<td colspan="3"></td>
</tr>
<tr>
<td colspan="6" class="text-center text-bold">📁 Library Management</td>
</tr>
<tr>
<td>Multi-Server Switching</td>
<td>⭕️</td>
<td></td>
<td>Folder View (Library Mode)</td>
<td>⭕️</td>
<td></td>
</tr>
<tr>
<td>Duplicate Detection (Library Mode)</td>
<td>⭕️</td>
<td></td>
<td colspan="3"></td>
</tr>
<tr>
<td colspan="6" class="text-center text-bold">🪄 Others</td>
</tr>
<tr>
<td>Fallback Servers</td>
<td>⭕️</td>
<td></td>
<td colspan="3"></td>
</tr>
</table>
1. DLNA compatibility is currently limited. Assume this feature may not work when purchasing.
2. Music may stop if opened via CarPlay/Shortcuts while the app is closed. Reopening the app resumes playback.
## Beta Access {#test}
Stream Music's beta channel: [https://devmusic.aqzscn.cn/docs/versions/latest](https://devmusic.aqzscn.cn/docs/versions/latest).
- Android: Universal APK only. Uninstall previous versions before installing.
- iOS: TestFlight available **only to existing premium users**.
**To request TestFlight access**, email `aqzscn@qq.com` with:
**Subject**: `Request Stream Music TestFlight`
**Content** (all required):
1. Purchase proof (screenshot of Apple receipt or Alipay order with order number).
2. Email linked to your Apple ID.
3. Your primary music server type.
Requests are processed periodically. Please be patient.

View File

@@ -0,0 +1,24 @@
---
sidebar_position: 5
---
# CarPlay {#carplay}
## Lyrics Display {#lyrics}
Due to Apple's safety restrictions, **full lyrics display is prohibited in CarPlay**.
Stream Music provides a **single-line lyric preview** by enabling the **"Lyrics - Lyric Notifications"** switch.
## Limitations {#limitation}
**The app must be open on your phone** for CarPlay functionality.
When the app is closed, the Flutter engine remains uninitialized, preventing CarPlay connection detection and playback control.
:::info
Related issue: [CarPlay app requires Flutter App open first?](https://github.com/oguzhnatly/flutter_carplay/issues/12)
Current workarounds allow CarPlay interface display without opening the app, but **music playback fails**, and the UI may freeze after manually launching the app. Further investigation is ongoing.
:::

View File

@@ -0,0 +1,67 @@
---
sidebar_position: 1
---
# Installation {#installation}
Installation guides for Android and Windows. Latest installers can be found [here](../versions/latest).
## Android {#android}
Four APK variants are provided for different chip architectures:
- For modern smartphones (released in recent years), choose `app-arm64-v8a-release.apk`.
- If unsure about your device's architecture, download `app-release.apk`.
:::caution
APKs for different architectures **cannot** be installed over each other. Uninstall existing versions before switching architectures.
:::
## Windows {#windows}
Windows version currently provides only **x64 MSIX** installer (Microsoft Store format). To install outside the Store, you must first install the developer certificate.
import Button from '@mui/material/Button';
import DownloadIcon from '@mui/icons-material/Download';
<Button variant="contained" startIcon={<DownloadIcon />} href="https://oss.aqzscn.cn/stream-music/stream_music_win.crt">Stream Music Certificate</Button>
### Standard Installation {#standard}
1. Double-click the certificate file. Select **Local Computer** during installation.
![Snipaste_2023-12-29_20-37-44](https://oss.aqzscn.cn/halo/2023/Snipaste_2023-12-29_20-37-44.png)
2. Store the certificate in **Trusted Root Certification Authorities**.
:::info
User feedback: Adding to "Trusted People" also works.
:::
![Snipaste_2023-12-29_20-39-16](https://oss.aqzscn.cn/halo/2023/Snipaste_2023-12-29_20-39-16.png)
3. After certificate installation, double-click the MSIX file to install Stream Music.
### Alternative Installation (Legacy Windows) {#legacy}
MSIX requires Windows 10 or later. For Windows 7/8 users:
:::warning
**Not recommended for Windows 7** due to missing dependencies and lack of Flutter support.
:::
1. Download the MSIX file and open it with any archive tool (e.g., 7-Zip):
![Snipaste_2023-12-29_20-46-42](https://oss.aqzscn.cn/halo/2023/Snipaste_2023-12-29_20-46-42.png)
2. Extract all files to your desired installation directory.
3. Launch via `stream_music.exe`:
![Snipaste_2023-12-29_20-49-22](https://oss.aqzscn.cn/halo/2023/Snipaste_2023-12-29_20-49-22.png)

View File

@@ -0,0 +1,181 @@
---
sidebar_position: 4
---
# Custom APIs {#api}
Advanced users can customize API responses when music services lack required features.
## Authentication (Optional) {#auth}
| Configuration | Location | Key | Description |
| ------------- | -------------- | --------------- | ----------- |
| Authorization | Request Header | Authorization | |
## API List {#list}
### Get Lyrics {#lyrics}
**Method**: GET
| Configuration | Location | Key | Description |
| ---------------------- | ------------ | --------- | -------------------------------------------------------------------------------------------------------------------- |
| Base URL | URL | - | Example: `https://example.com/lyrics` |
| Track Title | URL Params | `title` | Final URL: `https://example.com/lyrics?title={title}` |
| Artist | URL Params | `artist` | |
| Album | URL Params | `album` | |
| File Path (Optional) | URL Params | `path` | Available for Subsonic/Navidrome. May be empty for other protocols. |
| Duration (Optional) | URL Params | `duration`| In seconds. Supported since v1.1.3. |
| Offset (Optional) | URL Params | `offset` | Start line index (0-based). Supported since v1.1.6 (fixed to 0). |
| Limit (Optional) | URL Params | `limit` | Supported since v1.1.6 (fixed to 10). |
**Response**
Return lyrics content directly if found. Return empty or `404` if not found.
For pagination (v1.1.6+), set `Content-Type: application/json` and return:
```json
[
{
"id": "<Unique ID for deduplication>",
"title": "<May differ from query>",
"artist": "<May differ from query>",
"lyrics": "<Lyrics content>"
},
...
]
```
### Confirm Lyrics {#confirm-lyrics}
Applicable to version 1.2.0 and above.
Triggered **after** a user manually clicks the **Save** button on the lyrics switching interface.
Request method: POST
| Configuration Item | Location | Key | Description |
| ------------------- | -------- | ------------- | -------------------------------------------- |
| Base URL | URL | - | Example: `https://example.com/lyrics/confirm` |
| Content Type | headers | content-type | `application/json` |
Request Body:
```json
{
"path": "File path",
"title": "Song title",
"artist": "Artist",
"album": "Album",
"lyrics": "Lyrics content to confirm",
"lyricsId": "Lyrics ID (may be null)"
}
```
Response Code: If the response code is not `20x`, display "Lyrics confirmation exception" to the user. No message is shown if there's no exception.
:::note
Starting from v1.3.1, adjusting the lyrics offset and clicking the checkmark button will also trigger the lyrics confirmation interface. In this case, the request data will **exclude** the `lyricsId` field.
:::
### Get Cover Art {#cover}
Request method: GET
| Configuration Item | Location | Key | Description |
| ------------------------- | ----------- | ------ | ---------------------------------------------------------------------------- |
| Base URL | URL | - | Example: `https://example.com/covers` |
| Song title (optional) | URL Params | title | Final URL: `https://example.com/covers?title=SongTitle` |
| Artist name | URL Params | artist | |
| Album name (optional) | URL Params | album | |
| File path (optional) | URL Params | path | Only exists when querying song cover art. Supported from v1.3.3 |
Through this interface, the app can attempt to obtain different types of cover art by controlling parameters:
- All three parameters: Get song cover art
- No song title: Get album cover art
- Only artist name: Get artist image
**Response Body**
File stream.
### Song Details {#detail}
Applicable to version 1.2.4 and above. Used to redirect to the music service's song link in the browser.
| Configuration Item | Location | Key | Description |
| ------------------------- | ----------- | ------- | ---------------------------------------------------------------------------- |
| Base URL | URL | - | Example: `https://example.com/details` |
| Song path | URL Params | path | Final URL: `https://example.com/details?path=SongPath` |
| Target | URL Params | target | Currently fixed as `detail` |
Example configuration:
![](https://oss.aqzscn.cn/resource/blog/img/2024/891a6-5de6d34514b48759827b9e08e0236602.png)
**Path Replacement**
Used when your music service is deployed via Docker: the detected path might differ from the actual music file path. By replacing the first matching string through **Path Replacement**, it can be converted to a path recognizable by the Docker service, i.e.:
```
// Actual path
/volume1/music/ff.flac
// Replaced path
/app/media/ff.flac
```
## Simple Service {#example}
### Configuring Nginx to Load LRC Files from Same Directory `@ZaneYork` {#nginx}
Directly configure the API address in the app as `your_server_address + /lyrics/`.
```conf title="default.conf"
# Redirect requests for flac/mp3 resources to corresponding LRC files
location ~* \.(flac|mp3)$ {
rewrite ^/(.*)\.(flac|mp3)$ https://$host:8443/$1.lrc redirect;
}
location /lyrics/ {
# Fix space characters being converted to plus signs in request paths
if ($args ~ ^(?<first>.*)\+(?<second>.*)$) {
rewrite ^(.*)$ "$1?$first%20$second?" last;
}
# %2Fmusic%2F represents your Navidrome song root directory (URL-encoded /)
if ($query_string ~* "path=%2Fmusic%2F(.+)\.(mp3|flac)$") {
set $argv1 $1;
rewrite .* https://$host:8443/lyrics/$argv1.lrc? redirect;
}
# Nginx proxy logic for static resources in song directory omitted
}
```
### Serving LRC Files with PHP (Same Filename) `@lingluos` {#php}
A PHP-based method to return LRC files on Linux systems. Requires the LRC file to have the exact same name as the audio file.
Assume `index.php` is placed in `/var/www/html/lyrics`, and LRC files are stored in `/var/www/html/lyrics/lrc`.
```php title="index.php"
<?php
if (isset($_GET['path'])) {
$path = $_GET['path'];
$lrcName = rawurlencode(substr($path, strrpos($path, '/') + 1, -5) . '.lrc');
// Replace "your_domain" with your domain and path (default folder when accessing via Nginx port)
$apiUrl = "http://your_domain/lyrics/lrc/{$lrcName}";
// Print the API request URL (uncomment below and comment the header redirect
// if consistently getting 400 errors to verify LRC file accessibility)
// echo $apiUrl;
header("Location: $apiUrl");
exit;
} else {
echo '400 Missing file path';
}
?>
```
In theory, simply enter `http://your_domain/lyrics/` in the custom API lyrics interface to display the lyrics.
As a side note, if the lyrics appear garbled, try converting the LRC file encoding to UTF-8.

View File

@@ -0,0 +1,56 @@
---
sidebar_position: 5
---
# Miscellaneous {#other}
## Partitions {#partition}
Some users utilize Stream Music not only for music but also for audiobooks. The partition feature helps separate different audio types to avoid interference.
Currently, **Emby, Jellyfin, and Plex** support multiple media libraries (partitions):
- **Emby**: Set media library type to "Audiobooks" or "Music".
- **Jellyfin/Plex**: Must use "Music" type, as their "Books" category is designed for text-based content with incompatible layouts.
## List Elements {#list}
- **Green index numbers** indicate unplayed tracks (useful for audiobook progress tracking).
![](https://oss.aqzscn.cn/resource/blog/img/2024/90011-293fd6ac80a1ce9bc85adf176c807e19.png)
- **Track numbers** in album lists show disc number (top-right) and track order (index).
![](https://oss.aqzscn.cn/resource/blog/img/2024/90642-5882f5ffcf3b92988a49aaa5dac913c3.png)
- **Wrench icon** in artist lists indicates duplicate files.
![](https://oss.aqzscn.cn/resource/blog/img/2024/7ec2a-423ad72f94ace289a7d801936d02e3f6.png)
## Cross-Device Configuration Sync {#qr}
Sync server settings across devices via QR code or LAN URL to avoid repetitive setup:
- Access via **"Add Library"** or **Help → Data Sync**.
- Desktop users can manually enter the URL shown below the QR code.
:::caution
1. Data is transmitted over LAN with basic encryption. Use only in trusted networks.
2. QR scanning uses [mobile_scanner](https://github.com/juliansteenbakker/mobile_scanner). Retry if recognition fails.
:::
## Lyrics {#lyrics}
Supports **LRC format** ([Wikipedia](https://en.wikipedia.org/wiki/LRC_(file_format))). Bilingual lyrics formats:
**Same timestamp**
```
[00:01.123] Lyrics
[00:01.123] Translation
```
**Bracketed format**
```
[00:01.123] Lyrics【Translation】
```

View File

@@ -0,0 +1,51 @@
---
sidebar_position: 3
---
# Playback Logic {#playback}
Stream Music's playback logic differs slightly from common music apps, incorporating unique design philosophies.
**New users are strongly encouraged to read this section for optimal usage.**
## Playback Modes {#mode}
By default, Stream Music uses **Queue Playback**. Enable the loop switch to apply looping to both queue and shuffle modes.
![](https://oss.aqzscn.cn//resource/blog/img/2023/860419a28223c06c03964ff34a5a8668.png)
When selecting songs from a list, queue playback is the default behavior.
![](https://oss.aqzscn.cn//resource/blog/img/2023/e3f0f7469a58b3955598f8965eeef658.png)
If the list header includes the following buttons:
- Click the **circle icon** to jump to the current track.
- Click the **double-arrow icon** to switch the list's playback mode.
:::tip Track Navigation Upgrade (v1.3.0):
1. If the playback queue matches the current list, navigation jumps to the current track.
2. If the queues differ, navigation jumps to the first unplayed track in the list.
For paginated lists: If no matching track exists on the current page, scrolling to the bottom triggers loading the next page.
:::
**Playback mode changes from song lists are saved per list type.**
Changes from the playback queue or player page are temporary and session-only.
## Playback Controls {#control}
![](https://oss.aqzscn.cn//resource/blog/img/2023/15d11e29bb8e27f58378743eb86f6fd0.png)
Control bar features:
- Tap the cover to play/pause.
- Tap the lyrics area to enter full-screen playback.
- Tap the right-side button to open the current queue.
**Swipe gestures on lyrics area**:
- Swipe right ➔ Previous track.
- Swipe left ➔ Next track.
## DLNA {#dlna}
- DLNA streams the server's playback URL to devices. Ensure DLNA devices can access your server.
- For compatibility, playback status updates use **polling**, causing ~2-second delays for some operations.

View File

@@ -0,0 +1,54 @@
---
sidebar_position: 2
---
# Sync Modes {#sync}
## Library Mode {#library-mode}
In **Library Mode**, Stream Music fully synchronizes server-side song lists, album lists, and artist lists to the local device, enabling access to complete music library data.
This mode allows Stream Music to implement features not supported by the server, such as folder views, playlist imports, and advanced filtering.
**However**, if your music library is large, the initial sync process may take significant time.
### Automatic Sync {#auto}
On app startup, Stream Music detects if the server has more songs than the local copy and performs an **incremental sync** for missing data.
:::warning
Incremental sync relies on querying songs by their creation time in reverse order. If songs are deleted or modified on the server, manually trigger a full sync via the sync button.
:::
After login, the app initializes the player to restore the last playback session. If you see a "**Player initializing**" message, wait briefly.
### Manual Sync {#manual}
If automatic sync fails, click the **"Sync Now"** button in the music library to force a full update.
:::info
Manual sync is a full update. If interrupted, incremental sync resumes on the next launch.
:::
## Direct Mode {#direct}
In **Direct Mode**, Stream Music fetches data directly from the server without local synchronization. This improves initial app performance for large libraries.
**Limitations** due to server API dependencies:
- **Daily Mix** may include long audio tracks without duration filtering.
- No duplicate song detection.
- Folder views (for Subsonic/Navidrome/Jellyfin) only display locally cached data (manually queried folders).
- Some sorting/filtering features are unavailable.
:::info Work in Progress...
As someone with a growing music library, I find Direct Mode effective despite minor feature gaps. **Future optimizations will focus on Direct Mode**.
However, functionality depends on server APIs. A long-term vision is to develop a dedicated Stream Music server for enhanced compatibility.
:::

View File

@@ -0,0 +1,52 @@
---
sidebar_position: 1
---
# Introduction {#introduction}
Stream Music is a **NAS music player** that connects to **music services**<sup>1</sup> deployed on your NAS, allowing you to enjoy a consistent music experience across **multiple platforms**<sup>2</sup>.
![](https://oss.aqzscn.cn/resource/blog/img/2024/60b87-ca3fefb87f148b5c03ecf069fb1f95ab.png)
1. Currently supported music services: Subsonic, Navidrome, Emby, Jellyfin, AudioStation, Plex.
2. Currently supported platforms: Android 6.0, iOS 14, macOS 10.14, Windows 10.
## Requirements {#requirements}
Before using Stream Music, you must have a NAS running a music service. Stream Music is a pure music player focused on streaming your existing music library and does not provide any music content.
:::info
NAS stands for `Network Attached Storage`. If you are unfamiliar with this term, Stream Music may not be suitable for you.
:::
## Key Features {#features}
- 🎵 Compatible with multiple music services.
- 🎙️ Lyrics display support. Custom APIs enable lyrics display even for services without native lyrics interfaces!
- 🖥️📱 Built with Flutter, delivering a near-native experience and unlimited cross-platform adaptability.
## Download {#download}
### iOS {#ios}
Visit the [App Store page](https://apps.apple.com/cn/app/%E9%9F%B3%E6%B5%81-%E8%BF%9E%E6%8E%A5%E4%BD%A0%E7%9A%84%E9%9F%B3%E4%B9%90/id6449966496) or search for `音流` or `Stream Music` in the App Store.
### Android, macOS, Windows {#other-platform}
Since Stream Music is not yet listed on other app stores, please find the latest version for download on [this page](./versions/latest).
:::info
The Windows installer uses the MSIX format. For installation instructions, [click here](./guides/install).
:::
## Feedback & Suggestions {#feedback}
Please submit your feedback via GitHub Issues.
Follow our official account to receive updates about new releases:
![](https://oss.aqzscn.cn/resource/blog/img/2024/5645e-8796c787d6453480d3e7ac250bfdd930.png)

View File

@@ -0,0 +1,350 @@
# SMTC 适配
做音乐播放器,绕不开的就是要把当前播放的媒体告知操作系统。在 Android、iOS 及 macOS 平台,[audio_service](https://github.com/ryanheise/audio_service) 插件都能很好的完成任务。
在 Windows 系统上SMTC(SystemMediaTransportControls, 系统媒体传输控件) 负责显示媒体内容并提供控制按钮。
此前音流一直使用 [smtc_windows](https://pub.dev/packages/smtc_windows) 这个插件来完成这个任务,但使用这个插件对我来说有两个痛点:
- 无法使用本地图片(插件作者是 spotube 的作者,软件中大部分资源都是在线获取的,所以可能未来也不会加入此功能)
- 构建产物在 x86 的机器上运行就会报错(导致我只能在 arm 架构的 Windows 系统打包)。
所以一直以来就想通过 [flutter_rust_bridge](https://cjycode.com/flutter_rust_bridge/quickstart) 这个插件自己实现一下,奈何自己不懂 Rust实在不知道该怎么从一个空白文件开始写起。
还好最近在掘金上看到一个大佬写的文章:[Flutter 应用如何支持 SMTC](https://juejin.cn/post/7363556508603432972),遂下定决心改造当前项目。
## 启用 Melos
[Melos](https://invertase.docs.page/melos) 用于管理多个包在一个存储库的协同工作,对我来说,以下两个特点是吸引我使用它的原因:
- Executing simultaneous commands across packages.(跨包执行同时命令。)
- Listing of local packages & their dependencies.(本地包及其依赖项的列表。)
:::tip
启用 Melos 这个步骤对于 **SMTC 适配**来说并非必须的,只是我个人的选择。
如果只想了解如何适配 SMTC直接阅读原文章 [Flutter 应用如何支持 SMTC](https://juejin.cn/post/7363556508603432972) 是更好的选择。
:::
在命令行使用 `dart pub global activate melos` 命令全局激活一下,按照[官方文档指引](https://invertase.docs.page/melos/getting-started)创建对应的文件与文件夹结构。
```
my_project
├── apps
│ ├── apps_1
│ └── apps_2
├── packages
│ ├── package_1
│ └── package_2
├── melos.yaml
├── pubspec.yaml
└── README.md
```
对于 `melos.yaml`,我提供一个目前我所使用的示例文件,仅供参考:
```yaml title="melos.yaml"
name: stream_music
packages:
- apps/**/
- packages/**/
ignore:
- '**/.dart_tool/**'
- '**/.idea/**'
- '**/.vscode/**'
- '**/build/**'
- '**/example'
scripts:
gen:frb:
run: |
melos exec -c 6 --fail-fast -- \
"flutter_rust_bridge_codegen generate"
description: |
Generate dart files for FlutterRustBridge.
packageFilters:
scope: 'stream_music'
build:windows:
run: |
melos exec -c 6 --fail-fast -- \
"flutter build windows"
description: |
Build app for Windows.
packageFilters:
dirExists:
- windows
scope: 'stream_music'
build:msix:
run: |
melos exec -c 6 --fail-fast -- \
"dart run msix:publish"
description: |
Build app for Windows msix.
packageFilters:
dirExists:
- windows
scope: 'stream_music'
build:ios:
run: |
melos exec -c 6 --fail-fast -- \
"flutter build ios --config-only"
description: |
更新 iOS 应用配置.
packageFilters:
dirExists:
- ios
scope: 'stream_music'
clean:
run: |
melos exec -c 6 --fail-fast -- \
"flutter clean"
description: |
Clean all packages.
packageFilters:
scope: 'stream_music'
```
## 迁移项目
在 Rust 安装完成后,执行命令 `cargo install flutter_rust_bridge_codegen` 以安装 flutter_rust_bridge 的脚手架工具。
尽管 flutter_rust_bridge 提供了迁移已有项目的命令:`flutter_rust_bridge_codegen integrate`,但似乎在我的项目中并不好用。
因此我直接使用 `flutter_rust_bridge_codegen create my_app` 命令创建一个新的项目,然后一点点比较新旧项目的不同,最后也算是完成了迁移。
迁移完成后,使用 `melos bs` 命令引导一下项目,这个命令会安装所有包依赖项,并将所有本地包链接在一起,而且在 `melos.yaml` 中定义的脚本命令也会直接出现在 Android Studio 的运行配置中。
![](https://oss.aqzscn.cn/resource/blog/img/2024/2877c-551314d6ad5cb4871c61dd880b232e37.png)
## 适配 SMTC
这个步骤大部分参考大佬的 [Flutter 应用如何支持 SMTC](https://juejin.cn/post/7363556508603432972),再次表示感谢~
添加 Rust 依赖:
```toml title="rust/Cargo.toml"
[dependencies]
flutter_rust_bridge = "=2.3.0"
windows = { version = "0.58.0", features = [
"Media_Playback",
"Storage",
"Storage_Streams",
"Storage_FileProperties"
]}
```
添加 `smtc` 模块
```rust title="rust/src/api/mod.rs"
pub mod smtc;
```
补充 `smtc` 逻辑,这里的代码与原文的有些许不同,主要目的是为了能在不同平台编译通过,且尽量不修改 dart 的调用代码。
```rust title="rust/src/api/smtc.rs"
use flutter_rust_bridge::frb;
#[cfg(target_os = "windows")]
use windows::{
core::HSTRING,
Foundation::TypedEventHandler,
Media::{
MediaPlaybackStatus, MediaPlaybackType, Playback::MediaPlayer,
SystemMediaTransportControls, SystemMediaTransportControlsButton,
SystemMediaTransportControlsButtonPressedEventArgs,
},
Storage::{FileProperties::ThumbnailMode, StorageFile, Streams::RandomAccessStreamReference},
};
use crate::frb_generated::StreamSink;
pub struct SmtcFlutter {
#[cfg(target_os = "windows")]
_smtc: SystemMediaTransportControls,
#[cfg(target_os = "windows")]
_player: MediaPlayer,
}
pub enum SMTCControlEvent {
Play,
Pause,
Previous,
Next,
Unknown,
}
pub enum SMTCState {
Paused,
Playing,
}
/// Apis for Flutter
impl SmtcFlutter {
#[frb(sync)]
pub fn new() -> Self {
#[cfg(target_os = "windows")]
return Self::_new().unwrap();
#[cfg(not(target_os = "windows"))]
return SmtcFlutter {};
}
pub fn subscribe_to_control_events(&self, sink: StreamSink<SMTCControlEvent>) {
#[cfg(target_os = "windows")]
self._smtc
.ButtonPressed(&TypedEventHandler::<
SystemMediaTransportControls,
SystemMediaTransportControlsButtonPressedEventArgs,
>::new(move |_, event| {
let event = event.as_ref().unwrap().Button().unwrap();
let event = match event {
SystemMediaTransportControlsButton::Play => SMTCControlEvent::Play,
SystemMediaTransportControlsButton::Pause => SMTCControlEvent::Pause,
SystemMediaTransportControlsButton::Next => SMTCControlEvent::Next,
SystemMediaTransportControlsButton::Previous => SMTCControlEvent::Previous,
_ => SMTCControlEvent::Unknown,
};
sink.add(event).unwrap();
Ok(())
}))
.unwrap();
}
pub fn update_state(&self, state: SMTCState) {
#[cfg(target_os = "windows")]
self._update_state(state).unwrap();
}
pub fn update_display(&self, title: String, artist: String, album: String, path: Option<String>) {
#[cfg(target_os = "windows")]
self._update_display(
HSTRING::from(title),
HSTRING::from(artist),
HSTRING::from(album),
path.map(HSTRING::from),
)
.unwrap();
}
pub fn close(self) {
#[cfg(target_os = "windows")]
self._player.Close().unwrap();
}
}
#[cfg(target_os = "windows")]
impl SmtcFlutter {
fn _init_controls(smtc: &SystemMediaTransportControls) -> Result<(), windows::core::Error> {
// 下一首
smtc.SetIsNextEnabled(true)?;
// 暂停
smtc.SetIsPauseEnabled(true)?;
// 播放(恢复)
smtc.SetIsPlayEnabled(true)?;
// 上一首
smtc.SetIsPreviousEnabled(true)?;
Ok(())
}
fn _new() -> Result<Self, windows::core::Error> {
let _player = MediaPlayer::new()?;
_player.CommandManager()?.SetIsEnabled(false)?;
let _smtc = _player.SystemMediaTransportControls()?;
Self::_init_controls(&_smtc)?;
Ok(Self { _smtc, _player })
}
fn _update_state(&self, state: SMTCState) -> Result<(), windows::core::Error> {
let state = match state {
SMTCState::Playing => MediaPlaybackStatus::Playing,
SMTCState::Paused => MediaPlaybackStatus::Paused,
};
self._smtc.SetPlaybackStatus(state)?;
Ok(())
}
fn _update_display(
&self,
title: HSTRING,
artist: HSTRING,
album: HSTRING,
path: Option<HSTRING>,
) -> Result<(), windows::core::Error> {
let updater = self._smtc.DisplayUpdater()?;
updater.SetType(MediaPlaybackType::Music)?;
let music_properties = updater.MusicProperties()?;
music_properties.SetTitle(&title)?;
music_properties.SetArtist(&artist)?;
music_properties.SetAlbumTitle(&album)?;
if let Some(path) = path {
let file = StorageFile::GetFileFromPathAsync(&path)?.get()?;
let thumbnail = file
.GetThumbnailAsyncOverloadDefaultSizeDefaultOptions(ThumbnailMode::MusicView)?
.get()?;
updater.SetThumbnail(&RandomAccessStreamReference::CreateFromStream(&thumbnail)?)?;
}
updater.Update()?;
if !(self._smtc.IsEnabled()?) {
self._smtc.SetIsEnabled(true)?;
}
Ok(())
}
}
```
执行命令 `flutter_rust_bridge_codegen generate` 生成 dart 端代码,根据自己的业务逻辑进行调用即可。
```dart title="audio_handler.dart"
SmtcFlutter? _smtc;
if (Platform.isWindows) {
_smtc = SmtcFlutter();
// 监听点击事件
_smtc?.subscribeToControlEvents().listen((event) {
switch (event) {
case SMTCControlEvent.play:
play();
break;
case SMTCControlEvent.pause:
pause();
break;
case SMTCControlEvent.previous:
skipToPrevious();
break;
case SMTCControlEvent.next:
skipToNext();
break;
case SMTCControlEvent.unknown:
break;
}
});
}
// 更新媒体信息
_smtc?.updateDisplay(
title: event?.title ?? '',
artist: event?.artist ?? '',
album: event?.album ?? '',
path: event?.artUri?.toString(),
);
// 更新播放状态
_smtc?.updateState(state: event ? SMTCState.playing : SMTCState.paused);
```

View File

@@ -0,0 +1,551 @@
---
sidebar_position: 1
---
# Used Plugins
Without the support of open-source projects, StreamMusic wouldn't exist as it does today
If any feature of StreamMusic has helped you, consider giving these projects a 🌟 or supporting them.
## UI {#ui}
### macos_ui
[macos_ui](https://github.com/macosui/macos_ui), like Flutter's built-in Material Widgets and Cupertino Widgets, implements component libraries following macOS design guidelines.
[Click here to view](https://macosui.github.io/macos_ui/#/) the live demo.
![](https://oss.aqzscn.cn/resource/blog/img/2024/84187-8f40569512f26dedc256e709c73a4de9.png)
### fluent_ui
[fluent_ui](https://github.com/bdlukaa/fluent_ui) implements Windows Fluent Design components. Compared to `macos_ui`, its components are more feature-complete.
[Click here to view](https://bdlukaa.github.io/fluent_ui/) the live demo.
![](https://oss.aqzscn.cn/resource/blog/img/2024/65e8d-fc810c37b1bd57ddc5161705e21c8343.png)
### pulldown_button
[pulldown_button](https://github.com/notDmDrl/pull_down_button) implements iOS-style pull-down menus with smooth animations. It would be perfect if it supported nested menus.
![](https://oss.aqzscn.cn/resource/blog/img/2024/faae1-9ad0cf3582cd7ff590b3e02645f19bc7.png)
## Platform Features {#platform}
### macos_window_utils
[macos_window_utils](https://github.com/macosui/macos_window_utils.dart), another creation by the `macos_ui` author, controls window properties like blur effect and title bar visibility. Best used with macos_ui.
### flutter_acrylic
[flutter_acrylic](https://github.com/alexmercerind/flutter_acrylic) enables window blur/transparency effects on macOS/Windows/Linux. On macOS, it depends on `macos_window_utils`, so no need to include both.
### window_manager
[window_manager](https://pub.dev/packages/window_manager) controls window properties on desktop platforms.
### tray_manager
[tray_manager](https://pub.dev/packages/tray_manager) customizes system tray behaviors.
### windows_taskbar
[windows_taskbar](https://pub.dev/packages/windows_taskbar) adds preview buttons and progress bars to Windows taskbar icons - particularly useful for music players.
### flutter_carplay
[flutter_carplay](https://pub.dev/packages/flutter_carplay) enables CarPlay support for iOS (minimum iOS 14).
The original author hasn't updated it recently - consider using community forks.
A current challenge is launching the Flutter engine when CarPlay connects while ensuring smooth app switching between CarPlay and phone.
### flutter_rust_bridge
As the name suggests, [flutter_rust_bridge](https://cjycode.com/flutter_rust_bridge/quickstart) bridges Flutter and Rust by generating glue code. Flutter apps gain access to Rust's rich ecosystem, while Rust apps leverage Flutter's cross-platform UI.
I've followed this project for years but hesitated to adopt it due to my Rust inexperience. After optimizing Windows SMTC features using [this guide](https://juejin.cn/post/7363556508603432972), I've gained [some insights](./adaptive/smtc) and feel ready to migrate.
The core workflow when using Rust plugins involves two steps:
```rust title="image.rs"
// Define struct
pub struct RsImage {}
// Implement methods
impl RsImage {
pub fn blur(img_path: String) -> Result<Vec<u8>, String> {
// Use Rust crates to implement features...
}
}
```
For a Rust Newbie, Understanding ownership concepts is essential. Lifetime issues might arise, but my current principle is to resolve compiler errors without explicit lifetime annotations whenever possible. As a simple API caller, I haven't encountered situations requiring manual lifetime tagging yet.
Compared to other languages, Rust does feel awkward initially - error handling patterns, optional unwrapping, ownership borrowing etc. But most issues can be solved with GPT's help. The benefits of accessing Rust's cross-platform ecosystem make these growing pains worthwhile 😄
## Networking {#network}
### dio
[dio](https://pub.dev/packages/dio) is a powerful HTTP client featuring interceptors, request cancellation, and custom adapters. Community plugins further simplify networking tasks.
Dart's native HTTP client only handles standard requests properly. Non-standard implementations can fail, making it inferior to platform-native networking.
While dio offers [native_dio_adapter](https://github.com/cfug/dio/tree/main/plugins/native_dio_adapter) for native platform requests, it only works on Android/iOS - insufficient for StreamMusic's multi-platform needs.
### rhttp(rust)
[rhttp](https://github.com/Tienisto/rhttp) leverages Rust's renowned `reqwest` for requests, offering better compatibility than Dart's HTTP stack.
StreamMusic v1.3.2 uses rhttp for image fetching and song caching with improved compatibility and system proxy support. Future plans include migrating all networking to rhttp if stability holds.
### rupnp(rust)
[rupnp](https://github.com/jakobhellermann/rupnp) (Rust UPnP) replaced Dart's [upnp2](https://github.com/daniel-naegele/upnp.dart) due to mysterious Windows DLNA device discovery failures with the Dart version.
### shelf
[shelf](https://pub.dev/packages/shelf) creates local HTTP servers, with [shelf_proxy](https://pub.dev/packages/shelf_proxy) simplifying proxy setups. Note: iOS suspends local servers when app enters background - implement detection and restart mechanisms.
### connectivity_plus
[connectivity_plus](https://pub.dev/packages/connectivity_plus) monitors network status changes.
### network_info_plus
[network_info_plus](https://pub.dev/packages/network_info_plus) retrieves Wi-Fi details like IP addresses.
### url_launcher
[url_launcher](https://pub.dev/packages/url_launcher) opens URLs in default browsers.
## Audio {#audio}
### media_kit
[media_kit](https://github.com/media-kit/media-kit) uses MPV under the hood, achieving unparalleled [format compatibility](https://github.com/media-kit/media-kit?tab=readme-ov-file#supported-formats) for audio/video playback - a key differentiator from other Flutter players.
<details>
<summary>Supported Formats (Click to Expand)</summary>
- 3dostr 3DO STR
- 4xm 4X Technologies
- aa Audible AA format files
- aac raw ADTS AAC (Advanced Audio Coding)
- aax CRI AAX
- ac3 raw AC-3
- ace tri-Ace Audio Container
- acm Interplay ACM
- act ACT Voice file format
- adf Artworx Data Format
- adp ADP
- ads Sony PS2 ADS
- adx CRI ADX
- aea MD STUDIO audio
- afc AFC
- aiff Audio IFF
- aix CRI AIX
- alaw PCM A-law
- alias_pix Alias/Wavefront PIX image
- alp LEGO Racers ALP
- amr 3GPP AMR
- amrnb raw AMR-NB
- amrwb raw AMR-WB
- anm Deluxe Paint Animation
- apac raw APAC
- apc CRYO APC
- ape Monkey's Audio
- apm Ubisoft Rayman 2 APM
- apng Animated Portable Network Graphics
- aptx raw aptX
- aptx_hd raw aptX HD
- aqtitle AQTitle subtitles
- argo_asf Argonaut Games ASF
- argo_brp Argonaut Games BRP
- argo_cvg Argonaut Games CVG
- asf ASF (Advanced / Active Streaming Format)
- asf_o ASF (Advanced / Active Streaming Format)
- ass SSA (SubStation Alpha) subtitle
- ast AST (Audio Stream)
- au Sun AU
- av1 AV1 Annex B
- avi AVI (Audio Video Interleaved)
- avr AVR (Audio Visual Research)
- avs Argonaut Games Creature Shock
- avs2 raw AVS2-P2/IEEE1857.4
- avs3 raw AVS3-P2/IEEE1857.10
- bethsoftvid Bethesda Softworks VID
- bfi Brute Force & Ignorance
- bfstm BFSTM (Binary Cafe Stream)
- bin Binary text
- bink Bink
- binka Bink Audio
- bit G.729 BIT file format
- bitpacked Bitpacked
- bmp_pipe piped bmp sequence
- bmv Discworld II BMV
- boa Black Ops Audio
- bonk raw Bonk
- brender_pix BRender PIX image
- brstm BRSTM (Binary Revolution Stream)
- c93 Interplay C93
- caf Apple CAF (Core Audio Format)
- cavsvideo raw Chinese AVS (Audio Video Standard)
- cdg CD Graphics
- cdxl Commodore CDXL video
- cine Phantom Cine
- codec2 codec2 .c2 demuxer
- codec2raw raw codec2 demuxer
- concat Virtual concatenation script
- cri_pipe piped cri sequence
- dash Dynamic Adaptive Streaming over HTTP
- data raw data
- daud D-Cinema audio
- dcstr Sega DC STR
- dds_pipe piped dds sequence
- derf Xilam DERF
- dfa Chronomaster DFA
- dfpwm raw DFPWM1a
- dhav Video DAV
- dirac raw Dirac
- dnxhd raw DNxHD (SMPTE VC-3)
- dpx_pipe piped dpx sequence
- dsf DSD Stream File (DSF)
- dshow DirectShow capture
- dsicin Delphine Software International CIN
- dss Digital Speech Standard (DSS)
- dts raw DTS
- dtshd raw DTS-HD
- dv DV (Digital Video)
- dvbsub raw dvbsub
- dvbtxt dvbtxt
- dxa DXA
- ea Electronic Arts Multimedia
- ea_cdata Electronic Arts cdata
- eac3 raw E-AC-3
- epaf Ensoniq Paris Audio File
- exr_pipe piped exr sequence
- f32be PCM 32-bit floating-point big-endian
- f32le PCM 32-bit floating-point little-endian
- f64be PCM 64-bit floating-point big-endian
- f64le PCM 64-bit floating-point little-endian
- ffmetadata FFmpeg metadata in text
- film_cpk Sega FILM / CPK
- filmstrip Adobe Filmstrip
- fits Flexible Image Transport System
- flac raw FLAC
- flic FLI/FLC/FLX animation
- flv FLV (Flash Video)
- frm Megalux Frame
- fsb FMOD Sample Bank
- fwse Capcom's MT Framework sound
- g722 raw G.722
- g723_1 G.723.1
- g726 raw big-endian G.726 ("left aligned")
- g726le raw little-endian G.726 ("right aligned")
- g729 G.729 raw format demuxer
- gdigrab GDI API Windows frame grabber
- gdv Gremlin Digital Video
- gem_pipe piped gem sequence
- genh GENeric Header
- gif CompuServe Graphics Interchange Format (GIF)
- gif_pipe piped gif sequence
- gsm raw GSM
- gxf GXF (General eXchange Format)
- h261 raw H.261
- h263 raw H.263
- h264 raw H.264 video
- hca CRI HCA
- hcom Macintosh HCOM
- hdr_pipe piped hdr sequence
- hevc raw HEVC video
- hls Apple HTTP Live Streaming
- hnm Cryo HNM v4
- ico Microsoft Windows ICO
- idcin id Cinematic
- idf iCE Draw File
- iff IFF (Interchange File Format)
- ifv IFV CCTV DVR
- ilbc iLBC storage
- image2 image2 sequence
- image2pipe piped image2 sequence
- imf IMF (Interoperable Master Format)
- ingenient raw Ingenient MJPEG
- ipmovie Interplay MVE
- ipu raw IPU Video
- ircam Berkeley/IRCAM/CARL Sound Format
- iss Funcom ISS
- iv8 IndigoVision 8000 video
- ivf On2 IVF
- ivr IVR (Internet Video Recording)
- j2k_pipe piped j2k sequence
- jacosub JACOsub subtitle format
- jpeg_pipe piped jpeg sequence
- jpegls_pipe piped jpegls sequence
- jpegxl_pipe piped jpegxl sequence
- jv Bitmap Brothers JV
- kux KUX (YouKu)
- kvag Simon & Schuster Interactive VAG
- laf LAF (Limitless Audio Format)
- lavfi Libavfilter virtual input device
- live_flv live RTMP FLV (Flash Video)
- lmlm4 raw lmlm4
- loas LOAS AudioSyncStream
- lrc LRC lyrics
- luodat Video CCTV DAT
- lvf LVF
- lxf VR native stream (LXF)
- m4v raw MPEG-4 video
- matroska,webm Matroska / WebM
- mca MCA Audio Format
- mcc MacCaption
- mgsts Metal Gear Solid: The Twin Snakes
- microdvd MicroDVD subtitle format
- mjpeg raw MJPEG video
- mjpeg_2000 raw MJPEG 2000 video
- mlp raw MLP
- mlv Magic Lantern Video (MLV)
- mm American Laser Games MM
- mmf Yamaha SMAF
- mods MobiClip MODS
- moflex MobiClip MOFLEX
- mov,mp4,m4a,3gp,3g2,mj2 QuickTime / MOV
- mp3 MP2/3 (MPEG audio layer 2/3)
- mpc Musepack
- mpc8 Musepack SV8
- mpeg MPEG-PS (MPEG-2 Program Stream)
- mpegts MPEG-TS (MPEG-2 Transport Stream)
- mpegtsraw raw MPEG-TS (MPEG-2 Transport Stream)
- mpegvideo raw MPEG video
- mpjpeg MIME multipart JPEG
- mpl2 MPL2 subtitles
- mpsub MPlayer subtitles
- msf Sony PS3 MSF
- msnwctcp MSN TCP Webcam stream
- msp Microsoft Paint (MSP))
- mtaf Konami PS2 MTAF
- mtv MTV
- mulaw PCM mu-law
- musx Eurocom MUSX
- mv Silicon Graphics Movie
- mvi Motion Pixels MVI
- mxf MXF (Material eXchange Format)
- mxg MxPEG clip
- nc NC camera feed
- nistsphere NIST SPeech HEader REsources
- nsp Computerized Speech Lab NSP
- nsv Nullsoft Streaming Video
- nut NUT
- nuv NuppelVideo
- obu AV1 low overhead OBU
- ogg Ogg
- oma Sony OpenMG audio
- paf Amazing Studio Packed Animation File
- pam_pipe piped pam sequence
- pbm_pipe piped pbm sequence
- pcx_pipe piped pcx sequence
- pfm_pipe piped pfm sequence
- pgm_pipe piped pgm sequence
- pgmyuv_pipe piped pgmyuv sequence
- pgx_pipe piped pgx sequence
- phm_pipe piped phm sequence
- photocd_pipe piped photocd sequence
- pictor_pipe piped pictor sequence
- pjs PJS (Phoenix Japanimation Society) subtitles
- pmp Playstation Portable PMP
- png_pipe piped png sequence
- pp_bnk Pro Pinball Series Soundbank
- ppm_pipe piped ppm sequence
- psd_pipe piped psd sequence
- psxstr Sony Playstation STR
- pva TechnoTrend PVA
- pvf PVF (Portable Voice Format)
- qcp QCP
- qdraw_pipe piped qdraw sequence
- qoi_pipe piped qoi sequence
- r3d REDCODE R3D
- rawvideo raw video
- realtext RealText subtitle format
- redspark RedSpark
- rka RKA (RK Audio)
- rl2 RL2
- rm RealMedia
- roq id RoQ
- rpl RPL / ARMovie
- rsd GameCube RSD
- rso Lego Mindstorms RSO
- rtp RTP input
- rtsp RTSP input
- s16be PCM signed 16-bit big-endian
- s16le PCM signed 16-bit little-endian
- s24be PCM signed 24-bit big-endian
- s24le PCM signed 24-bit little-endian
- s32be PCM signed 32-bit big-endian
- s32le PCM signed 32-bit little-endian
- s337m SMPTE 337M
- s8 PCM signed 8-bit
- sami SAMI subtitle format
- sap SAP input
- sbc raw SBC (low-complexity subband codec)
- sbg SBaGen binaural beats script
- scc Scenarist Closed Captions
- scd Square Enix SCD
- sdns Xbox SDNS
- sdp SDP
- sdr2 SDR2
- sds MIDI Sample Dump Standard
- sdx Sample Dump eXchange
- ser SER (Simple uncompressed video format for astronomical capturing)
- sga Digital Pictures SGA
- sgi_pipe piped sgi sequence
- shn raw Shorten
- siff Beam Software SIFF
- simbiosis_imx Simbiosis Interactive IMX
- sln Asterisk raw pcm
- smjpeg Loki SDL MJPEG
- smk Smacker
- smush LucasArts Smush
- sol Sierra SOL
- sox SoX native
- spdif IEC 61937 (compressed data in S/PDIF)
- srt SubRip subtitle
- stl Spruce subtitle format
- subviewer SubViewer subtitle format
- subviewer1 SubViewer v1 subtitle format
- sunrast_pipe piped sunrast sequence
- sup raw HDMV Presentation Graphic Stream subtitles
- svag Konami PS2 SVAG
- svg_pipe piped svg sequence
- svs Square SVS
- swf SWF (ShockWave Flash)
- tak raw TAK
- tedcaptions TED Talks captions
- thp THP
- tiertexseq Tiertex Limited SEQ
- tiff_pipe piped tiff sequence
- tmv 8088flex TMV
- truehd raw TrueHD
- tta TTA (True Audio)
- tty Tele-typewriter
- txd Renderware TeXture Dictionary
- ty TiVo TY Stream
- u16be PCM unsigned 16-bit big-endian
- u16le PCM unsigned 16-bit little-endian
- u24be PCM unsigned 24-bit big-endian
- u24le PCM unsigned 24-bit little-endian
- u32be PCM unsigned 32-bit big-endian
- u32le PCM unsigned 32-bit little-endian
- u8 PCM unsigned 8-bit
- v210 Uncompressed 4:2:2 10-bit
- v210x Uncompressed 4:2:2 10-bit
- vag Sony PS2 VAG
- vbn_pipe piped vbn sequence
- vc1 raw VC-1
- vc1test VC-1 test bitstream
- vfwcap VfW video capture
- vidc PCM Archimedes VIDC
- vividas Vividas VIV
- vivo Vivo
- vmd Sierra VMD
- vobsub VobSub subtitle format
- voc Creative Voice
- vpk Sony PS2 VPK
- vplayer VPlayer subtitles
- vqf Nippon Telegraph and Telephone Corporation (NTT) TwinVQ
- w64 Sony Wave64
- wady Marble WADY
- wav WAV / WAVE (Waveform Audio)
- wavarc Waveform Archiver
- wc3movie Wing Commander III movie
- webm_dash_manifest WebM DASH Manifest
- webp_pipe piped webp sequence
- webvtt WebVTT subtitle
- wsaud Westwood Studios audio
- wsd Wideband Single-bit Data (WSD)
- wsvqa Westwood Studios VQA
- wtv Windows Television (WTV)
- wv WavPack
- wve Psion 3 audio
- xa Maxis XA
- xbin eXtended BINary text (XBIN)
- xbm_pipe piped xbm sequence
- xmd Konami XMD
- xmv Microsoft XMV
- xpm_pipe piped xpm sequence
- xvag Sony PS3 XVAG
- xwd_pipe piped xwd sequence
- xwma Microsoft xWMA
- yop Psygnosis YOP
- yuv4mpegpipe YUV4MPEG pipe
</details>
I can't contain my enthusiasm for this plugin. After struggling to find a worthy replacement for `just_audio`, media_kit has effortlessly resolved numerous playback issues I previously encountered.
So folks, now that you've read this, go show some love and [give media_kit a 🌟](https://github.com/media-kit/media-kit)!
:::note Dev Tip
Using default configurations may cause crashes when playing high-bitrate files on HarmonyOS. Apply this workaround:
```dart
NativePlayer get nativePlayer => player.platform as NativePlayer;
if (Platform.isAndroid) {
// Fix crash on HarmonyOS when playing high-bitrate files
await nativePlayer.setProperty("ao", "audiotrack,opensles,");
}
```
此处代码参考了 [spotube](https://github.com/KRTirtho/spotube) 项目的 [custom_player.dart](https://github.com/KRTirtho/spotube/blob/cb95663412fcc9a829c5657e0160132f13fb0649/lib/services/audio_player/custom_player.dart#L68)。
:::
### audio_service
[audio_service](https://github.com/ryanheise/audio_service) handles system music notifications, media controls interaction, and background playback persistence.
Currently supports Android, iOS, macOS. For Windows support, see my [modified version](https://github.com/gitbobobo/audio_service) which:
1. Adds Android status bar lyrics support
2. Implements Windows media notifications via [smtc_windows](https://github.com/KRTirtho/smtc_windows)
### lofty(rust)
[lofty](https://github.com/Serial-ATA/lofty-rs) - Rust library for reading audio file metadata tags. Supported formats:
| File Format | Metadata Format(s) |
|----------------|------------------------------------|
| AAC (ADTS) | `ID3v2`, `ID3v1` |
| Ape | `APE`, `ID3v2`\*, `ID3v1` |
| AIFF | `ID3v2`, `Text Chunks` |
| FLAC | `Vorbis Comments`, `ID3v2`\* |
| MP3 | `ID3v2`, `ID3v1`, `APE` |
| MP4 | `iTunes-style ilst` |
| MPC | `APE`, `ID3v2`\*, `ID3v1`\* |
| Opus | `Vorbis Comments` |
| Ogg Vorbis | `Vorbis Comments` |
| Speex | `Vorbis Comments` |
| WAV | `ID3v2`, `RIFF INFO` |
| WavPack | `APE`, `ID3v1` |
\* Read-only due to lack of official spec support
## Flutter Community {#community}
### Flutter Candies
[Flutter Candies](https://github.com/fluttercandies) - A thriving plugin ecosystem that fills gaps in official components' functionality. The maintainer actively shares insights on [Juejin](https://juejin.cn/user/254742428916408/posts) (I'm a silent follower 😉).
StreamMusic uses these Flutter Candies plugins:
- [extended_nested_scroll_view](https://github.com/fluttercandies/extended_nested_scroll_view)
Solves transparent header scrolling issues and syncs list scrolling in song list/artist detail pages.
- [loading_more_list](https://github.com/fluttercandies/loading_more_list)
Implements "load more" functionality without ScrollController.
- [scrollview_observer](https://github.com/fluttercandies/flutter_scrollview_observer)
Powers dynamic grid/list view switching with AZ jumping.
- [flutter_smart_dialog](https://github.com/fluttercandies/flutter_smart_dialog)
Context-free global dialogs/toasts.

View File

@@ -0,0 +1,30 @@
---
sidebar_position: 3
---
# Design Resources {#resource}
Below are the **royalty-free materials** used in **Stream Music APP**. If your copyrighted work is unintentionally infringed or you have royalty-free materials suitable for the app, please email [aqzscn@qq.com](mailto:aqzscn@qq.com) for removal or contribution. Thank you!
## Image Backgrounds {#image}
- [Default Album Art for Song Lists](https://pixabay.com/zh/vectors/record-disk-disc-music-musical-23281/) by Clker-Free-Vector-Images
- [TV Edition Artist Page Default Background](https://pixabay.com/zh/photos/concert-singer-singing-stage-2566002/) by StockSnap
## Color Illustrations {#illustrations}
- [Warning](https://pixabay.com/zh/vectors/warning-caution-alert-icon-media-145066/) by OpenClipart-Vectors
- [Success](https://pixabay.com/zh/vectors/icon-symbol-confirmation-hook-ok-803718/) by Leovinus
- [Error](https://pixabay.com/zh/vectors/error-button-failure-warning-24842/) by Clker-Free-Vector-Images
- [Info](https://pixabay.com/zh/vectors/info-information-tips-icon-support-148099/) by OpenClipart-Vectors
## Monochrome Illustrations {#mono}
- [TV Edition Membership Page](https://pixabay.com/zh/vectors/jewelry-crown-king-royal-queen-2025491/) by OpenClipart-Vectors
- [TV Edition About Page](https://pixabay.com/zh/vectors/found-icons-requests-1294561/) by OpenClipart-Vectors
- [TV Edition Help Page](https://pixabay.com/zh/vectors/drum-drums-jazz-kit-music-1295656/) by OpenClipart-Vectors
- [TV Edition Track Details Page](https://pixabay.com/zh/vectors/b-w-guitar-instrument-musical-2029526/) by OpenClipart-Vectors
- [TV Edition Personalization Page](https://pixabay.com/zh/vectors/head-music-silhouette-avatar-5405110/) by GDJ
- [TV Edition Themes Page](https://pixabay.com/zh/vectors/harp-mistletoe-music-line-art-5602052/) by GDJ
- [TV Edition Auto-Download Page](https://pixabay.com/zh/vectors/musical-notes-music-smile-merry-6159007/) by ArtRose
- [TV Edition Transcoding Page](https://pixabay.com/zh/illustrations/record-player-music-7000988/) by Vika_Glitter

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,568 @@
---
sidebar_position: 2
---
# Navidrome 接口文档
:::note
Navidrome 目前还没有官方的接口文档,以下均为抓包所得。
0.55.0 版本对原生接口进行了重大重构,以下内容部分已经过时。
:::
## 认证
### login 登录
POST`[host]/auth/login`
body(`application/json`)
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| username | Y | | 用户名 |
| password | Y | | 密码 |
响应内容:
```json
{
"id": "34c4xxxx-xxxx-xxxx-xxxx-6442b9a3xxxx",
"isAdmin": true,
"lastFMApiKey": "xxx",
"name": "username",
"subsonicSalt": "xxx",
"subsonicToken": "xxxxx",
"token": "xxxx",
"username": "username"
}
```
在之后的请求中,需要在请求头中携带以下信息:
- `x-nd-authorization`: 'Bearer `token`'
- `x-nd-client-unique-id`: `id`
### keepalive 登录状态保活
GET: `[host]/api/keepalive/keepalive`
## 请求节点
### album 获取专辑列表
GET: `[host]/api/album`
query:
| 参数名 | 备注 |
| --- | --- |
| _start | 起始行数0开始 |
| _end | 结束行数 |
| _order | 排序,可选值 `ASC`, `DESC` |
| _sort | 排序方式,可选值 `random`, `createdAt`, `min_year`, `play_count`, `play_date`, `name`, `albumArtist`, `rating`, 可用`,`分割多个排序方式,如 `min_year asc,date asc` |
| artist_id | 歌手id可选 |
| rating | 评分,可选 |
| starred | 收藏状态(`true/false`),可选 |
| name | 专辑名(like 查询),可选 |
:::note 待补充:
1. 如何查询在某个区间的年代,自测 `min_year``max_year` 只有相等的判断,同时传也不会判断区间。
2. 如何查询歌曲数量大于某个值的专辑
3. 专辑名的筛选是否可以添加多个关键词筛选
:::
响应内容:
```json
[
{
"playCount": 14,
"playDate": "2024-04-18T07:37:46.658+08:00",
"rating": 0,
"starred": false,
"starredAt": null,
"id": "2e7e41725443fa5e8a637a4668e63e98",
"name": "放下",
"embedArtPath": "/volume1/music/胡夏/放下/胡夏-放下.flac",
"artistId": "6d095fad618e04185bd66998450041da",
"artist": "胡夏",
"albumArtistId": "6d095fad618e04185bd66998450041da",
"albumArtist": "胡夏",
"allArtistIds": "6d095fad618e04185bd66998450041da",
"maxYear": 2013,
"minYear": 2013,
"date": "2013",
"maxOriginalYear": 0,
"minOriginalYear": 0,
"releases": 1,
"compilation": false,
"songCount": 1,
"duration": 337.08,
"size": 35163552,
"genre": "",
"genres": null,
"fullText": " 放下 胡夏",
"orderAlbumName": "放下",
"orderAlbumArtistName": "胡夏",
"paths": "/volume1/music/胡夏/放下",
"externalInfoUpdatedAt": null,
"createdAt": "2024-03-02T01:04:46.424670828+08:00",
"updatedAt": "2024-03-21T20:41:28.340360006+08:00"
}
]
```
响应头:
- `x-total-count`: 总行数
### album/[id] 获取专辑信息
GET: `[host]/api/album/[id]`
响应内容:
```json
{
"playCount": 14,
"playDate": "2024-04-18T07:37:46.658+08:00",
"rating": 0,
"starred": false,
"starredAt": null,
"id": "2e7e41725443fa5e8a637a4668e63e98",
"name": "放下",
"embedArtPath": "/volume1/music/胡夏/放下/胡夏-放下.flac",
"artistId": "6d095fad618e04185bd66998450041da",
"artist": "胡夏",
"albumArtistId": "6d095fad618e04185bd66998450041da",
"albumArtist": "胡夏",
"allArtistIds": "6d095fad618e04185bd66998450041da",
"maxYear": 2013,
"minYear": 2013,
"date": "2013",
"maxOriginalYear": 0,
"minOriginalYear": 0,
"releases": 1,
"compilation": false,
"songCount": 1,
"duration": 337.08,
"size": 35163552,
"genre": "",
"genres": null,
"fullText": " 放下 胡夏",
"orderAlbumName": "放下",
"orderAlbumArtistName": "胡夏",
"paths": "/volume1/music/胡夏/放下",
"externalInfoUpdatedAt": null,
"createdAt": "2024-03-02T01:04:46.424670828+08:00",
"updatedAt": "2024-03-21T20:41:28.340360006+08:00"
}
```
### artist/[id] 获取歌手信息
GET: `[host]/api/artist/[id]`
响应内容:
```json
{
"playCount": 42,
"playDate": "2024-04-18T08:27:04.036+08:00",
"rating": 0,
"starred": false,
"starredAt": null,
"id": "6d095fad618e04185bd66998450041da",
"name": "胡夏",
"albumCount": 19,
"songCount": 60,
"genres": null,
"fullText": " 胡夏",
"orderArtistName": "胡夏",
"size": 1714942860,
"externalUrl": "https://www.last.fm/music/%E8%83%A1%E5%A4%8F",
"externalInfoUpdatedAt": "0001-01-01T00:00:00Z"
}
```
### getArtistInfo 获取歌手简介及相似歌手
参见 Subsonic 的 [getArtistInfo](subsonic#getartistinfo2-获取歌手简介和相似歌手列表) 接口。
### artist 获取歌手列表
GET: `[host]/api/artist`
query:
| 参数名 | 备注 |
| --- | --- |
| _start | 起始行数0开始 |
| _end | 结束行数_end 和 _start 都等于 0 时可以查询全部 |
| _order | 排序,可选值 `ASC`, `DESC` |
| _sort | 排序方式,可选值 `random`, `play_count`, `play_date`, `name`, `rating`, 可用`,`分割多个排序方式,如 `min_year asc,date asc` |
| rating | 评分,可选 |
| starred | 收藏状态(`true/false`),可选 |
| name | 歌手名(like 查询),可选 |
| role | 角色可选0.55.0 及以上版本可用,以下版本添加此参数会出错 |
响应内容:
```json
[
{
"playCount": 42,
"playDate": "2024-04-18T08:27:04.036+08:00",
"rating": 0,
"starred": false,
"starredAt": null,
"id": "6d095fad618e04185bd66998450041da",
"name": "胡夏",
"albumCount": 19,
"songCount": 60,
"genres": null,
"fullText": " 胡夏",
"orderArtistName": "胡夏",
"size": 1714942860,
"mbzArtistId": "2ccbc670-5fe9-450a-a4ab-4d87131214b3",
"smallImageUrl": "https://i.scdn.co/image/ab67616d0000485129c9ac0b10fb4f016de87b11",
"mediumImageUrl": "https://i.scdn.co/image/ab67616d00001e0229c9ac0b10fb4f016de87b11",
"largeImageUrl": "https://i.scdn.co/image/ab67616d0000b27329c9ac0b10fb4f016de87b11",
"externalUrl": "https://www.last.fm/music/%E8%83%A1%E5%A4%8F",
"externalInfoUpdatedAt": "2024-04-18T16:10:03.997920721+08:00"
}
]
```
响应头:
- `x-total-count`: 总行数
### getCoverArt 封面图片
参见 Subsonic 的 [getCoverArt](./subsonic#getcoverart-封面图片)
### playlist 创建歌单
POST: `[host]/api/playlist`
body(`application/json`):
| 参数名 | 备注 |
| --- | --- |
| name | 歌单名 |
| comment | 评论 |
| public | 其他人是否可见 |
响应内容:
```json
{
"id": "775cca70-cd09-4029-9858-583098bef519"
}
```
### playlist/[id] 删除歌单
DELETE: `[host]/api/playlist/[id]`
响应内容:
```json
{}
```
### song/[id] 获取歌曲信息
GET: `[host]/api/song/[id]`
### playlist 获取歌单列表
GET: `[host]/api/playlist`
query:
| 参数名 | 备注 |
| --- | --- |
| _start | 起始行数0开始 |
| _end | 结束行数_end 和 _start 都等于 0 时可以查询全部 |
| _order | 排序,可选值 `ASC`, `DESC` |
| _sort | 排序方式,可选值 `random`, `name`, 可用`,`分割多个排序方式,如 `max_year asc,date asc` |
响应内容:
```json
[
{
"id": "355c94bd-4bef-485a-8945-d6d9d02191cd",
"name": "1999年老歌by慕星人",
"comment": "",
"duration": 8280.36,
"size": 951975104,
"songCount": 31,
"ownerName": "userA",
"ownerId": "34c42e25-70f8-42d3-83ff-6442b9a341a4",
"public": false,
"path": "",
"sync": false,
"createdAt": "2024-04-09T15:28:28.917434949+08:00",
"updatedAt": "2024-04-17T22:32:12.507824702+08:00",
"rules": null,
"evaluatedAt": null
},
{
"id": "bd200cad-839e-4818-85af-7e438fb6aef0",
"name": "15515",
"comment": "",
"duration": 170.67,
"size": 19324940,
"songCount": 1,
"ownerName": "userB",
"ownerId": "631ec3f3-0d00-4648-b404-ce4e95c305f2",
"public": false,
"path": "",
"sync": false,
"createdAt": "2024-03-17T18:55:34.432021369+08:00",
"updatedAt": "2024-03-17T18:55:47.208985366+08:00",
"rules": null,
"evaluatedAt": null
},
]
```
响应头:
- `x-total-count`: 总行数
### setRating 评分
参见 Subsonic 的 [setRating](./subsonic#setrating-评分) 接口。
### getScanStatus 获取扫描状态
参见 Subsonic 的 [getScanStatus](./subsonic#getscanstatus-获取扫描状态) 接口。
:::tip
这个接口获取到的歌曲数量可能与实际不符,建议从歌曲列表接口的响应头中获取歌曲总数。
:::
### scrobble 滚动播放记录
参见 Subsonic 的 [scrobble](./subsonic#scrobble-滚动播放记录) 接口。
### search2 搜索歌曲/专辑/歌手
参见 Subsonic 的 [search2](./subsonic#search2-搜索歌曲专辑歌手) 接口。
### getSimilarSongs 获取相似歌曲
参见 Subsonic 的 [getSimilarSongs](./subsonic#getsimilarsongs-获取相似歌曲) 接口。
### song 获取歌曲列表
GET: `[host]/api/song`
query:
| 参数名 | 备注 |
| --- | --- |
| _start | 起始行数0开始 |
| _end | 结束行数_end 和 _start 都等于 0 时可以查询全部歌手 |
| _order | 排序,可选值 `ASC`, `DESC` |
| _sort | 排序方式,可选值 `random`, `createdAt`, `max_year`, `play_count`, `play_date`, `title`, `album`, `rating`, 可用`,`分割多个排序方式,如 `max_year asc,date asc` |
| album_id | 专辑id |
| starred | 收藏状态 |
| title | 标题 |
响应内容:
```json
[
{
"playCount": 14,
"playDate": "2024-04-18T07:37:46.658+08:00",
"rating": 4,
"starred": true,
"starredAt": "2024-03-02T01:06:30.37479538+08:00",
"bookmarkPosition": 0,
"id": "be7daa6fc04bbbed2e0aaf15fc0b48df",
"path": "/volume1/music/胡夏/放下/胡夏-放下.flac",
"title": "放下",
"album": "放下",
"artistId": "6d095fad618e04185bd66998450041da",
"artist": "胡夏",
"albumArtistId": "6d095fad618e04185bd66998450041da",
"albumArtist": "胡夏",
"albumId": "2e7e41725443fa5e8a637a4668e63e98",
"hasCoverArt": true,
"trackNumber": 1,
"discNumber": 0,
"year": 2013,
"date": "2013",
"originalYear": 0,
"releaseYear": 0,
"size": 35163552,
"suffix": "flac",
"duration": 337.08,
"bitRate": 822,
"channels": 2,
"genre": "",
"genres": null,
"fullText": " 放下 胡夏",
"orderTitle": "放下",
"orderAlbumName": "放下",
"orderArtistName": "胡夏",
"orderAlbumArtistName": "胡夏",
"compilation": false,
"lyrics": "[{\"lang\":\"xxx\",\"line\":[{\"start\":0,\"value\":\"作词 : 丁丁张\"},{\"start\":370,\"value\":\"作曲 : 陈嵩\"},{\"start\":750,\"value\":\"风吹凉一杯茶\"},{\"start\":5800,\"value\":\"夕阳跑赢了老马\"},{\"start\":10400,\"value\":\"回头看雪染白长头发\"},{\"start\":19450,\"value\":\"少年被风催大\"},{\"start\":24350,\"value\":\"容颜未改心有疤\"},{\"start\":28500,\"value\":\"我爱你爱让我放下\"},{\"start\":38370,\"value\":\"放下\"},{\"start\":42920,\"value\":\"一只手握不住流沙\"},{\"start\":49220,\"value\":\"两双眼留不住落花\"},{\"start\":55480,\"value\":\"风吹草云落下你心如野马\"},{\"start\":62280,\"value\":\"等下时光请等一下\"},{\"start\":68440,\"value\":\"千只雀追不上流霞\"},{\"start\":74440,\"value\":\"万只蝶抵不过霜打\"},{\"start\":81540,\"value\":\"水滴石风在刮我声音沙哑\"},{\"start\":87500,\"value\":\"放下容我将你放下\"},{\"start\":94100,\"value\":\"天地江湖日月\"},{\"start\":95550,\"value\":\"不留不念不说话\"},{\"start\":100450,\"value\":\"繁华世界弱水\"},{\"start\":101850,\"value\":\"三千一瓢怎盛下\"},{\"start\":106100,\"value\":\"风吹凉一杯茶\"},{\"start\":109250,\"value\":\"夕阳跑赢了老马\"},{\"start\":112350,\"value\":\"回头看雪染白长头发\"},{\"start\":118600,\"value\":\"少年被风催大\"},{\"start\":121850,\"value\":\"容颜未改心有疤\"},{\"start\":125060,\"value\":\"我爱你爱让我放下\"},{\"start\":147120,\"value\":\"一个人走不到天涯\"},{\"start\":153420,\"value\":\"两场雪封不住嫩芽\"},{\"start\":159720,\"value\":\"月升起云落下你笑颜如花\"},{\"start\":166370,\"value\":\"等下时光请等一下\"},{\"start\":172370,\"value\":\"千个字说不出情话\"},{\"start\":178670,\"value\":\"万封信写不完牵挂\"},{\"start\":185310,\"value\":\"山走远风在刮我心乱如麻\"},{\"start\":191710,\"value\":\"放下容我将你放下\"},{\"start\":198460,\"value\":\"天地江湖日月\"},{\"start\":199860,\"value\":\"不留不念不说话\"},{\"start\":204710,\"value\":\"繁华世界弱水\"},{\"start\":206110,\"value\":\"三千一瓢怎盛下\"},{\"start\":210260,\"value\":\"风吹凉一杯茶\"},{\"start\":213410,\"value\":\"夕阳跑赢了老马\"},{\"start\":216560,\"value\":\"回头看雪染白长头发\"},{\"start\":222910,\"value\":\"少年被风催大\"},{\"start\":226670,\"value\":\"容颜未改心有疤\"},{\"start\":229210,\"value\":\"我爱你爱让我放下\"},{\"start\":235510,\"value\":\"风吹凉一杯茶\"},{\"start\":238660,\"value\":\"夕阳跑赢了老马\"},{\"start\":241810,\"value\":\"回头看雪染白长头发\"},{\"start\":248690,\"value\":\"少年被风催大\"},{\"start\":251210,\"value\":\"容颜未改心有疤\"},{\"start\":258830,\"value\":\"我爱你爱让我放下\"},{\"start\":267250,\"value\":\"忘了你爱让我放下\"}],\"synced\":true}]",
"rgAlbumGain": -6.4,
"rgAlbumPeak": 0.810242,
"rgTrackGain": -6.4,
"rgTrackPeak": 0.810242,
"createdAt": "2024-03-02T01:04:46.424670828+08:00",
"updatedAt": "2024-03-21T20:41:28.340360006+08:00"
}
]
```
响应头:
- `x-total-count`: 总行数
:::caution
`_sort` = `createdAt` 时,最多可以获取到 5w 条记录,再往后服务端会报错。
:::
### getTopSongs 获取歌手的热门歌曲
参见 Subsonic 的 [getTopSongs](./subsonic#gettopsongs-获取歌手的热门歌曲) 接口。
### playlist/tracks 获取歌单中的歌曲列表
GET: `[host]/api/playlist/[id]/tracks`
query:
| 参数名 | 备注 |
| --- | --- |
| _start | 起始行数0开始 |
| _end | 结束行数_end 和 _start 都等于 0 时可以查询全部 |
| _order | 排序,可选值 `ASC`, `DESC` |
| _sort | 排序方式,可选值 `id`, `createdAt`, 可用`,`分割多个排序方式,如 `max_year asc,date asc` |
| playlist_id | 歌单id |
响应内容:
```json
[
{
"id": "1",
"mediaFileId": "45bbcdc311aeb7c4cfd4ab5fb8db3b68",
"playlistId": "355c94bd-4bef-485a-8945-d6d9d02191cd",
"playCount": 5,
"playDate": "2024-03-23T15:52:34.334+08:00",
"rating": 0,
"starred": true,
"starredAt": "2024-02-05T14:07:28.428223292+08:00",
"bookmarkPosition": 0,
"path": "/volume1/music/张宇/雨一直下/张宇-雨一直下.flac",
"title": "雨一直下",
"album": "雨一直下",
"artistId": "1fed6de3753b8cf668a4eb4c485a70cb",
"artist": "张宇",
"albumArtistId": "1fed6de3753b8cf668a4eb4c485a70cb",
"albumArtist": "张宇",
"albumId": "986a826c9d21925f2be641d370d81e32",
"hasCoverArt": true,
"trackNumber": 1,
"discNumber": 0,
"year": 1999,
"date": "1999",
"originalYear": 0,
"releaseYear": 0,
"size": 37831941,
"suffix": "flac",
"duration": 290.31,
"bitRate": 1035,
"channels": 2,
"genre": "",
"genres": null,
"fullText": " 张宇 雨一直下",
"orderTitle": "雨一直下",
"orderAlbumName": "雨一直下",
"orderArtistName": "张宇",
"orderAlbumArtistName": "张宇",
"compilation": false,
"lyrics": "[{\"lang\":\"xxx\",\"line\":[{\"start\":0,\"value\":\"作词 : 十一郎\"},{\"start\":810,\"value\":\"作曲 : 张宇\"},{\"start\":1630,\"value\":\"编曲 : Michael Thompson\"},{\"start\":2450,\"value\":\"\"},{\"start\":40130,\"value\":\"雨一直下\"},{\"start\":43500,\"value\":\"气氛不算融洽\"},{\"start\":48150,\"value\":\"在同个屋檐下\"},{\"start\":49790,\"value\":\"你渐渐感到心在变化\"},{\"start\":53760,\"value\":\"你爱着他\"},{\"start\":57010,\"value\":\"也许也带着恨吧\"},{\"start\":61540,\"value\":\"青春耗了一大半\"},{\"start\":63380,\"value\":\"原来只是陪他玩耍\"},{\"start\":67330,\"value\":\"正想离开他\"},{\"start\":70830,\"value\":\"他却拿着鲜花\"},{\"start\":75390,\"value\":\"说不着边的话\"},{\"start\":77090,\"value\":\"让整个场面更加尴尬\"},{\"start\":80980,\"value\":\"不可思议吧\"},{\"start\":84580,\"value\":\"梦在瞬间崩塌\"},{\"start\":88920,\"value\":\"为何当初那么傻\"},{\"start\":90770,\"value\":\"还一心想要嫁给他\"},{\"start\":95340,\"value\":\"就是爱到深处 才怨他\"},{\"start\":99620,\"value\":\"舍不舍得 都断了吧\"},{\"start\":102560,\"value\":\"那是从来\"},{\"start\":103670,\"value\":\"都没有后路的悬崖\"},{\"start\":109030,\"value\":\"就是爱到深处 才由他\"},{\"start\":113200,\"value\":\"碎了心 也要放得下\"},{\"start\":116300,\"value\":\"难道忘了那爱他的伤\"},{\"start\":119070,\"value\":\"已密密麻麻\"},{\"start\":122380,\"value\":\"雨一直下\"},{\"start\":125740,\"value\":\"气氛不算融洽\"},{\"start\":130210,\"value\":\"在同个屋檐下\"},{\"start\":131950,\"value\":\"你渐渐感到心在变化\"},{\"start\":135890,\"value\":\"不可思议吧\"},{\"start\":139390,\"value\":\"梦在瞬间崩塌\"},{\"start\":143700,\"value\":\"为何当初那么傻\"},{\"start\":145580,\"value\":\"还一心想要嫁给他\"},{\"start\":150120,\"value\":\"就是爱到深处 才怨他\"},{\"start\":154360,\"value\":\"舍不舍得 都断了吧\"},{\"start\":157440,\"value\":\"那是从来\"},{\"start\":158480,\"value\":\"都没有后路的悬崖\"},{\"start\":163810,\"value\":\"就是爱到深处 才由他\"},{\"start\":168080,\"value\":\"碎了心 也要放得下\"},{\"start\":171150,\"value\":\"难道忘了那爱他的伤\"},{\"start\":173920,\"value\":\"已密密麻麻\"},{\"start\":177090,\"value\":\"不要再为了他挣扎\"},{\"start\":180270,\"value\":\"不要再为他左牵右挂\"},{\"start\":183760,\"value\":\"今后不管他爱不爱谁\"},{\"start\":186910,\"value\":\"快乐吗 都随他\"},{\"start\":204950,\"value\":\"就是爱到深处 才由他\"},{\"start\":209130,\"value\":\"碎了心 也要放得下\"},{\"start\":212180,\"value\":\"难道忘了那爱他的伤\"},{\"start\":215010,\"value\":\"已密密麻麻\"},{\"start\":218590,\"value\":\"就是爱到深处 才怨他\"},{\"start\":222760,\"value\":\"舍不舍得都断了吧\"},{\"start\":225920,\"value\":\"那是从来\"},{\"start\":227000,\"value\":\"都没有后路的悬崖\"},{\"start\":232340,\"value\":\"就是爱到深处 才由他\"},{\"start\":236570,\"value\":\"碎了心 也要放得下\"},{\"start\":239640,\"value\":\"难道忘了那爱他的伤\"},{\"start\":242430,\"value\":\"已密密麻麻\"},{\"start\":246940,\"value\":\"\"},{\"start\":247360,\"value\":\"Arranged By Michael Thompson\"},{\"start\":247590,\"value\":\"Acoustic Guitar Michael Thompson\"},{\"start\":247760,\"value\":\"Electric Guitar Michael Thompson\"},{\"start\":247940,\"value\":\"Guitar [Wah Wah] Michael Thompson\"},{\"start\":248130,\"value\":\"Soloist Michael Thompson\"},{\"start\":248330,\"value\":\"Bass Randy Jackson\"},{\"start\":248510,\"value\":\"Drums Vinnie Colaiuta\"},{\"start\":248690,\"value\":\"Engineer Bill Drescher\"},{\"start\":248880,\"value\":\"Engineer David N. Cole\"},{\"start\":249050,\"value\":\"Keyboards Jeffrey \\\"CJ\\\" Vanston\"},{\"start\":249230,\"value\":\"Programmed By Jeffrey \\\"CJ\\\" Vanston\"},{\"start\":249400,\"value\":\"Synth Jeffrey \\\"CJ\\\" Vanston\"},{\"start\":249590,\"value\":\"Lyrics By 萧慧文\"},{\"start\":249780,\"value\":\"Music By 张宇\"},{\"start\":249970,\"value\":\"Producer David N. Cole, Phil Chang\"},{\"start\":250140,\"value\":\"Mixed By David N. Cole\"},{\"start\":250500,\"value\":\"Recorded By Bill Schnee, Greg Droman, Richard Flack\"}],\"synced\":true}]",
"rgAlbumGain": -8.76,
"rgAlbumPeak": 0.998901,
"rgTrackGain": -9.65,
"rgTrackPeak": 0.988953,
"createdAt": "2024-02-04T00:11:12.548089502+08:00",
"updatedAt": "2024-03-21T21:42:11.165237602+08:00"
}
]
```
响应头:
- `x-total-count`: 总行数
:::tip
`id` 用于从歌单中删除歌曲,从 1 开始计数。
:::
### star 收藏歌曲/专辑/歌手
参见 Subsonic 的 [star](./subsonic#star-收藏歌曲专辑歌手) 接口。
### stream 歌曲播放链接
参见 Subsonic 的 [stream](./subsonic#stream-歌曲播放链接) 接口。
### unstar 取消收藏
参见 Subsonic 的 [unstar](./subsonic#unstar-取消收藏) 接口。
### playlist/[id] 更新歌单
PUT: `[host]/api/playlist/[id]`
body(`application/json`)
| 参数名 | 备注 |
| --- | --- |
| name | 歌单名 |
| comment | 评论 |
| public | 其他人是否可见 |
### playlist/tracks 添加歌曲到歌单
POST: `[host]/api/playlist/[id]/tracks`
body(`application/json`):
| 参数名 | 备注 |
| --- | --- |
| ids | 待添加的歌曲id列表, `,`分割 |
### playlist/tracks 从歌单中移除歌曲
DELETE: `[host]/api/playlist/[id]/tracks`
query:
| 参数名 | 备注 |
| --- | --- |
| id | 待移除的歌曲id多个id则以 `id=2&id=3` 的形式发起请求 |

View File

@@ -0,0 +1,824 @@
---
sidebar_position: 6
---
# Plex 接口文档
:::note 参考文档:
- [Plex API非官方](https://plexapi.dev/)
- [python-plexapi](https://github.com/pkkid/python-plexapi)
- [Plex Audio Transcoder File Extension](https://www.reddit.com/r/PleX/comments/189gtej/plex_audio_transcoder_file_extension/)
:::
## 认证
若无特殊说明,下文所有请求均需携带以下请求头。
| 参数名 | 备注 |
| --- | --- |
| X-Plex-Client-Identifier | 设备 ID |
| X-Plex-Platform | 操作系统,可选值:`Web`, `Android`, `iOS`, `MacOSX`, `Windows`, `Linux` |
| X-Plex-Provides | 应用类型,可选值:`player` |
| X-Plex-Product | 应用名称 |
| X-Plex-Version | 应用版本号 |
| X-Plex-Device | 设备型号 |
| X-Plex-Device-Name | 设备名 |
| X-Plex-Token | 访问令牌,登录成功后必填 |
### signin 登录
POST: `https://plex.tv/api/v2/users/signin`
body(`application/json`):
| 参数名 | 备注 |
| --- | --- |
| login | 用户名 |
| password | 密码 |
| verificationCode | OTP 验证码,可选 |
| rememberMe | 记住登录状态,可选值:`true`, `false` |
401 response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<errors>
<error code="1029" message="Please enter the verification code" status="401"/>
</errors>
```
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<user id="xxx" uuid="xxx" username="xxx" title="xxx" email="xxx@xxx.com" friendlyName="" locale="" confirmed="1" joinedAt="1701051277" emailOnlyAuth="0" hasPassword="1" protected="0" thumb="https://plex.tv/users/xxx/avatar?c=xxx" authToken="xxx" mailingListStatus="active" mailingListActive="1" scrobbleTypes="" country="CN" subscriptionDescription="Lifetime Plex Pass" restricted="0" anonymous="0" home="0" guest="0" homeSize="1" homeAdmin="0" maxHomeSize="15" rememberExpiresAt="1714812929" adsConsent="" adsConsentSetAt="" adsConsentReminderAt="" experimentalFeatures="1" twoFactorEnabled="1" backupCodesCreated="1">
<subscription active="1" subscribedAt="2024-03-24 05:13:37 UTC" status="Active" paymentService="braintree" plan="lifetime">
<features>
<feature id="guided-upgrade"/>
<feature id="increase-password-complexity"/>
<feature id="upgrade-3ds2"/>
<feature id="ad-countdown-timer"/>
<feature id="adaptive_bitrate"/>
<feature id="amazon-loop-debug"/>
<feature id="Android - Dolby Vision"/>
<feature id="Android - PiP"/>
<feature id="avod-ad-analysis"/>
<feature id="avod-new-media"/>
<feature id="blacklist_get_signin"/>
<feature id="camera_upload"/>
<feature id="CU Sunset"/>
<feature id="client-radio-stations"/>
<feature id="cloudsync"/>
<feature id="comments_and_replies_push_notifications"/>
<feature id="friend_request_push_notifications"/>
<feature id="community_access_plex_tv"/>
<feature id="companions_sonos"/>
<feature id="content_filter"/>
<feature id="custom-home-removal"/>
<feature id="grandfather-sync"/>
<feature id="disable_home_user_friendships"/>
<feature id="disable_sharing_friendships"/>
<feature id="downloads-gating"/>
<feature id="drm_support"/>
<feature id="dvr"/>
<feature id="dvr-block-unsupported-countries"/>
<feature id="epg-recent-channels"/>
<feature id="federated-auth"/>
<feature id="global-continue-watching"/>
<feature id="hwtranscode"/>
<feature id="hardware_transcoding"/>
<feature id="home"/>
<feature id="HRK_enable_EUR"/>
<feature id="imagga-v2"/>
<feature id="ios14-privacy-banner"/>
<feature id="item_clusters"/>
<feature id="iterable-notification-tokens"/>
<feature id="keep-payment-method"/>
<feature id="kevin-bacon"/>
<feature id="korea-consent"/>
<feature id="lets_encrypt"/>
<feature id="lightning-dvr-pivot"/>
<feature id="livetv"/>
<feature id="allow_dvr"/>
<feature id="live-tv-support-incomplete-segments"/>
<feature id="tuner-sharing"/>
<feature id="lyrics"/>
<feature id="metadata_search"/>
<feature id="vod_cloudflare"/>
<feature id="music_videos"/>
<feature id="new_plex_pass_prices"/>
<feature id="news-provider-sunset-modal"/>
<feature id="nominatim"/>
<feature id="pass"/>
<feature id="photos-favorites"/>
<feature id="photos-metadata-edition"/>
<feature id="photosV6-edit"/>
<feature id="photosV6-tv-albums"/>
<feature id="pms_health"/>
<feature id="premium-dashboard"/>
<feature id="premium_music_metadata"/>
<feature id="shared_server_notification"/>
<feature id="shared_source_notification"/>
<feature id="require-plex-nonce"/>
<feature id="scrobbling-service-plex-tv"/>
<feature id="album-types"/>
<feature id="collections"/>
<feature id="music-analysis"/>
<feature id="radio"/>
<feature id="session_bandwidth_restrictions"/>
<feature id="session_kick"/>
<feature id="exclude restrictions"/>
<feature id="signin_notification"/>
<feature id="signin_with_apple"/>
<feature id="sleep-timer"/>
<feature id="spring_serve_ad_provider"/>
<feature id="sync"/>
<feature id="trailers"/>
<feature id="transcoder_cache"/>
<feature id="boost-voices"/>
<feature id="TREBLE-show-features"/>
<feature id="silence-removal"/>
<feature id="sweet-fades"/>
<feature id="visualizers"/>
<feature id="volume-leveling"/>
<feature id="two-factor-authentication"/>
<feature id="unsupportedtuners"/>
<feature id="vod-schema"/>
<feature id="watch-together-invite"/>
<feature id="watchlist-rss"/>
<feature id="web_server_dashboard"/>
<feature id="webhooks"/>
</features>
</subscription>
<profile autoSelectAudio="0" defaultAudioLanguage="zh" defaultSubtitleLanguage="zh" autoSelectSubtitle="0" defaultSubtitleAccessibility="0" defaultSubtitleForced="0" watchedIndicator="1"/>
<entitlements>
<entitlement id="all"/>
<entitlement id="roku"/>
<entitlement id="android"/>
<entitlement id="xbox_one"/>
<entitlement id="xbox_360"/>
<entitlement id="windows"/>
<entitlement id="windows_phone"/>
<entitlement id="ios"/>
</entitlements>
<roles>
<role id="plexpass"/>
</roles>
<subscriptions>
<subscription id="" mode="lifetime" renewsAt="" endsAt="" canceled="0" gracePeriod="0" onHold="0" canReactivate="0" canUpgrade="0" canDowngrade="0" canConvert="0" type="plexpass" transfer="0" state="active">
<billing paymentMethodId="">
<internalPaymentMethod/>
</billing>
</subscription>
</subscriptions>
<pastSubscriptions></pastSubscriptions>
<trials></trials>
<services>
<service identifier="epg" endpoint="https://epg.provider.plex.tv" token="xxx=" secret="" status="online"/>
<service identifier="epg-staging" endpoint="https://epg-staging.provider.plex.tv" token="xxx=" secret="" status="online"/>
<service identifier="epg-dev" endpoint="https://epg-dev.provider.plex.tv" token="xxx=" secret="" status="online"/>
<service identifier="eyeq" endpoint="https://c4412416.ipg.web.cddbp.net/webapi/xml/1.0/" token="6iUU7xxxVrBzA/xxx+xxx" secret="" status="online"/>
<service identifier="eyeq-channel-icons" endpoint="http://akamai-b.cdn.cddbp.net/cds/2.0/image" token="" secret="" status="online"/>
<service identifier="graph-dev" endpoint="https://community-dev.plex.tv" token="" secret="" status="online"/>
<service identifier="graph-staging" endpoint="https://community-staging.plex.tv" token="" secret="" status="online"/>
<service identifier="community-dev" endpoint="https://community-dev.plex.tv" token="" secret="" status="online"/>
<service identifier="community-staging" endpoint="https://community-staging.plex.tv" token="" secret="" status="online"/>
<service identifier="community" endpoint="https://community.plex.tv" token="" secret="" status="online"/>
<service identifier="metadata" endpoint="https://metadata.provider.plex.tv" token="xxx=" secret="" status="online"/>
<service identifier="scrobbling" endpoint="https://scrobbles.plex.tv" token="xxx.xxx.ukvm_-xxx-xxx-xxx-3Vamxi7eNG-xxx-xxx-d7z-xxx" secret="" status="online"/>
<service identifier="metadata-dev" endpoint="https://metadata-dev.provider.plex.tv" token="xxx=" secret="" status="online"/>
<service identifier="metadata-provider" endpoint="https://mpm.plex.tv/" token="" secret="" status="online"/>
<service identifier="tmsapi" endpoint="https://tmsapi.plex.tv/v1.1/" token="xxx+OQ=" secret="" status="online"/>
<service identifier="subtitles-search" endpoint="https://metadata.provider.plex.tv/library/streams/matches" token="xxx=" secret="" status="online"/>
<service identifier="acoustid" endpoint="https://acoustid.plex.tv/" token="xxx==" secret="" status="online"/>
<service identifier="lyricfind" endpoint="https://lyricfind.plex.tv/" token="xxx+/xxx/zqV1" secret="H8q1AfgeOcf8+xxx+teyIOw" status="online"/>
<service identifier="lyricfind-search" endpoint="https://lyricfind.plex.tv/" token="4HRR+YgScsy+xxx+xxx" secret="" status="online"/>
<service identifier="tvdb" endpoint="https://api4.thetvdb.com/" token="xxx+9EAH+xxx/xxx" secret="" status="online"/>
</services>
</user>
```
### resources 获取资源列表
GET: `https://plex.tv/api/v2/resources?includeHttps=1&includeRelay=1`
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<resources>
<resource name="xxx" product="Plex Media Server" productVersion="1.29.2" platform="Linux" platformVersion="DSM" device="DS+" clientIdentifier="xxx" createdAt="2024-03-17T11:34:53Z" lastSeenAt="2024-04-19T19:09:52Z" provides="server" ownerId="" sourceTitle="" publicAddress="22.22.22.22" accessToken="xxx" owned="1" home="0" synced="0" relay="1" presence="1" httpsRequired="0" publicAddressMatches="1" dnsRebindingProtection="0" natLoopbackSupported="0">
<connections>
<connection protocol="https" address="192.168.22.22" port="32400" uri="https://192-168-22-22.xxx.plex.direct:32400" local="1" relay="0" IPv6="0"/>
<connection protocol="https" address="139.162.22.22" port="8443" uri="https://139-162-22-22.xxx.plex.direct:8443" local="0" relay="1" IPv6="0"/>
</connections>
</resource>
</resources>
```
### 测试服务器连通性
GET: `[host]`
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="25" allowCameraUpload="1" allowChannelAccess="1" allowMediaDeletion="1" allowSharing="1" allowSync="1" allowTuners="1" backgroundProcessing="1" certificate="1" companionProxy="1" countryCode="chn" diagnostics="logs,databases,streaminglogs" eventStream="1" friendlyName="xxx" hubSearch="1" itemClusters="1" livetv="7" machineIdentifier="xxx" mediaProviders="1" multiuser="1" musicAnalysis="2" myPlex="1" myPlexMappingState="mapped" myPlexSigninState="ok" myPlexSubscription="1" myPlexUsername="xxx" offlineTranscode="1" ownerFeatures="fec722a0-a6d4-4fbd-96dc-4ffb02b072c5,federated-auth,hardware_transcoding,home,hwtranscode,item_clusters,kevin-bacon,livetv,loudness,lyrics,music-analysis,music_videos,pass,photosV6-edit,photosV6-tv-albums,premium_music_metadata,radio,server-manager,session_bandwidth_restrictions,session_kick,shared-radio,sync,trailers,tuner-sharing,type-first,unsupportedtuners,webhooks" photoAutoTag="1" platform="Linux" platformVersion="DSM" pluginHost="1" pushNotifications="0" readOnlyLibraries="0" streamingBrainABRVersion="3" streamingBrainVersion="2" sync="1" transcoderActiveVideoSessions="0" transcoderAudio="1" transcoderLyrics="1" transcoderPhoto="1" transcoderSubtitles="1" transcoderVideo="1" transcoderVideoBitrates="64,96,208,320,720,1500,2000,3000,4000,8000,10000,12000,20000" transcoderVideoQualities="0,1,2,3,4,5,6,7,8,9,10,11,12" transcoderVideoRemuxOnly="1" transcoderVideoResolutions="128,128,160,240,320,480,768,720,720,1080,1080,1080,1080" updatedAt="1712973038" updater="1" version="1.29.2" voiceSearch="1">
<Directory count="1" key="actions" title="actions" />
<Directory count="1" key="activities" title="activities" />
<Directory count="1" key="butler" title="butler" />
<Directory count="1" key="channels" title="channels" />
<Directory count="1" key="clients" title="clients" />
<Directory count="1" key="devices" title="devices" />
<Directory count="1" key="diagnostics" title="diagnostics" />
<Directory count="1" key="hubs" title="hubs" />
<Directory count="3" key="library" title="library" />
<Directory count="3" key="livetv" title="livetv" />
<Directory count="3" key="media" title="media" />
<Directory count="3" key="metadata" title="metadata" />
<Directory count="1" key="neighborhood" title="neighborhood" />
<Directory count="1" key="playQueues" title="playQueues" />
<Directory count="1" key="player" title="player" />
<Directory count="1" key="playlists" title="playlists" />
<Directory count="1" key="resources" title="resources" />
<Directory count="1" key="search" title="search" />
<Directory count="1" key="server" title="server" />
<Directory count="1" key="servers" title="servers" />
<Directory count="1" key="statistics" title="statistics" />
<Directory count="1" key="system" title="system" />
<Directory count="1" key="transcode" title="transcode" />
<Directory count="1" key="updater" title="updater" />
<Directory count="1" key="user" title="user" />
</MediaContainer>
```
## 请求节点
### agents 获取代理(插件)列表
GET: `[host]/system/agents/com.plexapp.agents.none/config/8?X-Plex-Token=[token]`
结尾的 `8` 表示查询艺术家相关的代理。
response:
```xml
<?xml version="1.0" encoding="utf-8"?>
<MediaContainer noHistory="0" replaceParent="0" size="9" identifier="com.plexapp.system">
<Agent name="Personal Media Artists" enabled="1" hasPrefs="0" identifier="com.plexapp.agents.none"/>
<Agent name="Local Media Assets (Artists)" enabled="1" hasPrefs="0" identifier="com.plexapp.agents.localmedia"/>
<Agent name="Fanart.tv" hasPrefs="1" identifier="com.plexapp.agents.fanarttv"/>
<Agent name="Home Theater Backdrops" hasPrefs="0" identifier="com.plexapp.agents.htbackdrops"/>
<Agent name="Last.fm" hasPrefs="1" identifier="com.plexapp.agents.lastfm"/>
<Agent name="Musicbrainz" hasPrefs="1" identifier="org.musicbrainz.agents.music"/>
<Agent name="Plex Music" hasPrefs="1" identifier="tv.plex.agents.music"/>
</MediaContainer>
```
### sections 获取资料库列表
GET: `[host]/library/sections`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1" allowSync="0" title1="Plex Library">
<Directory allowSync="1" art="/:/resources/artist-fanart.jpg" composite="/library/sections/1/composite/xxx" filters="1" refreshing="0" thumb="/:/resources/artist.png" key="1" type="artist" title="&#38899;&#20048;" agent="com.plexapp.agents.xxx" scanner="Plex Music Scanner" language="zh" uuid="0d645d8b-xxxx-44f5-xxxx-7b90f6be6d67" updatedAt="1711858705" createdAt="1710675339" scannedAt="1713579735" content="1" directory="1" contentChangedAt="198267" hidden="0">
<Location id="1" path="/volume1/music" />
</Directory>
</MediaContainer>
```
在返回的列表中筛选 `type="artist"`的资料库,记录一下 `key` 值。
### sections 获取专辑列表
GET: `[host]/library/sections/[sectionKey]/all`
query:
| 参数名 | 备注 |
| --- | --- |
| type | 类型,固定为 `9` |
| sort | 排序方式,默认按专辑艺术家排序,可选值 `addedAt:desc` |
| title | 标题,可选 |
| includeAdvanced | `1` |
| includeCollections | `1` |
| includeExternalMedia | `1` |
| X-Plex-Container-Start | 起始行数 |
| X-Plex-Container-Size | 结果数量 |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1" totalSize="3636" offset="100" allowSync="1" art="/:/resources/artist-fanart.jpg" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="&#38899;&#20048;" librarySectionUUID="0d645d8b-6bca-44f5-8105-7b90f6be6d67" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136" nocache="1" thumb="/:/resources/artist.png" title1="&#38899;&#20048;" title2="All Artists" viewGroup="artist" viewMode="65592">
<Directory ratingKey="8014" key="/library/metadata/8014/children" parentRatingKey="8013" guid="local://8014" parentGuid="plex://artist/5d07bc05403c6402904ac4d2" type="album" title="Sing Me to Sleep" parentKey="/library/metadata/8013" parentTitle="Ben Folds" summary="" index="1" year="2015" thumb="/library/metadata/8014/thumb/1710932639" art="/library/metadata/8013/art/1711359519" parentThumb="/library/metadata/8013/thumb/1711359519" originallyAvailableAt="2015-01-01" addedAt="1710931892" updatedAt="1710932639" loudnessAnalysisVersion="2">
</Directory>
</MediaContainer>
```
### metadata 获取专辑信息
GET: `[host]/library/metadata/[id]`
query:
| 参数名 | 备注 |
| --- | --- |
| includeConcerts | `1` |
| includeExtras | `1` |
| includeOnDeck | `1` |
| includePopularLeaves | `1` |
| includePreferences | `1` |
| includeChapters | `1` |
| includeStations | `1` |
| includeMarkers | `1` |
| includeExternalMedia | `1` |
| asyncAugmentMetadata | `1` |
| includeRelated | `1` |
| checkFiles | `1` |
| asyncRefreshAnalysis | `1` |
| asyncRefreshLocalMediaAgent | `1` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1" allowSync="1" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="&#38899;&#20048;" librarySectionUUID="0d645d8b-6bca-44f5-8105-7b90f6be6d67" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136">
<Directory ratingKey="8014" key="/library/metadata/8014/children" parentRatingKey="8013" guid="local://8014" parentGuid="plex://artist/5d07bc05403c6402904ac4d2" type="album" title="Sing Me to Sleep" parentKey="/library/metadata/8013" librarySectionTitle="&#38899;&#20048;" librarySectionID="1" librarySectionKey="/library/sections/1" parentTitle="Ben Folds" summary="" index="1" year="2015" thumb="/library/metadata/8014/thumb/1710932639" art="/library/metadata/8013/art/1711359519" parentThumb="/library/metadata/8013/thumb/1711359519" originallyAvailableAt="2015-01-01" leafCount="1" viewedLeafCount="0" addedAt="1710931892" updatedAt="1710932639" loudnessAnalysisVersion="2">
<Extras size="0">
</Extras>
<Related>
</Related>
</Directory>
</MediaContainer>
```
### children 获取歌手名下的专辑
GET: `[host]/library/metadata/[id]/children`
query:
| 参数名 | 备注 |
| --- | --- |
| excludeAllLeaves | `1` |
### sections 获取歌手列表
GET: `[host]/library/sections/[sectionKey]/all`
query:
| 参数名 | 备注 |
| --- | --- |
| type | 类型,固定为 `8` |
| includeAdvanced | `1` |
| includeCollections | `1` |
| includeExternalMedia | `1` |
| X-Plex-Container-Start | 起始行数 |
| X-Plex-Container-Size | 结果数量 |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="2" totalSize="858" offset="0" allowSync="1" art="/:/resources/artist-fanart.jpg" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="音乐" librarySectionUUID="0d645d8b-6bca-44f5-8105-7b90f6be6d67" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136" nocache="1" thumb="/:/resources/artist.png" title1="音乐" title2="All Artists" viewGroup="artist" viewMode="65592">
<Directory ratingKey="21227" key="/library/metadata/21227/children" guid="com.plexapp.agents.xxx://85323?lang=zh" type="artist" title="2 Unlimited" titleSort="2 UNLIMITED" summary="来自荷兰的二人跳舞组合“双人无极”2 Unlimited是由主音歌手anita Doth和说唱手ray Slijngaard所组成配合两位长期合作的作曲人jean-paul De Coster和作词人phil Wilde。首张单曲《get Ready For This》一推出立即红遍全球而且四年后再一次打上美国billboard四十位之内该乐队先后推出三张销量惊人的专辑分别是get Ready,no Limit和real Thing碟内每张单曲均成绩骄人《no Limit》是35个国家排行榜的冠军单曲总销量超越250万张随后的《tribal Dance》、《maximum Drive》、《no One》等都是排行榜冠军歌曲。本专辑收录他们所有精彩流行作品更收录三首全新歌曲另外不特别加送精选串烧歌。Techno跳舞音乐的兴起和流行“双人无极”组合可说是功不可没他们亦代表了 Techno Dance文化。" index="1" thumb="/library/metadata/21227/thumb/1711359363" art="/library/metadata/21227/art/1711359363" addedAt="1710940905" updatedAt="1711359363"></Directory>
<Directory ratingKey="17139" key="/library/metadata/17139/children" guid="com.plexapp.agents.xxx://31081554?lang=zh" type="artist" title="24kGoldn" titleSort="24KGOLDN" summary="24KGOLDN是一名说唱歌手、歌手、编剧和来自加利福尼亚旧金山的前USC学生吹嘘诸如“Valentino”和“City of Angels”。他的首张EP《Dropped Outta College》现在在唱片公司/哥伦比亚唱片公司上映。" index="1" thumb="/library/metadata/17139/thumb/1711359367" addedAt="1710937685" updatedAt="1711359367"></Directory>
</MediaContainer>
```
### metadata 获取歌手信息
GET: `[host]/library/metadata/[id]`
query:
| 参数名 | 备注 |
| --- | --- |
| includeConcerts | `1` |
| includeExtras | `1` |
| includeOnDeck | `1` |
| includePopularLeaves | `1` |
| includePreferences | `1` |
| includeChapters | `1` |
| includeStations | `1` |
| includeMarkers | `1` |
| includeExternalMedia | `1` |
| asyncAugmentMetadata | `1` |
| includeRelated | `1` |
| checkFiles | `1` |
| asyncRefreshAnalysis | `1` |
| asyncRefreshLocalMediaAgent | `1` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1" allowSync="1" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="音乐" librarySectionUUID="0d645d8b-6bca-44f5-8105-7b90f6be6d67" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136">
<Directory ratingKey="17139" key="/library/metadata/17139/children" guid="com.plexapp.agents.xxx://31081554?lang=zh" type="artist" title="24kGoldn" titleSort="24KGOLDN" librarySectionTitle="音乐" librarySectionID="1" librarySectionKey="/library/sections/1" summary="24KGOLDN是一名说唱歌手、歌手、编剧和来自加利福尼亚旧金山的前USC学生吹嘘诸如“Valentino”和“City of Angels”。他的首张EP《Dropped Outta College》现在在唱片公司/哥伦比亚唱片公司上映。" index="1" thumb="/library/metadata/17139/thumb/1711359367" addedAt="1710937685" updatedAt="1711359367">
<Guid id="mbid://0fe5df51-ba65-4784-ba85-7d024a107a8a" />
<Location path="/volume1/music/24kGoldn" />
<Preferences>
<Setting id="albumSort" label="Album sorting" summary="How to sort the albums for an artist." type="text" default="-1" value="-1" hidden="0" advanced="0" group="" enumValues="-1:Library default|0:Newest first|1:Oldest first|2:By name" />
</Preferences>
<Extras size="0"></Extras>
<Related>
<Hub key="/library/sections/1/all?artist.id=17139&type=9&format=EP,Single&resolveTags=1&sort=year:desc,originallyAvailableAt:desc,artist.titleSort:desc,album.titleSort,album.index,album.id,album.originallyAvailableAt" title="Singles & EPs" type="album" hubIdentifier="artist.albums.singles" context="hub.artist.albums.singles" size="0" more="0" style="shelf"></Hub>
<Hub key="/library/sections/1/all?artist.id=17139&type=9&format!=EP,Single&subformat=Live&resolveTags=1&sort=year:desc,originallyAvailableAt:desc,artist.titleSort:desc,album.titleSort,album.index,album.id,album.originallyAvailableAt" title="Live Albums" type="album" hubIdentifier="artist.albums.live" context="hub.artist.albums.live" size="0" more="0" style="shelf"></Hub>
<Hub key="/library/sections/1/all?artist.id=17139&type=9&format!=EP,Single&subformat=Soundtrack&subformat!=Live&resolveTags=1&sort=year:desc,originallyAvailableAt:desc,artist.titleSort:desc,album.titleSort,album.index,album.id,album.originallyAvailableAt" title="Soundtracks" type="album" hubIdentifier="artist.albums.soundtrack" context="hub.artist.albums.soundtrack" size="0" more="0" style="shelf"></Hub>
<Hub key="/library/sections/1/all?artist.id=17139&type=9&format!=EP,Single&subformat=Compilation&subformat!=Live,Soundtrack&resolveTags=1&sort=year:desc,originallyAvailableAt:desc,artist.titleSort:desc,album.titleSort,album.index,album.id,album.originallyAvailableAt" title="Compilations" type="album" hubIdentifier="artist.albums.compilation" context="hub.artist.albums.compilation" size="0" more="0" style="shelf"></Hub>
<Hub key="/library/sections/1/all?artist.id=17139&type=9&format!=EP,Single&subformat=Demo&subformat!=Live,Soundtrack,Compilation&resolveTags=1&sort=year:desc,originallyAvailableAt:desc,artist.titleSort:desc,album.titleSort,album.index,album.id,album.originallyAvailableAt" title="Demos" type="album" hubIdentifier="artist.albums.demo" context="hub.artist.albums.demo" size="0" more="0" style="shelf"></Hub>
<Hub key="/library/sections/1/all?artist.id=17139&type=9&format!=EP,Single&subformat=Remix&subformat!=Live,Soundtrack,Compilation,Demo&resolveTags=1&sort=year:desc,originallyAvailableAt:desc,artist.titleSort:desc,album.titleSort,album.index,album.id,album.originallyAvailableAt" title="Remixes" type="album" hubIdentifier="artist.albums.remix" context="hub.artist.albums.remix" size="0" more="0" style="shelf"></Hub>
</Related>
<Stations size="1">
<Playlist key="/library/metadata/17139/station/fb23b278-81c4-410a-a187-ae92906c6973?type=10" guid="" type="playlist" title="24kGoldn Radio" librarySectionTitle="音乐" librarySectionID="1" librarySectionKey="/library/sections/1" summary="" smart="1" playlistType="audio" leafCount="0" icon="playlist://image.radio" radio="1"></Playlist>
</Stations>
<PopularLeaves size="0" key="/library/sections/1/all?album.subformat!=Compilation,Live&artist.id=17139&group=title&limit=100&ratingCount>=1&resolveTags=1&sort=ratingCount:desc&type=10"></PopularLeaves>
</Directory>
</MediaContainer>
```
### photo 图片链接
GET: `[host]/photo/:/transcode`
query:
| 参数名 | 备注 |
| --- | --- |
| width | 宽度 |
| height | 高度 |
| minSize | `1` |
| upscale | `1` |
| url | `[thumb]?X-Plex-Token=[token]` |
| X-Plex-Token | 访问令牌 |
### playlists 创建歌单
GET: `[host]/playlists`
首先需要通过 [测试服务器连通性](#测试服务器连通性) 的响应拿到 `machineIdentifier`
query:
| 参数名 | 备注 |
| --- | --- |
| type | 类型,固定为 `audio` |
| title | 歌单名 |
| smart | 是否智能歌单,可选值:`1`, `0` |
| uri | `server://[machineIdentifier]/com.plexapp.plugins.library/library/metadata/[歌曲ID列表]` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1">
<Playlist ratingKey="24055" key="/playlists/24055/items" guid="com.plexapp.agents.none://3a0bd837-d83a-4d59-bdca-4d6e747fab35" type="playlist" title="6655" summary="" smart="0" playlistType="audio" leafCount="0" addedAt="1713620514" updatedAt="1713620514"></Playlist>
</MediaContainer>
```
### playlists 删除歌单
DELETE: `[host]/playlists/[id]`
### metadata 删除歌曲
DELETE: `[host]/library/metadata/[id]`
### folder 获取目录列表
GET: `/library/sections/[sectionId]/folder`
query:
| 参数名 | 备注 |
| --- | --- |
| X-Plex-Container-Start | 行数偏移 |
| X-Plex-Container-Size | 结果数量 |
| includeCollections | `1` |
| includeExternalMedia | `1` |
| includeAdvanced | `1` |
| includeMeta | `1` |
| parent | 目录ID不传时查询根目录 |
### genre 获取类型列表
GET: `[host]/library/sections/[sectionId]/genre`
query:
| 参数名 | 备注 |
| --- | --- |
| type | `9` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="32" allowSync="0" art="/:/resources/artist-fanart.jpg" content="secondary" identifier="com.plexapp.plugins.library" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136" nocache="1" thumb="/:/resources/artist.png" title1="音乐" title2="By Genre" viewGroup="secondary" viewMode="65592">
<Directory fastKey="/library/sections/1/all?genre=231" key="231" title="Abstract" type="genre" />
<Directory fastKey="/library/sections/1/all?genre=19984" key="19984" title="Alternative 另类" type="genre" />
<Directory fastKey="/library/sections/1/all?genre=3941" key="3941" title="国际流行" type="genre" />
<Directory fastKey="/library/sections/1/all?genre=19688" key="19688" title="流行" type="genre" />
<Directory fastKey="/library/sections/1/all?genre=1625" key="1625" title="粤语流行" type="genre" />
</MediaContainer>
```
### streams 获取歌词
GET: `[host]/library/streams/[id]`
query:
| 参数名 | 备注 |
| --- | --- |
| format | 格式,可选值:`xml` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1">
<Lyrics provider="com.plexapp.agents.localmedia" minLines="0" timed="1" author="" by="">
<Line startOffset="0" endOffset="1000">
<Span text="作词 : xxx" startOffset="1000" endOffset="2000" />
</Line>
</Lyrics>
</MediaContainer>
```
### matches 获取歌手匹配结果
GET: `[host]/library/metadata/[id]/matches`
query:
| 参数名 | 备注 |
| --- | --- |
| manual | 是否手动,固定为 `0` |
| agent | 代理ID |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="4" identifier="com.plexapp.plugins.library" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136">
<SearchResult guid="com.plexapp.agents.xxx://791534?lang=zh" name="戴荃" score="106" lifespanEnded="0"></SearchResult>
<SearchResult guid="com.plexapp.agents.xxx://791534?lang=zh" name="戴荃" score="106" lifespanEnded="0"></SearchResult>
<SearchResult guid="com.plexapp.agents.xxx://11975111?lang=zh" name="ilem" score="86" lifespanEnded="0"></SearchResult>
<SearchResult guid="com.plexapp.agents.xxx://11975111?lang=zh" name="ilem" score="77" lifespanEnded="0"></SearchResult>
</MediaContainer>
```
### match 确认歌手匹配结果
PUT: `[host]/library/metadata/[id]/match`
query:
| 参数名 | 备注 |
| --- | --- |
| name | 歌手名 |
| agent | |
### playlists 获取歌单列表
GET: `[host]/playlists`
query:
| 参数名 | 备注 |
| --- | --- |
| playlistType | `audio` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="3">
<Playlist ratingKey="24053" key="/playlists/24053/items" guid="com.plexapp.agents.none://de11d190-442c-4c2e-853f-6c8e4c078e27" type="playlist" title="1999年老歌by慕星人" summary="" smart="0" playlistType="audio" composite="/playlists/24053/composite/1713319718" viewCount="1" lastViewedAt="1713319717" duration="7984000" leafCount="30" addedAt="1713319717" updatedAt="1713319718"></Playlist>
</MediaContainer>
```
### rate 评分歌曲/专辑/歌手
PUT: `[host]/:/rate`
query:
| 参数名 | 备注 |
| --- | --- |
| key | 歌曲/专辑/歌手ID |
| identifier | `com.plexapp.plugins.library` |
| rating | 评分0-10之间 |
### scrobble 滚动播放记录
**更新播放进度**
GET: `[host]/:/timeline`
query:
| 参数名 | 备注 |
| --- | --- |
| ratingKey | 歌曲ID |
| time | 播放进度单位ms |
| state | 播放状态,可选值:`playing`, `paused` |
> 此接口不会将歌曲播放次数+1需要手动调用下面的接口。
**将歌曲标记为已播放**
GET: `[host]/:/scrobble`
query:
| 参数名 | 备注 |
| --- | --- |
| key | 歌曲ID |
| identifier | `com.plexapp.plugins.library` |
### sections 获取歌曲列表
GET: `[host]/library/sections/[sectionKey]/all`
query:
| 参数名 | 备注 |
| --- | --- |
| type | 类型,固定为 `10` |
| sort | 排序方式,可选值:`random`, `addedAt`, `year`, `lastViewedAt`, `titleSort`, `album.titleSort`, `ratingCount`,若要倒序,则使用 `addedAt:desc` 这种格式。 |
| includeCollections | `1` |
| includeExternalMedia | `1` |
| artist.id | 歌手ID可选 |
| userRating | 评分,可选 |
| title | 标题,可选 |
| X-Plex-Container-Start | 起始行数 |
| X-Plex-Container-Size | 结果数量 |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1" totalSize="19403" offset="0" allowSync="1" art="/:/resources/artist-fanart.jpg" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="音乐" librarySectionUUID="0d645d8b-6bca-44f5-8105-7b90f6be6d67" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136" nocache="1" thumb="/:/resources/artist.png" title1="音乐" title2="All Artists" viewGroup="artist" viewMode="65592">
<Track ratingKey="3609" key="/library/metadata/3609" parentRatingKey="3608" grandparentRatingKey="3605" guid="plex://track/6344359ca5c478aa2b7a54b8" parentGuid="plex://album/633ae09ba5c478aa2b6619d2" grandparentGuid="plex://artist/633ae07aa5c478aa2b62fd54" type="track" title="可能否" grandparentKey="/library/metadata/3605" parentKey="/library/metadata/3608" grandparentTitle="木小雅" parentTitle="可能否" summary="" index="1" parentIndex="1" ratingCount="673" userRating="10.0" lastRatedAt="1713319768" parentYear="2018" thumb="/library/metadata/3608/thumb/1710954289" parentThumb="/library/metadata/3608/thumb/1710954289" duration="227944" addedAt="1638002162" updatedAt="1711289822">
<Media id="2800" duration="227944" bitrate="128" audioChannels="2" audioCodec="mp3" container="mp3">
<Part id="2800" key="/library/parts/2800/1711051647/file.mp3" duration="227944" file="/volume1/music/木小雅/可能否/可能否.mp3" size="3727358" container="mp3" hasThumbnail="1" />
</Media>
</Track>
</MediaContainer>
```
### metadata 获取歌曲信息
GET: `[host]/library/metadata/[id]`
query:
| 参数名 | 备注 |
| --- | --- |
| includeConcerts | `1` |
| includeExtras | `1` |
| includeOnDeck | `1` |
| includePopularLeaves | `1` |
| includePreferences | `1` |
| includeChapters | `1` |
| includeStations | `1` |
| includeMarkers | `1` |
| includeExternalMedia | `1` |
| asyncAugmentMetadata | `1` |
| includeRelated | `1` |
| checkFiles | `1` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="1" allowSync="1" augmentationKey="/library/metadata/augmentations/88" identifier="com.plexapp.plugins.library" librarySectionID="1" librarySectionTitle="音乐" librarySectionUUID="0d645d8b-6bca-44f5-8105-7b90f6be6d67" mediaTagPrefix="/system/bundle/media/flags/" mediaTagVersion="1667296136">
<Track ratingKey="3609" key="/library/metadata/3609" parentRatingKey="3608" grandparentRatingKey="3605" guid="plex://track/6344359ca5c478aa2b7a54b8" parentGuid="plex://album/633ae09ba5c478aa2b6619d2" grandparentGuid="plex://artist/633ae07aa5c478aa2b62fd54" type="track" title="可能否" grandparentKey="/library/metadata/3605" parentKey="/library/metadata/3608" librarySectionTitle="音乐" librarySectionID="1" librarySectionKey="/library/sections/1" grandparentTitle="木小雅" parentTitle="可能否" summary="" index="1" parentIndex="1" ratingCount="673" userRating="10.0" lastRatedAt="1713319768" parentYear="2018" thumb="/library/metadata/3608/thumb/1710954289" parentThumb="/library/metadata/3608/thumb/1710954289" duration="227944" addedAt="1638002162" updatedAt="1711289822">
<Media id="2800" duration="227944" bitrate="128" audioChannels="2" audioCodec="mp3" container="mp3">
<Part accessible="1" exists="1" id="2800" key="/library/parts/2800/1711051647/file.mp3" duration="227944" file="/volume1/music/木小雅/可能否/可能否.mp3" size="3727358" container="mp3" hasThumbnail="1">
<Stream id="2800" streamType="2" selected="1" codec="mp3" index="0" channels="2" bitrate="128" albumGain="-3.84" albumPeak="1.000000" albumRange="12.185394" audioChannelLayout="stereo" gain="-3.84" loudness="-14.16" lra="12.19" peak="1.000000" samplingRate="44100" displayTitle="MP3 (Stereo)" extendedDisplayTitle="MP3 (Stereo)"></Stream>
</Part>
</Media>
<Guid id="mbid://ea6cdd7e-d9fc-419c-b994-01c1c1f79b5c" />
<Extras size="0"></Extras>
<Related></Related>
</Track>
</MediaContainer>
```
### children 获取专辑中的歌曲
GET: `[host]/library/metadata/[id]/children`
query:
| 参数名 | 备注 |
| --- | --- |
| excludeAllLeaves | `1` |
### items 获取歌单中的歌曲
GET: `[host]/playlists/[id]/items`
query:
| 参数名 | 备注 |
| --- | --- |
| type | `track` |
response:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<MediaContainer size="2" composite="/playlists/23237/composite/1712824484" duration="490" leafCount="2" playlistType="audio" ratingKey="23237" smart="0" title="古风">
<Track ratingKey="20887" key="/library/metadata/20887" parentRatingKey="20886" grandparentRatingKey="20808" guid="local://20887" parentGuid="local://20886" grandparentGuid="plex://artist/5d07bc92403c64029052193c" type="track" title="是你" grandparentKey="/library/metadata/20808" parentKey="/library/metadata/20886" librarySectionTitle="音乐" librarySectionID="1" librarySectionKey="/library/sections/1" grandparentTitle="弦子" parentTitle="长风渡 影视原声带" originalTitle="弦子/李茂" summary="" index="3" parentIndex="1" userRating="10.0" viewCount="10" lastViewedAt="1713282859" lastRatedAt="1711882837" parentYear="2023" thumb="/library/metadata/20886/thumb/1710944657" parentThumb="/library/metadata/20886/thumb/1710944657" playlistItemID="46" duration="253397" addedAt="1710940658" updatedAt="1711291448">
<Media id="16815" duration="253397" bitrate="1701" audioChannels="2" audioCodec="flac" container="flac">
<Part id="16815" key="/library/parts/16815/1711029835/file.flac" duration="253397" file="/volume1/music/弦子/李茂/长风渡 影视原声带/弦子 _ 李茂 - 是你.flac" size="53958405" container="flac" hasThumbnail="1" />
</Media>
</Track>
<Track ratingKey="23890" key="/library/metadata/23890" parentRatingKey="23888" grandparentRatingKey="6277" guid="com.plexapp.agents.qqmusic://0011CYh41MbdFm/001YwctD3AleZ4/-1/10?lang=zh" parentGuid="com.plexapp.agents.qqmusic://0011CYh41MbdFm/001YwctD3AleZ4?lang=zh" grandparentGuid="com.plexapp.agents.qqmusic://0011CYh41MbdFm?lang=zh" parentStudio="寰亚音乐" type="track" title="Anita" grandparentKey="/library/metadata/6277" parentKey="/library/metadata/23888" librarySectionTitle="音乐" librarySectionID="1" librarySectionKey="/library/sections/1" grandparentTitle="梅艳芳" parentTitle="封面女郎" originalTitle="梅艳芳" summary="" index="10" viewCount="1" lastViewedAt="1712824795" parentYear="1990" thumb="/library/metadata/23888/thumb/1712719241" parentThumb="/library/metadata/23888/thumb/1712719241" grandparentThumb="/library/metadata/6277/thumb/1711889072" playlistItemID="48" duration="237373" addedAt="1712719232" updatedAt="1712719399">
<Media id="19277" duration="237373" bitrate="842" audioChannels="2" audioCodec="flac" container="flac">
<Part id="19277" key="/library/parts/19277/1712645733/file.flac" duration="237373" file="/volume1/music/梅艳芳/封面女郎/梅艳芳-Anita.flac" size="25106519" container="flac" hasThumbnail="1" />
</Media>
</Track>
</MediaContainer>
```
### 收藏歌曲/专辑/歌手
Plex 没有收藏功能,建议筛选评分为 10 的作为收藏项目。
### transcode 歌曲播放链接
**不转码**
首先需要获取歌曲信息中的 `Track.Media.Part.key`
GET: `[host]/[partKey]`
query:
| 参数名 | 备注 |
| --- | --- |
| X-Plex-Token | 访问令牌 |
| X-Plex-Platform | 操作系统,可选值:`Web`, `Android`, `iOS`, `MacOSX`, `Windows`, `Linux` |
**转码**
GET: `[host]/music/:/transcode/universal/start`
query:
| 参数名 | 备注 |
| --- | --- |
| path | `/library/metadata/[id]` |
| directPlay | `0` |
| musicBitrate | 比特率 |
| session | 会话ID客户端随机生成 |
| X-Plex-Token | 访问令牌 |
| X-Plex-Platform | 操作系统,可选值:`Web`, `iOS` |
:::note
转码还有更详细的配置,这里记录是直接返回转码后的文件的链接,若需 hls 等其他协议,请参考顶部列出的参考文档。
:::
### items 添加歌曲到歌单
PUT: `[host]/playlists/[id]/items`
query:
| 参数名 | 备注 |
| --- | --- |
| uri | `server://[machineIdentifier]/com.plexapp.plugins.library/library/metadata/[歌曲ID列表]` |
### items 从歌单中移除歌曲
DELETE: `[host]/playlists/[id]/items/[songId]`
:::note
此接口只能单个移除。
:::
### playlists 更新歌单信息
PUT: `[host]/playlists/[id]`
query:
| 参数名 | 备注 |
| --- | --- |
| title | 歌单名 |
| summary | 评论,可选 |

View File

@@ -0,0 +1,632 @@
---
sidebar_position: 1
---
# Subsonic 接口文档
:::note 参考文档:
- [Subsonic](https://www.subsonic.org/pages/api.jsp)
- ~~[OpenSubsonic](https://opensubsonic.netlify.app/docs/)~~
:::
## 认证
所有请求均需携带以下参数:
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| u | Y | | 用户名 |
| t | Y | | 以md5(密码+盐)计算出的身份验证令牌 |
| s | Y | | 盐随机生成至少6位 |
| v | Y | | 客户端实现的协议版本 |
| c | Y | | 客户端名称 |
| f | N | xml | 返回格式,可选值: `xml`, `json`, `jsonp`。 |
示例:
```js
password = 'sesame'
salt = 'c19b2d'
token = md5('sesamec19b2d') = '26719a1196d2a940705a59634eb18eab'
url = 'http://your-server/rest/ping.view?u=joe&t=26719a1196d2a940705a59634eb18eab&s=c19b2d&v=1.12.0&c=myapp'
```
## 错误代码
| 代码 | 备注 |
| --- | --- |
| 0 | 一般性错误 |
| 10 | 缺少参数 |
| 20 | 客户端版本过低 |
| 30 | 服务端版本过低 |
| 40 | 用户名或密码错误 |
| 50 | 无权限 |
| 60 | Subsonic 试用期已结束 |
| 70 | 未找到请求的数据 |
示例:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<subsonic-response xmlns="http://subsonic.org/restapi" status="failed" version="1.1.0">
<error code="40" message="Wrong username or password"/>
</subsonic-response>
```
## 请求节点
以下节点中,凡是允许填写多个值的,均为以`,`分割的。
:::tip
因 URL 长度限制,批量处理时最好分批请求。
:::
### getAlbumList2 获取专辑列表
请求地址:`http://your-server/rest/getAlbumList2`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| type | Y | | 排序方式,可选值: `random`, `newest`, `frequent`, `recent`, `starred`, `alphabeticalByName`, `alphabeticalByArtist`. 特殊值: `byYear`, `byGenre` |
| size | N | 10 | 返回结果数量,最大值 500 |
| offset | N | 0 | 偏移数量,用于分页获取数据 |
| fromYear | Y(type = byYear) | | 年代最小值,若 最小值大于最大值,将倒序返回结果 |
| toYear | Y(type = byYear) | | 年代最大值 |
| genre | Y(type = byGenre) | | 流派 |
| musicFolderId | N | | |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0">
<albumList2>
<album id="1768" name="Duets" coverArt="al-1768" songCount="2" created="2002-11-09T15:44:40" duration="514" artist="Nik Kershaw" artistId="829"/>
<album id="2277" name="Hot" coverArt="al-2277" songCount="4" created="2004-11-28T00:06:52" duration="1110" artist="Melanie B" artistId="1242"/>
<album id="4201" name="Bande A Part" coverArt="al-4201" songCount="14" created="2007-10-29T19:25:05" duration="3061" artist="Nouvelle Vague" artistId="2060"/>
<album id="2910" name="Soundtrack From Twin Peaks" coverArt="al-2910" songCount="6" created="2002-11-17T09:58:42" duration="1802" artist="Angelo Badalamenti" artistId="1515"/>
<album id="3109" name="Wild One" coverArt="al-3109" songCount="38" created="2001-04-17T00:20:08" duration="9282" artist="Thin Lizzy" artistId="661"/>
<album id="1151" name="Perleporten" coverArt="al-1151" songCount="2" created="2002-11-16T22:24:22" duration="494" artist="Magnus Grønneberg" artistId="747"/>
<album id="2204" name="Wholesale Meats And Fish" coverArt="al-2204" songCount="24" created="2004-11-27T23:44:31" duration="5362" artist="Letters To Cleo" artistId="1216"/>
<album id="114" name="Sounds of the Seventies: AM Nuggets" coverArt="al-114" songCount="2" created="2004-03-09T07:32:46" duration="420" artist="Rubettes" artistId="97"/>
<album id="279" name="Waiting for the Day" coverArt="al-279" songCount="2" created="2004-11-27T17:49:19" duration="448" artist="Bachelor Girl" artistId="231"/>
<album id="4414" name="For Sale" songCount="14" created="2007-10-30T00:11:58" duration="2046" artist="The Beatles" artistId="509"/>
</albumList2>
</subsonic-response>
```
### getAlbum 获取专辑信息及音轨列表
请求地址:`http://your-server/rest/getAlbum`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 专辑id |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0">
<album id="11053" name="High Voltage" coverArt="al-11053" songCount="8" created="2004-11-27T20:23:32" duration="2414" artist="AC/DC" artistId="5432">
<song id="71463" parent="71381" title="The Jack" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-08T23:36:11" duration="352" bitRate="128" size="5624132" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - The Jack.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71464" parent="71381" title="Tnt" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-08T23:36:11" duration="215" bitRate="128" size="3433798" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - TNT.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71458" parent="71381" title="It's A Long Way To The Top" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-27T20:23:32" duration="315" bitRate="128" year="1976" genre="Rock" size="5037357" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - It's a long way to the top if you wanna rock 'n 'roll.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71461" parent="71381" title="Rock 'n' Roll Singer." album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-27T20:23:33" duration="303" bitRate="128" track="2" year="1976" genre="Rock" size="4861680" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - Rock N Roll Singer.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71460" parent="71381" title="Live Wire" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-27T20:23:33" duration="349" bitRate="128" track="4" year="1976" genre="Rock" size="5600206" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - Live Wire.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71456" parent="71381" title="Can I sit next to you girl" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-27T20:23:32" duration="251" bitRate="128" track="6" year="1976" genre="Rock" size="4028276" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - Can I Sit Next To You Girl.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71459" parent="71381" title="Little Lover" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-27T20:23:33" duration="339" bitRate="128" track="7" year="1976" genre="Rock" size="5435119" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - Little Lover.mp3" albumId="11053" artistId="5432" type="music"/>
<song id="71462" parent="71381" title="She's Got Balls" album="High Voltage" artist="AC/DC" isDir="false" coverArt="71381" created="2004-11-27T20:23:34" duration="290" bitRate="128" track="8" year="1976" genre="Rock" size="4651866" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/High voltage/ACDC - Shes Got Balls.mp3" albumId="11053" artistId="5432" type="music"/>
</album>
</subsonic-response>
```
### getArtist 获取歌手信息及专辑列表
请求地址:`http://your-server/rest/getArtist`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌手id |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0">
<artist id="5432" name="AC/DC" coverArt="ar-5432" albumCount="15">
<album id="11047" name="Back In Black" coverArt="al-11047" songCount="10" created="2004-11-08T23:33:11" duration="2534" artist="AC/DC" artistId="5432"/>
<album id="11048" name="Black Ice" coverArt="al-11048" songCount="15" created="2008-10-30T09:20:52" duration="3332" artist="AC/DC" artistId="5432"/>
<album id="11049" name="Blow up your Video" coverArt="al-11049" songCount="10" created="2004-11-27T19:22:45" duration="2578" artist="AC/DC" artistId="5432"/>
<album id="11050" name="Flick Of The Switch" coverArt="al-11050" songCount="10" created="2004-11-27T19:22:51" duration="2222" artist="AC/DC" artistId="5432"/>
<album id="11051" name="Fly On The Wall" coverArt="al-11051" songCount="10" created="2004-11-27T19:22:57" duration="2405" artist="AC/DC" artistId="5432"/>
<album id="11052" name="For Those About To Rock" coverArt="al-11052" songCount="10" created="2004-11-08T23:35:02" duration="2403" artist="AC/DC" artistId="5432"/>
<album id="11053" name="High Voltage" coverArt="al-11053" songCount="8" created="2004-11-27T20:23:32" duration="2414" artist="AC/DC" artistId="5432"/>
<album id="10489" name="Highway To Hell" coverArt="al-10489" songCount="12" created="2009-06-15T09:41:54" duration="2745" artist="AC/DC" artistId="5432"/>
<album id="11054" name="If You Want Blood..." coverArt="al-11054" songCount="1" created="2004-11-27T20:23:32" duration="304" artist="AC/DC" artistId="5432"/>
<album id="11056" name="Let There Be Rock" coverArt="al-11056" songCount="8" created="2004-11-27T20:33:40" duration="2449" artist="AC/DC" artistId="5432"/>
<album id="11057" name="Live - Special Collector's Edition" coverArt="al-11057" songCount="22" created="2004-11-08T23:37:09" duration="6999" artist="AC/DC" artistId="5432"/>
<album id="11058" name="Powerage" coverArt="al-11058" songCount="9" created="2004-11-27T20:33:41" duration="2380" artist="AC/DC" artistId="5432"/>
<album id="11059" name="Stiff Upper Lip" coverArt="al-11059" songCount="11" created="2004-11-08T23:41:13" duration="2595" artist="AC/DC" artistId="5432"/>
<album id="11060" name="The Razors Edge" coverArt="al-11060" songCount="12" created="2004-11-27T20:33:42" duration="2787" artist="AC/DC" artistId="5432"/>
<album id="11061" name="Who Made Who" coverArt="al-11061" songCount="9" created="2004-11-08T23:43:18" duration="2291" artist="AC/DC" artistId="5432"/>
</artist>
</subsonic-response>
```
### getArtistInfo2 获取歌手简介和相似歌手列表
请求地址:`http://your-server/rest/getArtistInfo2`
最低版本1.11.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌手id |
| count | N | | 相似歌手数量 |
| includeNotPresent | N | | 是否返回媒体库不存在的歌手 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.11.0">
<artistInfo2>
<biography>Black Sabbath is an English
<a target='_blank' href="http://www.last.fm/tag/heavy metal" class="bbcode_tag" rel="tag">heavy metal</a> band that formed in 1968 in Birmingham, West Midlands, England, United Kingdom, originally comprising
<a target='_blank' href="http://www.last.fm/music/Ozzy+Osbourne" class="bbcode_artist">Ozzy Osbourne</a> (vocals),
<a target='_blank' href="http://www.last.fm/music/Tony+Iommi" class="bbcode_artist">Tony Iommi</a> (guitar),
<a target='_blank' href="http://www.last.fm/music/Geezer+Butler" class="bbcode_artist">Geezer Butler</a> (bass), and
<a target='_blank' href="http://www.last.fm/music/Bill+Ward" class="bbcode_artist">Bill Ward</a> (drums). In the early
<a target='_blank' href="http://www.last.fm/tag/70s" class="bbcode_tag" rel="tag">70s</a>, they were the first to pair heavily distorted, sonically dissonant
<a target='_blank' href="http://www.last.fm/tag/blues rock" class="bbcode_tag" rel="tag">blues rock</a> at slow speeds with lyrics about drugs, mental pain and abominations of war, thus giving birth to generations of metal bands that followed in their wake.
<a target='_blank' href="http://www.last.fm/music/Black+Sabbath">Read more about Black Sabbath on Last.fm</a>.
</biography>
<musicBrainzId>5182c1d9-c7d2-4dad-afa0-ccfeada921a8</musicBrainzId>
<lastFmUrl>http://www.last.fm/music/Black+Sabbath</lastFmUrl>
<smallImageUrl>http://userserve-ak.last.fm/serve/64/27904353.jpg</smallImageUrl>
<mediumImageUrl>http://userserve-ak.last.fm/serve/126/27904353.jpg</mediumImageUrl>
<largeImageUrl>http://userserve-ak.last.fm/serve/_/27904353/Black+Sabbath+sabbath+1970.jpg</largeImageUrl>
<similarArtist id="279" name="AC/DC" coverArt="ar-279" albumCount="15"/>
<similarArtist id="278" name="Accept" coverArt="ar-278" albumCount="1"/>
<similarArtist id="433" name="Kiss" coverArt="ar-433" albumCount="1"/>
<similarArtist id="372" name="Bruce Dickinson" coverArt="ar-372" albumCount="2"/>
<similarArtist id="290" name="Alice in Chains" coverArt="ar-290" albumCount="3"/>
<similarArtist id="285" name="Aerosmith" coverArt="ar-285" albumCount="2"/>
<similarArtist id="396" name="The Doors" albumCount="1"/>
<similarArtist id="397" name="Guns N' Roses" albumCount="1"/>
</artistInfo2>
</subsonic-response>
```
### getIndexes 获取歌手列表
请求地址:`http://your-server/rest/getIndexes`
最低版本1.0.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| musicFolderId | N | | |
| ifModifiedSince | N | | 返回给定时间之后发生修改的歌手列表单位毫秒自1970.1.1之后的差值 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.10.1">
<indexes lastModified="237462836472342" ignoredArticles="The El La Los Las Le Les">
<shortcut id="11" name="Audio books"/>
<shortcut id="10" name="Podcasts"/>
<index name="A">
<artist id="1" name="ABBA"/>
<artist id="2" name="Alanis Morisette"/>
<artist id="3" name="Alphaville" starred="2013-11-02T12:30:00"/>
</index>
<index name="B">
<artist name="Bob Dylan" id="4"/>
</index>
<child id="111" parent="11" title="Dancing Queen" isDir="false" album="Arrival" artist="ABBA" track="7" year="1978" genre="Pop" coverArt="24" size="8421341" contentType="audio/mpeg" suffix="mp3" duration="146" bitRate="128" path="ABBA/Arrival/Dancing Queen.mp3"/>
<child id="112" parent="11" title="Money, Money, Money" isDir="false" album="Arrival" artist="ABBA" track="7" year="1978" genre="Pop" coverArt="25" size="4910028" contentType="audio/flac" suffix="flac" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" duration="208" bitRate="128" path="ABBA/Arrival/Money, Money, Money.mp3"/>
</indexes>
</subsonic-response>
```
### getCoverArt 封面图片
请求地址:`http://your-server/rest/getCoverArt`
最低版本1.0.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌曲/专辑/歌手id其中专辑id应添加前缀 `al-`歌手id应添加前缀 `ar-` |
| size | N | | 图片大小,示例:`600` |
### createPlaylist 创建或更新歌单名
请求地址:`http://your-server/rest/createPlaylist`
最低版本1.2.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| playlistId | Y更新时填写 | | 歌单id |
| name | Y创建时填写 | | 歌单名 |
早期版本返回空的 `<subsonic-response> `, 自 1.14.0 之后会返回创建/更新后的歌单。
### deletePlaylist 删除歌单
请求地址:`http://your-server/rest/createPlaylist`
最低版本1.2.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌单id |
### ping 测试服务连通性或登录
请求地址:`http://your-server/rest/ping`
最低版本1.0.0
### getGenres 获取全部类型
请求地址:`http://your-server/rest/getGenres`
最低版本1.9.0
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.10.2">
<genres>
<genre songCount="28" albumCount="6">Electronic</genre>
<genre songCount="6" albumCount="2">Hard Rock</genre>
<genre songCount="8" albumCount="2">R&B</genre>
<genre songCount="22" albumCount="2">Blues</genre>
<genre songCount="2" albumCount="2">Podcast</genre>
<genre songCount="11" albumCount="1">Brit Pop</genre>
<genre songCount="14" albumCount="1">Live</genre>
</genres>
</subsonic-response>
```
### getLyrics 获取歌词
请求地址:`http://your-server/rest/getLyrics`
最低版本1.2.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| artist | N | | 歌手名 |
| title | N | | 歌曲名 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.2.0">
<lyrics artist="Muse" title="Hysteria"> It's bugging me Grating me And twisting me around Yeah I'm endlessly Caving in And turning inside out Cause I want it now I want it now Give me your heart and your soul And I'm breaking out I'm breaking out That's when she'll lose control It's holding me Morphing me And forcing me to strive To be endlessly Cold within And dreaming I'm alive Cause I want it now I want it now Give me your heart and your soul I'm not breaking down I'm breaking out That's when she'll lose control And I want you now I want you now I'll feel my heart implode And I'm breaking out Escaping now Feeling my faith erode </lyrics>
</subsonic-response>
```
### getPlaylists 获取歌单列表
请求地址:`http://your-server/rest/getPlaylists`
最低版本1.0.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| username | N | | 获取某个用户名下的歌单列表,使用此参数的用户必须有管理员权限 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.11.0">
<playlists>
<playlist id="15" name="Some random songs" comment="Just something I tossed together" owner="admin" public="false" songCount="6" duration="1391" created="2012-04-17T19:53:44" coverArt="pl-15">
<allowedUser>sindre</allowedUser>
<allowedUser>john</allowedUser>
</playlist>
<playlist id="16" name="More random songs" comment="No comment" owner="admin" public="true" songCount="5" duration="1018" created="2012-04-17T19:55:49" coverArt="pl-16"/>
</playlists>
</subsonic-response>
```
### setRating 评分
请求地址:`http://your-server/rest/setRating`
最低版本1.6.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌曲/专辑/歌手id |
| rating | Y | | 分数范围0-5 |
### getScanStatus 获取扫描状态
请求地址:`http://your-server/rest/getScanStatus`
最低版本1.15.0
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.15.0">
<scanStatus scanning="true" count="5422"/>
</subsonic-response>
```
### scrobble 滚动播放记录
请求地址:`http://your-server/rest/scrobble`
最低版本1.5.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌曲id |
| time | N | | 播放时间自1970以来的毫秒数 |
| submission | N | True | 是否提交,不提交则表示正在播放 |
### search2 搜索歌曲/专辑/歌手
请求地址:`http://your-server/rest/search2`
最低版本1.4.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| query | Y | | 关键词,传 `""` 时可用于获取全部数据 |
| artistCount | N | 20 | 返回的最大歌手数量 |
| artistOffset | N | 0 | 歌手列表偏移量 |
| albumCount | N | 20 | 返回的最大专辑数量 |
| albumOffset | N | 0 | 专辑列表偏移量 |
| songCount | N | 20 | 返回的最大歌曲数量 |
| songOffset | N | 0 | 歌曲列表偏移量 |
| musicFolderId | N | | |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.10.1">
<searchResult2>
<artist id="1" name="ABBA" starred="2012-04-05T18:40:08"/>
<album id="11" parent="1" title="Arrival" artist="ABBA" isDir="true" coverArt="22"/>
<album id="12" parent="1" title="Super Trouper" artist="ABBA" isDir="true" coverArt="23"/>
<song id="112" parent="11" title="Money, Money, Money" isDir="false" album="Arrival" artist="ABBA" track="7" year="1978" genre="Pop" coverArt="25" size="4910028" contentType="audio/flac" suffix="flac" transcodedContentType="audio/mpeg" transcodedSuffix="mp3" path="ABBA/Arrival/Money, Money, Money.mp3"/>
</searchResult2>
</subsonic-response>
```
### getSongsByGenre 获取某个类型的歌曲列表
请求地址:`http://your-server/rest/getSongsByGenre`
最低版本1.9.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| genre | Y | | 类型名 |
| count | N | 10 | 返回的歌曲数量,最大 500 |
| offset | N | 0 | 起始行数,用于分页 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.9.0">
<songsByGenre>
<song id="16" parent="15" title="Atrapado" album="Antígona" artist="Antígona" isDir="false" coverArt="15" created="2012-12-26T17:05:54" duration="261" bitRate="128" track="1" year="2008" genre="Metal" size="4188288" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Antigona/Antigona/01 - Atrapado.mp3" albumId="2" artistId="2" type="music"/>
<song id="17" parent="15" title="Gritar al cielo" album="Antígona" artist="Antígona" isDir="false" coverArt="15" created="2012-12-26T17:05:44" duration="233" bitRate="128" track="2" year="2008" genre="Metal" size="3737728" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Antigona/Antigona/02 - Gritar al cielo.mp3" albumId="2" artistId="2" type="music"/>
<song id="18" parent="15" title="En sus garras" album="Antígona" artist="Antígona" isDir="false" coverArt="15" created="2012-12-26T17:05:22" duration="239" bitRate="128" track="3" year="2008" genre="Metal" size="3846272" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Antigona/Antigona/03 - En sus garras.mp3" albumId="2" artistId="2" type="music"/>
<song id="19" parent="15" title="Nuevos Horizontes" album="Antígona" artist="Antígona" isDir="false" coverArt="15" created="2012-12-26T17:05:35" duration="310" bitRate="128" track="4" year="2008" genre="Metal" size="4980864" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Antigona/Antigona/04 - Nuevos Horizontes.mp3" albumId="2" artistId="2" type="music"/>
</songsByGenre>
</subsonic-response>
```
### getSimilarSongs 获取相似歌曲
请求地址:`http://your-server/rest/getSimilarSongs`
最低版本1.11.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌手/专辑/歌曲id |
| count | N | 50 | 返回的歌曲数量 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.11.0">
<similarSongs>
<song id="1631" parent="1628" isDir="false" title="A Whiter Shade Of Pale" album="Medusa" artist="Annie Lennox" track="3" coverArt="1628" size="5068173" contentType="audio/mpeg" suffix="mp3" duration="316" bitRate="128" path="Annie Lennox/Medusa/03 - A Whiter Shade Of Pale.MP3" isVideo="false" created="2004-11-08T22:21:17.000Z" albumId="471" artistId="305" type="music"/>
<song id="4654" parent="4643" isDir="false" title="somebodys somebody" album="christina aguilera" artist="christina aguilera" track="8" year="1999" genre="Pop" coverArt="4643" size="6039760" contentType="audio/mpeg" suffix="mp3" duration="302" bitRate="160" path="Christina Aguilera/Album/08-cps-christina_aguilera--somebodys_somebody.mp3" isVideo="false" created="2004-11-25T22:18:53.000Z" albumId="698" type="music"/>
<song id="2592" parent="2590" isDir="false" title="Higher Ground" album="Higher Ground" artist="Barbra Streisand" track="2" genre="Pop Vocals" coverArt="2590" size="5271680" contentType="audio/mpeg" suffix="mp3" duration="263" bitRate="160" path="Barbra Streisand/Higher Ground/02 - Higher Ground.mp3" isVideo="false" created="2002-11-09T14:36:28.000Z" albumId="524" artistId="328" type="music"/>
<song id="1435" parent="1412" isDir="false" title="I dreamed you" album="Freak Of Nature" artist="Anastacia" track="11" year="2001" genre="Pop" coverArt="1412" size="4879261" contentType="audio/mpeg" suffix="mp3" duration="305" bitRate="128" path="Anastacia/Freak Of Nature/Anastacia - Freak Of Nature - 11 - I dreamed you .mp3" isVideo="false" created="2004-11-27T19:43:58.000Z" albumId="453" artistId="152" type="music"/>
<song id="4664" parent="4644" isDir="false" title="The Christmas Song" album="My Kind Of Christmas" artist="Christina Aguilera" track="9" genre="Pop" coverArt="4644" size="4239446" contentType="audio/mpeg" suffix="mp3" duration="265" bitRate="128" path="Christina Aguilera/My Kind Of Christmas/09 - The Christmas Song.mp3" isVideo="false" created="2003-07-20T13:00:48.000Z" albumId="700" artistId="102" type="music"/>
<song id="4118" parent="4111" isDir="false" title="The Hook Up" album="In The Zone" artist="Britney Spears" track="9" year="2003" genre="Pop" coverArt="4111" size="5623047" contentType="audio/mpeg" suffix="mp3" duration="234" bitRate="192" path="Britney Spears/In the Zone/09 - The Hook Up.mp3" isVideo="false" created="2004-11-27T20:27:16.000Z" albumId="653" artistId="79" type="music"/>
<song id="1637" parent="1628" isDir="false" title="Waiting In Vain" album="Medusa" artist="Annie Lennox" track="9" coverArt="1628" size="5453102" contentType="audio/mpeg" suffix="mp3" duration="340" bitRate="128" path="Annie Lennox/Medusa/09 - Waiting In Vain.MP3" isVideo="false" created="2004-11-08T22:21:32.000Z" albumId="471" artistId="305" type="music"/>
<song id="4520" parent="4519" isDir="false" title="Save Up All Your Tears" album="Love Hurts" artist="Cher" track="1" year="1991" genre="Pop" coverArt="4519" size="3831936" contentType="audio/mpeg" suffix="mp3" duration="239" bitRate="128" path="Cher/Love Hurts/01-Save Up All Your Tears.mp3" isVideo="false" created="2004-11-14T12:35:07.000Z" albumId="689" artistId="67" type="music"/>
<song id="4684" parent="4646" isDir="false" title="Make Over" album="Stripped" artist="Christina Aguilera" track="12" year="2002" genre="Rock" coverArt="4646" size="6065009" contentType="audio/mpeg" suffix="mp3" duration="253" bitRate="192" path="Christina Aguilera/Stripped/(12) Christina Aguilera - Make Over.mp3" isVideo="false" created="2004-11-25T22:18:56.000Z" albumId="277" artistId="102" type="music"/>
<song id="1629" parent="1628" isDir="false" title="No More I Love You's" album="Medusa" artist="Annie Lennox" track="1" coverArt="1628" size="4686874" contentType="audio/mpeg" suffix="mp3" duration="292" bitRate="128" path="Annie Lennox/Medusa/01 - No More I Love You's.MP3" isVideo="false" created="2004-11-08T22:21:29.000Z" albumId="471" artistId="305" type="music"/>
</similarSongs>
</subsonic-response>
```
### getRandomSongs 随机获取歌曲
请求地址:`http://your-server/rest/getRandomSongs`
最低版本1.2.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| size | N | 10 | 结果数量最大500条 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.16.1" type="navidrome" serverVersion="0.52.0 (92a98cd5)" openSubsonic="true">
<randomSongs>
<song id="072f97e35d3c7a361daec0264d8941b3" parent="cf859b29e87f5e9e25ef0cf78ca22b84" isDir="false" title="独上西楼" album="邓丽君 Vol.2" artist="邓丽君" track="3" year="2007" coverArt="mf-072f97e35d3c7a361daec0264d8941b3_65fc18d7" size="16584611" contentType="audio/flac" suffix="flac" duration="163" bitRate="809" path="邓丽君/邓丽君 Vol.2/03 - 独上西楼.flac" created="2024-04-30T10:25:33.16687882Z" albumId="cf859b29e87f5e9e25ef0cf78ca22b84" artistId="8fccbf2dbaf0d3b8a486f385cce4f803" type="music" isVideo="false" bpm="0" comment="" sortName="" mediaType="song" musicBrainzId="" channelCount="2">
<replayGain trackPeak="1" albumPeak="1"></replayGain>
</song>
<song id="de28115e41db88f25e3d02e6e5021d45" parent="661b3dda98a12c146da788d3bd204c8f" isDir="false" title="Dancing in the Rain" album="我们在中场相遇" artist="莫文蔚" track="7" year="2018" coverArt="mf-de28115e41db88f25e3d02e6e5021d45_65fc36a5" size="59678579" contentType="audio/flac" suffix="flac" duration="260" bitRate="1818" path="莫文蔚/我们在中场相遇/07 - Dancing in the Rain.flac" created="2024-04-30T10:17:01.624046459Z" albumId="661b3dda98a12c146da788d3bd204c8f" artistId="47418e7b558c66b3114fb8c9571cff24" type="music" isVideo="false" bpm="0" comment="" sortName="" mediaType="song" musicBrainzId="" channelCount="2">
<replayGain trackGain="-9.18" albumGain="-8.72" trackPeak="0.964932" albumPeak="0.999969"></replayGain>
</song>
</randomSongs>
</subsonic-response>
```
### getStarred 获取收藏歌曲/专辑/歌手
请求地址:`http://your-server/rest/getStarred`
最低版本1.8.0
### getSong 获取歌曲信息
请求地址:`http://your-server/rest/getSong`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌曲id |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.8.0">
<song id="48228" parent="48203" title="You Shook Me All Night Long" album="Back In Black" artist="AC/DC" isDir="false" coverArt="48203" created="2004-11-08T23:33:11" duration="210" bitRate="112" size="2945619" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="ACDC/Back in black/ACDC - You Shook Me All Night Long.mp3"/>
</subsonic-response>
```
### getTopSongs 获取歌手的热门歌曲
请求地址:`http://your-server/rest/getTopSongs`
最低版本1.13.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| artist | Y | | 歌手名 |
| count | N | 50 | 返回的歌曲数量 |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.13.0">
<topSongs>
<song id="1013" parent="1008" isDir="false" title="London Leatherboys" album="Balls To The Wall" artist="Accept" track="2" year="1984" genre="Metal" coverArt="1008" size="5706432" contentType="audio/mpeg" suffix="mp3" duration="237" bitRate="192" path="Accept/Balls To The Wall/Accept - London Leatherboys - 02.mp3" isVideo="false" created="2004-11-27T17:22:37.000Z" albumId="411" artistId="278" type="music"/>
<song id="1012" parent="1008" isDir="false" title="Head Over Heels" album="Balls To The Wall" artist="Accept" track="4" year="1984" genre="Metal" coverArt="1008" size="6219527" contentType="audio/mpeg" suffix="mp3" duration="259" bitRate="192" path="Accept/Balls To The Wall/Accept - Head Over Heels - 04.mp3" isVideo="false" created="2004-11-27T17:22:35.000Z" starred="2015-01-03T21:12:10.070Z" albumId="411" artistId="278" type="music"/>
<song id="1016" parent="1008" isDir="false" title="Love Child" album="Balls To The Wall" artist="Accept" track="6" year="1984" genre="Metal" coverArt="1008" size="5156143" contentType="audio/mpeg" suffix="mp3" duration="214" bitRate="192" path="Accept/Balls To The Wall/Accept - Love Child - 06.mp3" isVideo="false" created="2004-11-27T17:22:42.000Z" starred="2014-12-30T15:05:03.815Z" albumId="411" artistId="278" type="music"/>
</topSongs>
</subsonic-response>
```
### getPlaylist 获取歌单中的歌曲
请求地址:`http://your-server/rest/getPlaylist`
最低版本1.0.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌单id |
示例:
```xml
<subsonic-response
xmlns="http://subsonic.org/restapi" status="ok" version="1.11.0">
<script/>
<playlist id="15" name="kokos" comment="fan" owner="admin" public="true" songCount="6" duration="1391" created="2012-04-17T19:53:44" coverArt="pl-15">
<allowedUser>sindre</allowedUser>
<allowedUser>john</allowedUser>
<entry id="657" parent="655" title="Making Me Nervous" album="I Don't Know What I'm Doing" artist="Brad Sucks" isDir="false" coverArt="655" created="2008-04-10T07:10:32" duration="159" bitRate="202" track="1" year="2003" size="4060113" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Brad Sucks/I Don't Know What I'm Doing/01 - Making Me Nervous.mp3" albumId="58" artistId="45" type="music"/>
<entry id="823" parent="784" title="Piano escena" album="BSO Sebastian" artist="PeerGynt Lobogris" isDir="false" coverArt="784" created="2009-01-14T22:26:29" duration="129" bitRate="170" track="8" year="2008" genre="Blues" size="2799954" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="PeerGynt Lobogris/BSO Sebastian/08 - Piano escena.mp3" albumId="75" artistId="54" type="music"/>
<entry id="748" parent="746" title="Stories from Emona II" album="Between two worlds" artist="Maya Filipič" isDir="false" coverArt="746" created="2008-07-30T22:05:40" duration="335" bitRate="176" track="2" year="2008" genre="Classical" size="7458214" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Maya Filipic/Between two worlds/02 - Stories from Emona II.mp3" albumId="68" artistId="51" type="music"/>
<entry id="848" parent="827" title="Run enemy" album="Eve" artist="Shearer" isDir="false" coverArt="827" created="2009-01-15T22:54:38" duration="331" bitRate="195" track="14" year="2008" genre="Rock" size="8160185" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Shearer/Eve/14 - Run enemy.mp3" albumId="77" artistId="55" type="music"/>
<entry id="884" parent="874" title="Isolation" album="Kosmonaut" artist="Ugress" isDir="false" coverArt="874" created="2009-01-14T21:34:49" duration="320" bitRate="160" track="4" year="2006" genre="Electronic" size="6412176" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="Ugress/Kosmonaut/Ugress-KosmonautEP-04-Isolation.mp3" albumId="81" artistId="57" type="music"/>
<entry id="805" parent="783" title="Bajo siete lunas (intro)" album="Broken Dreams" artist="PeerGynt Lobogris" isDir="false" coverArt="783" created="2008-12-19T14:13:58" duration="117" bitRate="225" track="1" year="2008" genre="Blues" size="3363271" suffix="mp3" contentType="audio/mpeg" isVideo="false" path="PeerGynt Lobogris/Broken Dreams/01 - Bajo siete lunas (intro).mp3" albumId="74" artistId="54" type="music"/>
</playlist>
</subsonic-response>
```
### star 收藏歌曲/专辑/歌手
请求地址:`http://your-server/rest/star`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | N | | 歌曲/专辑/歌手id允许填写多个值 |
| albumId | N | | 专辑id允许填写多个值 |
| artistId | N | | 歌手id允许填写多个值 |
### stream 歌曲播放链接
请求地址:`http://your-server/rest/stream`
最低版本1.0.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | Y | | 歌曲id |
| maxBitRate | N | | 比特率设为0则不转码 |
| format | N | | 文件格式,特殊值 `raw` 以禁用转码 |
| estimateContentLength | N | false | 将 content-length 设为转码后的估计值 |
### unstar 取消收藏
请求地址:`http://your-server/rest/unstar`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| id | N | | 歌曲/专辑/歌手id允许填写多个值 |
| albumId | N | | 专辑id允许填写多个值 |
| artistId | N | | 歌手id允许填写多个值 |
### updatePlaylist 更新歌单
请求地址:`http://your-server/rest/updatePlaylist`
最低版本1.8.0
| 参数名 | 是否必填 | 默认值 | 备注 |
| --- | --- | --- | --- |
| playlistId | Y | | 歌单id |
| name | N | | 歌单名 |
| comment | N | | 评论 |
| public | N | | 是否对所有用户可见 |
| songIdToAdd | N | | 待添加的歌曲id允许填写多个值 |
| songIndexToRemove | N | | 待删除的歌曲id允许填写多个值 |

View File

@@ -0,0 +1,41 @@
---
sidebar_position: 8
---
# Roadmap {#roadmap}
## In Progress {#working}
- Server-side DLNA
## Android Store Listing {#android-distribution}
| Preparation | Progress |
| --- | --- |
| Company Registration | Completed: Changsha Liuyin Technology Co., Ltd. |
| Pending... | |
## Car & TV Editions {#more-platform}
No standalone car edition planned. The current version supports phone/tablet interfaces and should work on car infotainment systems if installable.
If your car system supports navigation via **directional keys + OK key + back key** with a landscape screen, try switching to **TV mode** on the login page.
Apple TV Edition may begin adaptation in v1.4.0 after feasibility research, but **no guarantee of release**.
## HarmonyOS Next (Native) Adaptation {#ohos}
Stream Music is built with Flutter (a Google product), making **official Flutter support for HarmonyOS highly unlikely**.
~~Personal bandwidth limitations prevent dedicated HarmonyOS adaptation.~~
:::info
OpenHarmony is reportedly working on Flutter compatibility, leaving future HarmonyOS support possible.
:::
## New Music Services {#protocols}
- **QNAP Music Station** support planned.
- **WebDAV**, cloud storage, and local music support are **not currently planned** (long-term roadmap items).

View File

@@ -0,0 +1,126 @@
---
sidebar_position: 7
---
# Issues {#issues}
If you encounter any issues or have suggestions while using the software, please visit the [GitHub repository](https://github.com/gitbobobo/StreamMusic):
1. Go to the **Issues** tab and search for existing reports.
2. If no similar issue exists, create a new one and **provide detailed information**, such as OS version, server version, Stream Music version, logs, screenshots, etc. **The more details you provide, the easier it is to reproduce and resolve the issue.**
:::note Viewing Logs
On the About page, tap the version number repeatedly to enable Developer Mode.
:::
## Music Services {#services}
### Unable to Log In {#login}
Possible causes:
- Incorrect username/password.
- Invalid server address (must include protocol, IP, and port).
- Self-signed or incomplete SSL certificate chain.
- Proxy software intercepting `127.0.0.1`.
### Navidrome Fails to Scan Beyond 50,000 Songs {#navidrome-scan}
In Navidrome versions ≤0.52, theres a known bug in the song query logic. Upgrade to the latest version.
If upgrading is not possible, set the Docker environment variable `ND_DEVOFFSETOPTIMIZE` to a value greater than your total song count.
:::info
Related issue: [The retrieval of data fails when sorting by createAt after the number of songs exceeds 50,000.](https://github.com/navidrome/navidrome/issues/3006)
:::
### Fuzzy Search Not Working {#search}
- **Direct Connection Mode**: Fuzzy search depends on server support. For Navidrome, enable the `SearchFullString` environment variable.
- **Library Mode**: Fuzzy search is client-side. Report any failures promptly.
## Playback {#playback}
### Android Background Playback Pauses (No Sound) {#background}
1. **Stream Music****Help** → Disable battery optimization.
2. **System Settings****Stream Music** → Network & Data → Allow background data usage.
*Steps may vary by device. For Huawei: Battery → More Settings → Keep Network Connected During Sleep.*
### Playback Duration Keeps Updating {#transcoding}
This occurs when the server is transcoding the track. The displayed duration reflects the buffered content. Wait for transcoding to complete.
### Mobile Data Playback Fails {#ffmpeg}
- Ensure your server is publicly accessible.
- If transcoding fails (common on mobile data), check if `ffmpeg` is properly configured on the server.
:::info
Recommendation: Use Docker for server deployment to avoid configuration issues.
:::
## Platform-Specific {#platform}
### Android Notification Controls Fail {#notification}
This is likely an OS bug. Disable battery optimization for Stream Music in system settings.
:::info
Related issue: [Android notification controls stop working](https://github.com/gitbobobo/StreamMusic/issues/145).
Post v1.2.8, the Help page detects battery optimization status and redirects to settings.
:::
### Android Car Bluetooth Metadata Not Updating {#bluetooth}
Occurs after screen lock. Track progress: [Android MediaItem not updating via Bluetooth](https://github.com/ryanheise/audio_service/issues/908).
### Bitwarden Clicks Blocked by Floating Lyrics (Android) {#overlay}
Locked lyrics overlay may interfere. Unlock/disable lyrics temporarily via the notification panel.
### High CPU Usage/Overheating {#cpu}
Caused by Flutter animations. Enable **Power Saving Mode** in theme settings (default: ON).
:::info
Related issue: [High CPU usage and overheating](https://github.com/gitbobobo/StreamMusic/issues/60).
:::
### CarPlay/Notification Controls Fail to Skip Tracks {#carplay-notification}
Disable **"Allow Concurrent Playback"** in settings. This is an iOS limitation.
## Membership {#vip}
### Invalid Signature When Restoring Purchase {#signature}
Likely caused by incorrect device time. Sync your device clock.
### Invalid Email Format {#email}
Type the email manually. Avoid pasting extra spaces or line breaks.
### Device Limit {#device-limit}
Exceeding 7 devices automatically logs out the oldest one. No manual management needed.
## other {#other}
### Security Concerns {#security}
Some users worry about credential leaks. Clarifications:
- NAS music is niche; data volume is too small for commercial exploitation.
- Tech-savvy NAS users would detect malicious code, risking developer reputation.
Still concerned? Use a dedicated music-only account. If server IP exposure worries you, choose trusted software instead.

View File

@@ -0,0 +1,41 @@
---
sidebar_position: 2
---
# Services {#services}
From my personal experience, there is currently no perfect music service - each has its own pros and cons. You should choose based on your specific needs.
## Supported Versions {#versions}
- Navidrome 0.49.3 and above
- Plex 1.29.2 and above (supports OTP verification code login, shared music libraries not currently supported)
- AudioStation DSM 6 and above (supports OTP verification code login)
- Emby 4.7.14.0 and above
- Jellyfin 10.8.10 and above
- Subsonic 1.15.0 and above
## Feature Comparison {#comparison}
`-` Unknown
| Feature | Subsonic | Navidrome | Audio Station | Emby | Jellyfin | Plex |
| ------- | ------- | ------- | --- | --- | --- | --- |
| Embedded Lyrics<sup>1</sup> | - | ✅ | | ✅ | ✅ | |
| External Lyrics | - | | ✅ | ✅ | ✅ | ✅ |
| Online Lyrics | - | | ✅ | ✅ | ✅ | ✅ |
| Artist Bio | - | ✅ | | ✅ | ✅ | ✅ |
| Artist Image | - | *<sup>2</sup> | *<sup>3</sup> | ✅ | ✅ | ✅ |
| Multiple Artists | - | | - | ✅ | ✅ | |
| Replay Gain | - | ✅ | ✅ | | | ✅ |
| Rating<sup>4</sup> | ✅ | ✅ | ✅ | | | ✅ |
| Favorites<sup>5</sup> | ✅ | ✅ | | ✅ | ✅ | |
| Folder View | - | | ✅ | ✅ | | ✅ |
| Delete API | - | | | ✅ | ✅ | ✅ |
1. Since v1.2.8, Stream Music can read embedded lyrics when "Cache While Playing" is enabled.
2. For Navidrome artist images: Requires Spotify API configuration (may not work effectively in Chinese environments) or placing an image named `artist.*` in the artist folder. [Artwork location resolution](https://www.navidrome.org/docs/usage/artwork/#artists)
3. Audio Station uses album artwork from music library for artist images.
4. Audio Station only supports song ratings.
5. Audio Station and Plex lack favorites feature. Stream Music treats songs rated 🌟🌟🌟🌟🌟 as favorites.

View File

@@ -0,0 +1,25 @@
---
sidebar_position: 2
---
# Detection and Deletion of Duplicate Songs {#detect}
As your music library grows, duplicate tracks inevitably appear, which can be frustrating for perfectionists who struggle to decide which version to keep.
After connecting via **[Library Mode](../guides/sync_mode#library-mode)** and fully syncing server data, a **Duplicate Song Detection** entry will appear on the artist details page if duplicates exist.
This feature allows you to view and compare duplicate versions of a song, then delete unwanted copies based on provided metadata.
:::info Developers Note
Library Mode may perform poorly with large libraries. Use it only when necessary; stick to **Direct Mode** for daily use.
:::
What if the [connected server lacks file deletion support](../services#comparison)?
**Solution 1**: If Stream Music retrieves the actual file path, copy the deletion command from the page and execute it via SSH in another tool.
*Note: This method involves cross-software/device operations and is not ideal.*
**Solution 2**: Deploy a Docker-based server that supports file deletion. Switch to this server in Stream Music when detecting duplicates, sync data, and perform deletions.
*(See [Focused Audio Management](./focus_specific_audio) for similar workflows.)*

View File

@@ -0,0 +1,13 @@
---
sidebar_position: 1
---
# Focus on a Specific Type of Audio {#focus}
In addition to storing music, we may also add audiobooks and other audio types to our library.
While this can expand the use of Yinliu, it also introduces a new issue—we may not want to see these special types of audio in places like daily recommendations or smart playlists, as they can interrupt our current music listening experience.
To solve this problem, we can either choose to set up a server that supports media library partitions, such as Emby and Jellyfin, or use Docker to set up another server specifically for storing these special types of audio.
By isolating these special audio files in different libraries or partitions, we can take advantage of **Yinliu's ability to switch libraries and partitions** to focus on listening to music or audiobooks.

View File

@@ -0,0 +1,33 @@
---
sidebar_position: 4
---
# Track Playback History via Last.FM {#lastfm}
Seeing others share **annual music reports** at year-end while you have none? Don't worry! You can record your listening history through Last.FM and happily share your stats with friends later
![](https://oss.aqzscn.cn/resource/blog/img/2024/8e26c-0835da59547fd34cc652db034d977f09.png)
Since StreamMusic isn't open-source, direct Last.FM integration might pose copyright risks. This guide demonstrates server-side configuration instead.
:::info
I've emailed Last.FM for API access but received no response.
:::
## Create Last.FM Account {#account}
Register at https://www.last.fm/. **QQ email addresses may fail registration**.
## Report Plays via Navidrome {#navidrome}
Enable Last.FM scrobbling in Navidrome's web interface:
![](https://oss.aqzscn.cn/resource/blog/img/2024/b269c-862548c7f7e351f285de76a02c0b8389.png)
## Report Plays via Emby {#emby}
1. Install the Last.fm metadata plugin under "Metadata" in Emby's admin panel.
2. Restart server.
3. Configure via sidebar settings:
![](https://oss.aqzscn.cn/resource/blog/img/2024/58760-e43cba8065b629dfcf3285068d40d7eb.png)

View File

@@ -0,0 +1,34 @@
---
sidebar_position: 3
---
# Play Music via Shortcuts {#shortcuts}
Stream Music supports **iOS Shortcuts** starting from v1.3.4, enabling music playback via Siri or Shortcuts without opening the app.
:::caution
Current limitation: If you enter the app after initiating playback via shortcuts, music may stop due to Flutter engine reinitialization.
:::
Stream Music provides granular shortcut actions for personalized workflows:
1. Search Library
2. Search Library Partition
3. Switch Library
4. Search Artist
5. Search Album
6. Search Track
7. Play Music
8. Stop Playback
9. Get Playback Status
10. Add/Remove Tracks from Playlist
## Examples {#example}
**Play My Favorite Music**
![](https://oss.aqzscn.cn/resource/blog/img/2024/f0825-b5659c5bff07fbad19554d9120cdbd7a.jpg)
**Play Bedtime Stories**
![](https://oss.aqzscn.cn/resource/blog/img/2024/81994-6b0a809dcf8d1dab42b8f2ca55f72d7f.jpg)

View File

@@ -0,0 +1,156 @@
---
sidebar_position: 1
---
# 1.0.x
更新日期2023-06-06 至 2023-07-28
## V1.0.102023-07-28
更新内容:
- 新增歌词偏移功能
- 优化歌曲列表排序功能
- 可自定义控制栏底部间距
- 新增歌曲列表多选功能
- 移动网络下播放歌曲可选择单次允许
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzouq.com/b04q7c5fa) 密码:6heo
## V1.0.92023-07-19
更新内容:
- 可自定义主题色
- 可自定义歌词样式
- 播放记录可同步至服务端
- 新增分页和下拉刷新功能
- 转码音质新增 256kbps
- 歌曲可添加到下一首播放
- 搜索历史可长按删除
- 修复 m4a 格式无法播放的问题
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzouq.com/b04q5qtij) 密码:dxvq
## V1.0.82023-07-03
更新内容:
- 新增兼容模式
- 控制栏可选择毛玻璃效果
- 控制栏歌词提示可使用变量
- 可自定义数据刷新间隔
- 可分别配置移动网络和 Wi-Fi 下的在线音乐音质
- 启动时不再恢复 5000 首以上的播放队列
- 可单独切换下载任务的状态
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzoum.com/b04q3sppc) 密码:h4lu
> 兼容模式现在有两个作用,快速模式下可以保证转码后的歌曲进度条是正常的,强制模式下保证重定向后的歌曲资源能正常播放。
> 开启兼容模式后,默认打开边听边存功能。播放第一首歌时需要等待服务器转码完成,开始播放后,有预加载功能,不频繁切歌就不会有问题。
## V1.0.72023-06-28
更新内容:
- 新增主题切换功能
- 增强手势可双击跳转当前播放列表
- 歌手简介可通过翻译接口翻译
- 歌曲列表可选择排序方式
- 优化启动时恢复播放队列的逻辑
- 新增启动后自动播放的选项
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzoum.com/b04q3567c) 密码:8jcl
## V1.0.62023-06-23
更新内容:
- 定时停止功能可在播放完成后停止播放
- 专辑列表可选择排序方式
- 可查看歌曲文件的详细信息
- 可自定义部分页面显示内容
- 增加检查更新功能
- 修复下载进度显示不正确的问题
- 修复下载的歌曲无法显示的问题
- 优化部分界面细节
安卓体验地址:[蓝奏云](https://wwco.lanzoum.com/b04q2kxxe) 密码:6pfr
## V1.0.52023-06-20
更新内容:
- 下载功能
- 自定义 API 获取歌词
- 增强手势
- 歌手列表 a-z 指示器
- 降低 subsonic API 服务端版本要求至 1.15.0
- 修复歌词界面屏幕常亮不生效问题
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzoum.com/b04q28tsd) 密码:55yw
## V1.0.42023-06-16
更新内容:
- 专辑/歌手列表筛选功能
- 歌词页面常亮
- 处理推荐页面上下滑动重新加载封面的问题
- 修复封面与当前歌曲不对应的问题
- 支持多时间戳歌词
- 支持歌词翻译(【】括住的翻译及相同时间戳的翻译)
- 【安卓】修复播放时闪退问题
安卓体验地址:[蓝奏云](https://wwco.lanzoum.com/b04q1u3je) 密码:5prj
## V1.0.32023-06-11
> 接下来几天有事先更个小版本基本是对安卓的一些问题的修复就不发iOS 版本了。
更新内容:
- 首页可切换全部/我的歌单
- 【安卓】增加锁屏歌词开关
- 【安卓】修复锁屏组件不显示图标的问题
- 【安卓】支持连按两次返回桌面
- 【安卓】处理打开邮件失败的问题
安卓版体验地址:[蓝奏云](https://wwco.lanzoum.com/b04q16a0d) 密码:9wpa
## V1.0.22023-06-10
更新内容:
- 控制栏显示播放进度。
- 定时停止播放、倍速播放。
- 搜索框添加清空按钮。
安卓版体验地址:[https://wwco.lanzoum.com/b04q1214j](https://wwco.lanzoum.com/b04q1214j) 密码:b4co
## V1.0.12023-06-09
更新内容:
- 主机名后的路径将作为请求的一部分。
- 处理登录后无法获取封面/歌曲播放地址的问题。
- 大部分页面已增加点击标题栏返回顶部功能。
- 其他问题优化。
安卓版体验地址:[https://wwco.lanzoum.com/b04q0xu2b](https://wwco.lanzoum.com/b04q0xu2b) 密码:5gm0
**更新说明**
尽量选择卸载重装,也可尝试退出后重新登录。
## V1.0.02023-06-06
公测版本:
- 安卓版体验地址:[https://wwco.lanzoum.com/b04q0p5kb](https://wwco.lanzoum.com/b04q0p5kb) 密码:i1gc

View File

@@ -0,0 +1,248 @@
---
sidebar_position: 2
---
# 1.1.x
更新日期2023-08-13 至 2023-12-05
## V1.1.102023-12-05
:::danger
当前版本已加入付费验证,部分功能受限,仅供尝鲜,在音流正式上架前请谨慎更新此版本。
:::
更新内容:
- 【iOS、macOS】初步优化 navidrome 转码播放的问题
- 支持多语言
- 播放页点击标题、专辑、歌手名可独立跳转
- 修复默认主题滑动卡顿的问题
- Emby、Jellyfin 支持删除文件接口
- 修复Emby非管理员用户登录后无法获取数据的问题
安卓尝鲜地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.10/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.10/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.10/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.10/app-release.apk)
Mac 下载地址:[音流v1.1.10.dmg](https://oss.aqzscn.cn/stream-music/versions/1.1.10/音流v1.1.10.dmg)
## V1.1.92023-11-29
:::danger
当前版本已加入付费验证,部分功能受限,仅供尝鲜,在音流正式上架前请谨慎更新此版本。
:::
更新内容:
- 修复开启循环播放时,单首歌曲导致软件卡死的问题
- 获取封面的接口支持重定向资源
- 修复 AudioStation 含单引号的专辑无法显示歌曲的问题
安卓尝鲜地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.9/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.9/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.9/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.9/app-release.apk)
Mac 下载地址:[音流v1.1.9.dmg](https://oss.aqzscn.cn/stream-music/versions/1.1.9/音流v1.1.9.dmg)
## V1.1.82023-11-27
:::danger
当前版本已加入付费验证,部分功能受限,仅供尝鲜,在音流正式上架前请谨慎更新此版本。
:::
更新内容:
- 单行歌词支持滚动[#57](https://github.com/gitbobobo/StreamMusic/issues/57)、[#61](https://github.com/gitbobobo/StreamMusic/issues/61)
- AudioStation 支持个人文件夹
- AudioStation 支持查看超过 1000 首的歌单
- 暂时移除实验室
- 修复[无法调整缓存限额的问题](https://github.com/gitbobobo/StreamMusic/issues/64)
- 文件夹功能现可识别 windows 的路径分隔符
- 新增[省电模式](https://github.com/gitbobobo/StreamMusic/issues/60)(默认禁用循环动画)
- 优化部分界面显示效果
- 调整歌单数据同步方式
- 修复 [Emby 无法读取年份的问题](https://github.com/gitbobobo/StreamMusic/issues/80)
- 自定义 API 新增[获取封面接口](https://aqzscn.cn/archives/stream-music-custom-api#%E8%8E%B7%E5%8F%96%E5%B0%81%E9%9D%A2)
安卓尝鲜地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.8/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.8/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.8/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.8/app-release.apk)
Mac 尝鲜地址:[音流v1.1.8.dmg](https://oss.aqzscn.cn/stream-music/versions/1.1.8/音流v1.1.8.dmg)
## V1.1.72023-10-11
当前版本是商店预览版,音流正在准备上架 Play Store在上架之前仅会关注用户反馈的问题并不定期更新此版本
10-17 更新内容:
- [更快的备用线路切换速度](https://github.com/gitbobobo/StreamMusic/issues/59)
- 文件夹视图(更新后同步一次数据后生效)
- 修复 AudioStation 部分专辑无法显示歌曲的问题
- 修复 DLNA 后台播放时无法切歌的问题
- 修复误删除缓存歌曲的问题
10-13 更新内容:
- 修复 AudioStation 部分封面获取失败的问题
- 修复切换为备用线路后,下载任务全部失败的问题
- DLNA 播放时遇到非 flac 或 mp3 格式的歌曲将默认转码
10-12 更新内容:
- 修复 AudioStation 登录问题
- 歌词详情可复制歌词内容
- 桌面歌词去掉文字阴影
- 修复 Emby 无法下载的问题
更新内容:
- AudioStation 支持 DSM6
- 【iOS】支持 DLNA 播放
- 优化歌词切换逻辑
- 【macOS】支持状态栏歌词
- 自动下载现在仅会在 Wi-Fi 环境下开始
- 修复自动跳转下一曲的问题
- 修复通知栏组件不更新的问题
- 修复搜索页面播放歌曲导致已下载歌曲找不到的问题
安卓体验地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.7/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.7/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.7/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.7/app-release.apk)
Mac 体验地址:[stream_music_mac.zip](https://oss.aqzscn.cn/stream-music/versions/1.1.7/stream_music_mac.zip)
## V1.1.62023-10-07
更新内容:
- 支持通过地址连接 AudioStation
- 支持 AudioStation 的 OTP 验证登录
- 兼容含`[]``<>`时间戳的歌词
- 支持搜索歌词(含 AudioStation 和自定义歌词 API
- 【安卓】支持 DLNA 播放
- [初步适配 MacOS](https://github.com/gitbobobo/StreamMusic/issues/48)
- 离线模式逻辑优化
- 修复在不同网络环境下会缓存两份歌曲文件的问题
安卓体验地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.6/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.6/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.6/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.6/app-release.apk)
## V1.1.52023-10-01
更新内容:
- [支持 AudioStation](https://github.com/gitbobobo/StreamMusic/issues/31)(目前仅支持通过 QuickConncet ID 连接,未验证 DSM 6 及以下版本)
- 新增主备线路切换功能AudioStation 禁用此功能)
- 新增[回放增益](https://github.com/gitbobobo/StreamMusic/issues/19)(仅 Navidrome 支持)
- 循环播放作为独立开关,默认为队列播放
- [倍速播放支持更细粒度的调节](https://github.com/gitbobobo/StreamMusic/issues/37)
- 修复已知问题
安卓体验地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.5/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.5/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.5/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.5/app-release.apk)
## V1.1.42023-09-26
更新内容:
- 支持 Emby
- 调整启动逻辑
- [调整本地数据同步逻辑](https://github.com/gitbobobo/StreamMusic/issues/17)
- 删除兼容模式
- 修复大量已知问题
安卓体验地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.4/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.4/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.4/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.4/app-release.apk)
## V1.1.32023-09-23
更新内容:
- [队列播放模式替换为循环播放模式](https://github.com/gitbobobo/StreamMusic/issues/46)
- 修复已知的[路由跳转问题](https://github.com/gitbobobo/StreamMusic/issues/39)(无法返回上级的问题)
- 修复 [OPPO 系手机安卓 13 系统播放闪退问题](https://github.com/ryanheise/audio_service/blob/minor/audio_service/CHANGELOG.md#01812)
- 【安卓】[支持 Flyme 状态栏歌词](https://github.com/gitbobobo/StreamMusic/issues/15)
:::caution
当前版本对播放逻辑进行了较大调整,请谨慎升级!
:::
安卓体验地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.3/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.3/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.3/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.1.3/app-release.apk)
> 关于状态栏歌词,如果你的系统不是 Flyme 但能显示的,可以在这个 [issue](https://github.com/ryanheise/audio_service/issues/1043) 下反馈一下(现在是通过魔改这个插件实现的,如果这个特性能带到这个插件里还是挺不错的)
## V1.1.22023-09-03
更新内容:
- 支持键盘快捷键
- 修复界面卡顿问题
- 支持上滑显示播放界面
- 【安卓】支持桌面歌词
- 【安卓】系统通知添加收藏按钮
安卓体验地址:[蓝奏云](https://wwco.lanzouq.com/b04qiog7g) 密码:alzb
## V1.1.12023-08-28
更新内容:
- 适配横屏
- 适配 pad 端
- 新增登录密码调整功能(仅用于服务端密码修改后客户端的调整)
- 可查看最后一次自定义 API 的请求信息
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzouq.com/b04qh4s4j) 密码:5tho
## V1.1.02023-08-13
更新内容:
- 支持 Jellyfin API
- 可自动下载歌单歌曲
- 新增离线模式开关
- 搜索页面和歌手详情页加入歌曲多选功能
- 播放页面可选择方形封面
- 其他细节优化
安卓体验地址:[蓝奏云](https://wwco.lanzouq.com/b04qacf7a) 密码:39hc

View File

@@ -0,0 +1,348 @@
---
sidebar_position: 3
---
# 1.2.x
更新日期2023-12-29 至 2024-05-15
## V1.2.92024-05-15
:::tip 活动预告
音流将在 1.3.0 适配安卓TV为庆祝音流达到此里程碑**将在 1.3.0 推出之后进行为期两周的优惠活动**。
活动期间,音流会员价格将降低 10 元左右。
:::
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Button from '@mui/material/Button';
import WindowIcon from '@mui/icons-material/Window';
import AppleIcon from '@mui/icons-material/Apple';
import AndroidIcon from '@mui/icons-material/Android';
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.9/app-arm64-v8a-release.apk">ARM64 版本</Button>
<span class="ml-md gray">MD5: b92e53f777e90c2c5ffd85d8a33dd44f</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.9/app-armeabi-v7a-release.apk">ARMV7 版本</Button>
<span class="ml-md gray">MD5: 5384b906a87b2126a70772cfd49b0af0</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.9/app-x86_64-release.apk">x86 版本</Button>
<span class="ml-md gray">MD5: 42447e8e9a83b1fe2d5c4153a54ea05d</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.9/app-release.apk">通用版本(体积较大)</Button>
<span class="ml-md gray">MD5: aafea724704fc74ed72d01ebd9fcea31</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.9/stream_music_1.2.9.1.msix">立即下载</Button>
<span class="ml-md gray">MD5: 83374503628c198b8d31df7d867153c2</span>
</div>
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.9/音流v1.2.9.dmg">立即下载</Button>
<span class="ml-md gray">MD5: 0a8f6aef5509376c2233521e5afbfc1b</span>
</div>
</TabItem>
</Tabs>
更新内容:
- 新增直连模式(不再完全扫描服务器数据,这会导致部分功能缺失)
- 媒体库模式(现有模式)不再扫描歌单内的歌
- 不完美[兼容 Airsonic](https://github.com/gitbobobo/StreamMusic/issues/274) 与 Gonic
- [升级线路配置功能](https://github.com/gitbobobo/StreamMusic/issues/248),可创建多个线路,拖拽可调整优先级,可手动切换当前线路
- 歌手列表增加宫格布局
- 调整提示弹框样式
- [兼容 mm:ss 格式的歌词](https://github.com/gitbobobo/StreamMusic/issues/230)
- 增加配置:[忽略短歌词](https://github.com/gitbobobo/StreamMusic/issues/287)少于5行
- 增加个性化配置:控制栏始终显示歌曲标题
- 桌面端增加个性化配置:双击播放歌曲
- Windows 端增加配置:是否应用窗口透明效果
- Windows 支持通过托盘切换歌曲
- 修复鸿蒙系统播放高码率文件闪退问题
- 修复 [Windows 中文用户名导致的无法播放问题](https://github.com/gitbobobo/StreamMusic/issues/242)
- 修复iOS音量淡入淡出的问题
- [Plex 支持选择分区](https://github.com/gitbobobo/StreamMusic/issues/259)
- 修复 bug[#216](https://github.com/gitbobobo/StreamMusic/issues/216), [#231](https://github.com/gitbobobo/StreamMusic/issues/231), [#261](https://github.com/gitbobobo/StreamMusic/issues/261), [#276](https://github.com/gitbobobo/StreamMusic/issues/276), [#285](https://github.com/gitbobobo/StreamMusic/issues/285), [#280](https://github.com/gitbobobo/StreamMusic/issues/280), [#273](https://github.com/gitbobobo/StreamMusic/issues/273), [#266](https://github.com/gitbobobo/StreamMusic/issues/266), [#260](https://github.com/gitbobobo/StreamMusic/issues/260)
文档更新:
- 增加直连模式说明
- 增加音乐服务接口文档
- 提供 [Navidrome 同步到 50000 首歌曲后无法继续同步的问题的解决方案](/docs/problems#navidrome-scan)
- 补充了一些[常见问题](/docs/problems)
## V1.2.82024-04-17
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.8/app-arm64-v8a-release.apk">ARM64 版本</Button>
<span class="ml-md gray">MD5: b6632b23a6222f0b9e3c6f4b4c0f64c7</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.8/app-armeabi-v7a-release.apk">ARMV7 版本</Button>
<span class="ml-md gray">MD5: c065b1057438cabc922e6679c8450e89</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.8/app-x86_64-release.apk">x86 版本</Button>
<span class="ml-md gray">MD5: f55b8fb5fe91eb29db3824c8632a1b3c</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.8/app-release.apk">通用版本(体积较大)</Button>
<span class="ml-md gray">MD5: 2dee053974f9376807c1ba8190dec36f</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.8/stream_music_1.2.8.0.msix">立即下载</Button>
<span class="ml-md gray">MD5: 7dfb4fb5aeea8e007b5531b8f0043dda</span>
</div>
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.2.8/音流v1.2.8.dmg">立即下载</Button>
<span class="ml-md gray">MD5: bafa36503c4bf79584e3d96188b40a1a</span>
</div>
:::caution
mac 版从当前版本起不再使用沙箱环境,若您之前安装过旧版,请自行删除 `/Users/用户名/Library/Containers/cn.aqzscn.streamMusic` 目录,避免占用您的电脑存储空间。
:::
</TabItem>
</Tabs>
更新内容:
- 支持更多音乐格式,如 m4a, wav 整轨等。[查看详情](/docs/notes/plugins#media_kit)
- 支持解析音乐文件内嵌歌词,文件若被转码,此功能可能失效。
- 支持[音量淡入淡出](https://github.com/gitbobobo/StreamMusic/issues/203)
- 支持[与其他应用同时播放](https://github.com/gitbobobo/StreamMusic/issues/199)
- 支持按文件类型筛选歌曲。
- 非会员可进入二级页面查看会员功能。
- 若歌手名下有重复文件,会在歌手列表右侧显示🔧
- 现可记忆从歌手页面播放歌曲的播放模式。
- 可配置播放时是否自动打开播放页。
- Navidrome 支持 OPUS 转码,相关问题:[#95](https://github.com/gitbobobo/StreamMusic/issues/95), [#193](https://github.com/gitbobobo/StreamMusic/issues/193)
- Plex 支持转码播放,支持文件删除接口和歌手匹配接口。
- 修复 Subsonic 无法下载的问题。
- 修复 [Emby 部分封面无法显示](https://github.com/gitbobobo/StreamMusic/issues/216)的问题。
- 修复 [Audio Station 部分封面无法显示](https://github.com/gitbobobo/StreamMusic/issues/227)的问题。
- 修复 [Audio Station DSM 6.0 版本登录失败](https://github.com/gitbobobo/StreamMusic/issues/219)的问题。
- 因更换播放插件,以下问题被关闭:[#10](https://github.com/gitbobobo/StreamMusic/issues/10), [#29](https://github.com/gitbobobo/StreamMusic/issues/29), [#102](https://github.com/gitbobobo/StreamMusic/issues/102), [#121](https://github.com/gitbobobo/StreamMusic/issues/121), [#166](https://github.com/gitbobobo/StreamMusic/issues/166), [#185](https://github.com/gitbobobo/StreamMusic/issues/185)
- 因更换播放插件,以下问题进入观察期,若无后续反馈将被关闭:[#86](https://github.com/gitbobobo/StreamMusic/issues/86), [#103](https://github.com/gitbobobo/StreamMusic/issues/103), [#146](https://github.com/gitbobobo/StreamMusic/issues/146), [#162](https://github.com/gitbobobo/StreamMusic/issues/162), [#177](https://github.com/gitbobobo/StreamMusic/issues/177), [#194](https://github.com/gitbobobo/StreamMusic/issues/194), [#196](https://github.com/gitbobobo/StreamMusic/issues/196), [#210](https://github.com/gitbobobo/StreamMusic/issues/210), [#212](https://github.com/gitbobobo/StreamMusic/issues/212), [#215](https://github.com/gitbobobo/StreamMusic/issues/215), [#226](https://github.com/gitbobobo/StreamMusic/issues/226)
## V1.2.72024-04-08
更新内容:
- 支持[专辑/歌手收藏功能](https://github.com/gitbobobo/StreamMusic/issues/155),增加对应的筛选功能
- 删除自动切换离线模式的逻辑
- 调整部分界面的弹出菜单样式
- 降低联网验证会员身份的概率
- 支持多艺术家【[#116](https://github.com/gitbobobo/StreamMusic/issues/116), [#96](https://github.com/gitbobobo/StreamMusic/issues/96)】
- 自定义 API 封面接口支持单独配置获取专辑还是歌手(取消请求歌曲封面,[统一改为获取专辑封面](https://github.com/gitbobobo/StreamMusic/issues/209)
- [提升歌词解析的兼容性](https://github.com/gitbobobo/StreamMusic/issues/190)
- 支持[连接至 Plex](https://github.com/gitbobobo/StreamMusic/issues/43),暂未适配转码播放,请注意流量消耗(下个版本适配)
- Audio Station 喜欢功能调整为获取五星评分的歌曲
- Emby 禁止直接创建歌单,可选中歌曲后在添加到歌单的弹框中创建新歌单
- 修复[Subsonic 封面图片混乱的问题](https://github.com/gitbobobo/StreamMusic/issues/189)
- [桌面端点击控制栏可显示播放控制按钮](https://github.com/gitbobobo/StreamMusic/issues/182),用于适配触屏操作
- Windows 改为单进程应用
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.7/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.7/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.7/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.7/app-release.apk)
Mac 下载地址:[音流v1.2.7.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.7/音流v1.2.7.dmg)
Windows 版下载地址:[stream_music_1.2.7.1.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.7/stream_music_1.2.7.1.msix)
## V1.2.62024-03-15
更新内容:
- AudioStation/Navidrome/Subsonic 新增歌曲评分功能
- Emby 现在只会显示存在音频的播放列表(此外,无需开启在主页显示播放列表视图也能获取播放列表了)
- 优化检查更新逻辑
- 优化[登录时自动补充端口号的逻辑](https://github.com/gitbobobo/StreamMusic/issues/172)
- 允许[应用系统字体缩放(仅缩小)](https://github.com/gitbobobo/StreamMusic/issues/169)
- 修复[在输入框中按空格键触发快捷键响应的问题](https://github.com/gitbobobo/StreamMusic/issues/175)
- 修复[播放队列最后一首歌重放的问题](https://github.com/gitbobobo/StreamMusic/issues/157)
- 【安卓】桌面歌词增加[双行显示的选项](https://github.com/gitbobobo/StreamMusic/issues/61)
- 【Mac/Windows】适配桌面端窗口外观
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.6/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.6/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.6/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.6/app-release.apk)
Mac 下载地址:[音流v1.2.6.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.6/音流v1.2.6.dmg)
Windows 版下载地址:[stream_music_1.2.6.1.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.6/stream_music_1.2.6.1.msix)
## V1.2.52024-03-03
更新内容:
- 默认主题支持自定义背景
- 登录时若未填写端口号则自动补充默认 HTTP 端口号
- 修复[音乐自动回到开头的问题](https://github.com/gitbobobo/StreamMusic/issues/157)
- 暂时禁用系统字体缩放功能
- 【iOS】初步[支持 CarPlay](https://github.com/gitbobobo/StreamMusic/issues/68)
- 【Mac/Windows】更换为沉浸式窗口标题栏
- 【Mac/Windows】支持最小化到托盘/ Dock 栏
- 【Windows】[修复音乐缓存不生效的问题](https://github.com/gitbobobo/StreamMusic/issues/161)
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.5/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.5/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.5/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.5/app-release.apk)
Mac 下载地址:[音流v1.2.5.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.5/音流v1.2.5.dmg)
Windows 版下载地址:[stream_music_1.2.5.0.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.5/stream_music_1.2.5.0.msix)
> Windows 更新此版本可能导致窗口全屏点不到关闭按钮,若遇到此问题,请删除`用户目录/AppData/Roaming/cn.aqzscn`目录(应用数据所在目录)后重新打开。
## V1.2.42024-02-13
更新内容:
- 新增重复歌曲检测功能(歌手详情页面)
- 歌曲转码时可以切换应用或锁屏了
- 自定义 API 新增歌曲详情接口
- 现可通过翻译接口翻译歌词(需手动操作)
- 现可识别同一行的中英文歌词并分离(需手动操作)
- 【iOS】修复更新应用导致已下载音乐丢失的问题
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.4/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.4/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.4/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.4/app-release.apk)
Mac 下载地址:[音流v1.2.4.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.4/音流v1.2.4.dmg)
Windows 版下载地址:[stream_music_1.2.4.0.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.4/stream_music_1.2.4.0.msix)
## V1.2.32024-01-30
更新内容:
- 修复歌曲切换后信息未更新的问题
- 【安卓】写入文件前先询问存储权限
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.3/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.3/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.3/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.3/app-release.apk)
Mac 下载地址:[音流v1.2.3.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.3/音流v1.2.3.dmg)
Windows 版下载地址:[stream_music_1.2.3.1.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.3/stream_music_1.2.3.1.msix)
## V1.2.22024-01-27
更新内容:
- 支持调节应用内音量
- 歌单导入导出功能m3u 格式iOS 暂不支持)
- 支持 Emby 歌词接口
- 适配 Navidrome 0.51(需重新同步数据)
- 【Windows】支持媒体通知
- 全平台支持蓝牙歌词(原锁屏歌词)
- 修复了一些问题
> 感觉叫蓝牙歌词也不太合适,不知道你有没有更简单明了的叫法。
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.2/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.2/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.2/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.2/app-release.apk)
Mac 下载地址:[音流v1.2.2.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.2/音流v1.2.2.dmg)
Windows 版下载地址:[stream_music_1.2.2.2.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.2/stream_music_1.2.2.2.msix)
## V1.2.12024-01-14
更新内容:
- [支持专辑艺术家标签](https://github.com/gitbobobo/StreamMusic/issues/114)
- [自动同步方式改为增量同步](https://github.com/gitbobobo/StreamMusic/issues/100)
- [歌曲预缓存功能](https://github.com/gitbobobo/StreamMusic/issues/58)
- 调整移动网络下内网地址可达性的判断逻辑
- 从未播放过的歌曲前面的**序号**将以绿色表示
- [提升曲库中包含长音频(有声书)文件的使用体验](https://github.com/gitbobobo/StreamMusic/issues/21)
- 歌词字体增加**极大**的选项
- 【安卓】[修复返回键逻辑异常的问题](https://github.com/gitbobobo/StreamMusic/issues/112)
- 【桌面端】可恢复上次打开时的窗口大小
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.1/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.1/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.1/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.1/app-release.apk)
Mac 下载地址:[音流v1.2.1.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.1/音流v1.2.1.dmg)
Windows 版下载地址:[stream_music_1.2.1.2.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.1/stream_music_1.2.1.2.msix)
## V1.2.02023-12-29
更新内容:
- 【Android、MacOS、Windows】可选择文件下载位置
- 【Android】支持支付宝支付
- 首页最近播放和最常播放可选择显示专辑或歌曲(主题-主页)
- 首屏可选择推荐页或首页(主题-主页)
- 支持[歌词确认接口](https://aqzscn.cn/archives/stream-music-custom-api#%E7%A1%AE%E8%AE%A4%E6%AD%8C%E8%AF%8D)
- 歌词中的空行可选择是否显示(主题-歌词)
- 支持单独刷新歌单列表
- 歌曲列表支持本地搜索
安卓版下载地址:
- [app-arm64-v8a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.0/app-arm64-v8a-release.apk)
- [app-armeabi-v7a-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.0/app-armeabi-v7a-release.apk)
- [app-x86_64-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.0/app-x86_64-release.apk)
- [app-release.apk](https://oss.aqzscn.cn/stream-music/versions/1.2.0/app-release.apk)
Mac 下载地址:[音流v1.2.0.dmg](https://oss.aqzscn.cn/stream-music/versions/1.2.0/音流v1.2.0.dmg)
Windows 版下载地址:[stream_music_1.2.0.0.msix](https://oss.aqzscn.cn/stream-music/versions/1.2.0/stream_music_1.2.0.0.msix)
windows 版安装方法详见 [Windows 版音流安装教程](https://aqzscn.cn/archives/stream-music-win)

View File

@@ -0,0 +1,508 @@
---
sidebar_position: 99
---
# Latest
Updated: 2025-01-18
:::tip Armor+1
import DayCounter from '@site/src/components/DayCounter';
StreamMusic has been released for <DayCounter dateStr="2023-06-06"/> days with 36 updates - still a young player!
Due to limited development experience and resources (while supporting multiple platforms & music services), updates and bug fixes may be slower than expected. Your understanding is appreciated.
But I always believe: The next version will be better!
:::
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
import Button from '@mui/material/Button';
import WindowIcon from '@mui/icons-material/Window';
import AppleIcon from '@mui/icons-material/Apple';
import AndroidIcon from '@mui/icons-material/Android';
## V1.3.6 (2025-03-20)
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} target="_blank" href="https://wwco.lanzouq.com/b00je8d17e">Download</Button>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} target="_blank" href="https://www.ilanzou.com/s/zok0EbV7">Download</Button>
</div>
:::caution
If installation fails, see [Installation Guide](../guides/install)
:::
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} target="_blank" href="https://www.ilanzou.com/s/X4J0EbUt">Download</Button>
</div>
</TabItem>
</Tabs>
**Updates:**
- [Adapted to new Navidrome native interface](https://github.com/gitbobobo/StreamMusic/issues/832)
- Support editing playlist info
- Added TXT format (Title - Artist) for playlist import/export
- Albums with fewer than 3 tracks show the total song count on their cover
- ReplayGain support for all servers
- Removed offline mode
- Added Spanish language support
- [Apple platform media controls show skip buttons for long audio](https://github.com/gitbobobo/StreamMusic/issues/865)
- [Auto-play on launch now opens player page](https://github.com/gitbobobo/StreamMusic/issues/878)
- [Enhanced visual feedback for prev/next buttons](https://github.com/gitbobobo/StreamMusic/issues/837)
- Improved Windows launch/exit experience
- Fixed [UI freeze when deleting empty playlist files](https://github.com/gitbobobo/StreamMusic/issues/843)
- Fixed inability to delete last remaining playlist
- Fixed bulk deletion of duplicate tracks in playlists
- Fixed POST requests not following redirects
- Fixed [UI freeze when no playable tracks](https://github.com/gitbobobo/StreamMusic/issues/882)
- Fixed [MTW lyrics matching by title only](https://github.com/gitbobobo/StreamMusic/issues/851)
- Fixed [ReplayGain volume calculation errors](https://github.com/gitbobobo/StreamMusic/issues/562)
## V1.3.52025-01-18
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} target="_blank" href="https://wwco.lanzouq.com/b00jdzrvmj">立即下载</Button>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} target="_blank" href="https://www.ilanzou.com/s/Vs50I5BH">立即下载</Button>
</div>
:::caution
若安装失败请查看[安装教程](../guides/install)
:::
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} target="_blank" href="https://www.ilanzou.com/s/d9D0I5O6">立即下载</Button>
</div>
</TabItem>
</Tabs>
更新内容:
- 支持 [Navidrome 的电台功能](https://github.com/gitbobobo/StreamMusic/issues/241)
- 提升多线路切换速度
- [歌词页添加粗体效果](https://github.com/gitbobobo/StreamMusic/issues/798)
- 登录时默认开启直连模式
- 下拉菜单适配桌面端 UI
- [桌面端添加屏幕常亮开关,避免一直点亮屏幕](https://github.com/gitbobobo/StreamMusic/issues/790)
- [Windows 支持同步 SMTC 播放进度](https://github.com/gitbobobo/StreamMusic/issues/722)
- 修复资料库详情页可能灰屏的问题
- 修复[媒体库模式获取不到歌单的问题](https://github.com/gitbobobo/StreamMusic/issues/794)
- 修复[下载歌曲被覆盖的问题](https://github.com/gitbobobo/StreamMusic/issues/781)
- 修复[切换到无歌词歌曲后,界面依旧显示上一句歌词的问题](https://github.com/gitbobobo/StreamMusic/issues/710)
- 修复[1970 年之前的专辑显示为未知年代的问题](https://github.com/gitbobobo/StreamMusic/issues/674)
- 修复[安卓桌面歌词拉大最大宽度后闪退的问题](https://github.com/gitbobobo/StreamMusic/issues/750)
- 修复[CarPlay 从歌手列表进入闪退的问题](https://github.com/gitbobobo/StreamMusic/issues/779)
## V1.3.42024-12-26
:::caution
由于每日的下载量逐渐增大CDN 流量成本已经有些难以承受。今后正式版本的**下载链接将通过网盘或 Github Release 发布**。
很抱歉给您造成的不便,不过请相信这都是暂时的,明年我将把上架安卓应用商店列为首要事项。
:::
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} target="_blank" href="https://wwco.lanzouq.com/b00jdws8cj">立即下载</Button>
<span class="ml-md gray">密码: bd39</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} target="_blank" href="https://www.ilanzou.com/s/dfMyb5zg">立即下载</Button>
<span class="ml-md gray">MD5: 0312775fa5ab5e7d829bb95ef2f19791</span>
</div>
:::caution
若安装失败请查看[安装教程](../guides/install)
:::
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} target="_blank" href="https://www.ilanzou.com/s/ZpwybpnX">立即下载</Button>
<span class="ml-md gray">MD5: 8f413127e9ba4bc1eb398cdf10a18956</span>
</div>
</TabItem>
</Tabs>
更新内容:
- 👑 iOS 支持快捷指令
- 移动端首页支持显示用户头像Emby,Jellyfin,Plex 可用)
- [windows 使用 NotoSansSC-Regular 作为默认字体](https://github.com/gitbobobo/StreamMusic/issues/760)
- 支持[m4a 格式转码播放](https://github.com/gitbobobo/StreamMusic/issues/611)
- 多线路增加蜂窝网络偏好
- 应用内添加安卓桌面歌词解锁按钮
- [增加上滑控制栏打开播放页的开关](https://github.com/gitbobobo/StreamMusic/issues/671)
- [桌面端图片资源均使用原图](https://github.com/gitbobobo/StreamMusic/issues/721)
- [CarPlay 艺术家列表支持按字母跳转](https://github.com/gitbobobo/StreamMusic/issues/698)
- 修复不打开 APP 无法使用 CarPlay 的问题
- 修复[创建歌单后,首页数据未刷新](https://github.com/gitbobobo/StreamMusic/issues/725)的问题
- 修复 [strm 文件无法播放的问题](https://github.com/gitbobobo/StreamMusic/issues/716)
- 修复[歌手详情专辑排序问题](https://github.com/gitbobobo/StreamMusic/issues/686)
- 修复 [Jellyfin 无法播放 ipv6 音乐链接的问题](https://github.com/gitbobobo/StreamMusic/issues/756)
- 修复[无法通过 Emby 的 Last.fm 插件上报播放记录的问题](https://github.com/gitbobobo/StreamMusic/issues/713)
- 修复 [Windows 端迷你窗口双击后会全屏显示的问题](https://github.com/gitbobobo/StreamMusic/issues/702)
- 修复[队列结尾无法下一曲到第一首的问题](https://github.com/gitbobobo/StreamMusic/issues/654)
## V1.3.32024-11-17
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.3/app-arm64-v8a-release.apk">ARM64 版本</Button>
<span class="ml-md gray">MD5: 010b0ccd625d3f7c872dab9da7502df6</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.3/app-armeabi-v7a-release.apk">ARMV7 版本</Button>
<span class="ml-md gray">MD5: ae92e104f118c6b6f0a4256003cd8952</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.3/app-x86_64-release.apk">x86 版本</Button>
<span class="ml-md gray">MD5: 0b44f215d577ecedef30b2e0f715a815</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.3/app-release.apk">通用版本(体积较大)</Button>
<span class="ml-md gray">MD5: f6ff5c17704238315dfa5d82a26f126d</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.3/stream_music_1.3.3.6.msix">立即下载</Button>
<span class="ml-md gray">MD5: 2d474371df21c7d8cd1cd75e98f46363</span>
</div>
:::caution
若安装失败请查看[安装教程](../guides/install)
:::
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.3/StreamMusic_1.3.3.dmg">立即下载</Button>
<span class="ml-md gray">MD5: d2e1ca2f3b7ac1c2229499ef744565fb</span>
</div>
</TabItem>
</Tabs>
更新内容:
- 👑 桌面端支持迷你窗口
- 👑 iOS 14.2 及以上版本支持画中画歌词
- iOS 通知中心组件支持显示收藏按钮
- 桌面端新增[关闭窗口快捷键](https://github.com/gitbobobo/StreamMusic/issues/627)
- [桌面端支持全局热键](https://github.com/gitbobobo/StreamMusic/issues/363),开关位于**帮助 - 快捷键**
- 多语言支持繁体中文
- 谷歌翻译接口可配置基础地址
- [自定义封面接口请求歌曲封面时会附加歌曲路径信息](https://github.com/gitbobobo/StreamMusic/issues/650)
- 调整安卓设置界面字体大小
- 媒体库模式在同步数据时可选择手动取消
- 支持[批量删除重复歌曲](https://github.com/gitbobobo/StreamMusic/issues/680)
- 优化[虚拟键盘自动隐藏逻辑](https://github.com/gitbobobo/StreamMusic/issues/639)
- 在不支持的服务端中隐藏文件夹和专辑艺术家的入口
- 安卓桌面歌词支持宽度调节
- 修复[安卓桌面歌词无法显示的问题](https://github.com/gitbobobo/StreamMusic/issues/615)
- 修复[逐字歌词解析问题](https://github.com/gitbobobo/StreamMusic/issues/605)
- 修复登录页面无法切换 TV 模式的问题
- 修复 Windows 端歌手详情页文字重叠的问题
- 修复[定时停止功能中,勾选播完当前歌曲后停止导致功能失效的问题](https://github.com/gitbobobo/StreamMusic/issues/618)
- 修复安卓耳机线控失效的问题
- 修复 DLNA 连接小爱音箱时无法更新播放状态的问题
- 修复切换资料库时首页部分数据未更新的问题
## V1.3.22024-10-04
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.2/app-arm64-v8a-release.apk">ARM64 版本</Button>
<span class="ml-md gray">MD5: 39d89dca63685ef98c440ca5efd2abeb</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.2/app-armeabi-v7a-release.apk">ARMV7 版本</Button>
<span class="ml-md gray">MD5: 4fe07080fbe91f4f8b699a3da79c8aa4</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.2/app-x86_64-release.apk">x86 版本</Button>
<span class="ml-md gray">MD5: 0fff06886b64b713337682793426639a</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.2/app-release.apk">通用版本(体积较大)</Button>
<span class="ml-md gray">MD5: 99a4b99ed10d2d11e70318d925e30905</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.2/stream_music_1.3.2.6.msix">立即下载</Button>
<span class="ml-md gray">MD5: 81cf96d4ee3c6b122eab1456e6a673e3</span>
</div>
:::caution
若安装失败请查看[安装教程](../guides/install)
:::
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.2/StreamMusic_1.3.2.dmg">立即下载</Button>
<span class="ml-md gray">MD5: bbad7b8ad5030553dae4357b59a9bab0</span>
</div>
</TabItem>
</Tabs>
更新内容:
- 移动端添加桌面小组件(播放控制与实时歌词)
- 为设置界面项目添加图标(主题中开启),并适应各平台风格
- 播放界面适应亮色风格
- 支持在应用内切换语言
- 优化歌手详情页在移动端横屏状态的表现
- [单曲循环时允许按下一曲切歌](https://github.com/gitbobobo/StreamMusic/issues/487)
- [AudioStation 支持按音轨号排序](https://github.com/gitbobobo/StreamMusic/issues/525),新增按音轨号排序方式
- [稍微增加横屏状态下播放页封面的尺寸](https://github.com/gitbobobo/StreamMusic/issues/448)
- [重复歌曲数量大于 9 时显示为 9+](https://github.com/gitbobobo/StreamMusic/issues/589)
- 播放页的歌词选项添加「生成翻译」功能
- [优化屏幕常亮触发逻辑](https://github.com/gitbobobo/StreamMusic/issues/600)
- 媒体库模式下,[同年发行的专辑按照专辑名排序](https://github.com/gitbobobo/StreamMusic/issues/476)
- [媒体库模式使用实时搜索](https://github.com/gitbobobo/StreamMusic/issues/599)
- 修复 [Windows 端无法搜索到 DLNA 设备的问题](https://github.com/gitbobobo/StreamMusic/issues/578)
- 修复无法播放 DSF 格式的问题 #388 #548
- 优化歌曲缓存逻辑,现已重新支持不转码播放 ogg 格式
- 修复 [VIVO 系手机不显示通知组件的问题](https://github.com/gitbobobo/StreamMusic/issues/394)
- 修复安卓通知栏播放按钮无法点击的问题
- 修复 [Jellyfin 封面不显示](https://github.com/gitbobobo/StreamMusic/issues/535)的问题
- 修复[切换播放模式后界面未更新](https://github.com/gitbobobo/StreamMusic/issues/537)的问题
- 修复 Subsonic 直连模式获取不到歌手的歌曲列表的问题
- 修复 [AudioStation 全部播放随机范围过小](https://github.com/gitbobobo/StreamMusic/issues/526)的问题
- 修复[播放已下载歌曲无法自动切歌的问题](https://github.com/gitbobobo/StreamMusic/issues/557)
- 修复[歌单内包含重复歌曲导致无法在启动时恢复播放列表的问题](https://github.com/gitbobobo/StreamMusic/issues/538)
- 修复 [windows 端无法切换歌单的问题](https://github.com/gitbobobo/StreamMusic/issues/576)
## V1.3.12024-09-02
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.1/app-arm64-v8a-release.apk">ARM64 版本</Button>
<span class="ml-md gray">MD5: dd95dadfc5e0da5390a56a4c2333b529</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.1/app-armeabi-v7a-release.apk">ARMV7 版本</Button>
<span class="ml-md gray">MD5: c6cc33ba5efa185d3daea8f62bdf399a</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.1/app-x86_64-release.apk">x86 版本</Button>
<span class="ml-md gray">MD5: be12b8d86a1d9867c6b2b6cfbddcee47</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.1/app-release.apk">通用版本(体积较大)</Button>
<span class="ml-md gray">MD5: 4e8d8000211401a7f1aa5f36a63ef0c7</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.1/stream_music_1.3.1.5.msix">立即下载</Button>
<span class="ml-md gray">MD5: 9eb42a5d0d3730034ec76030dee86bb9</span>
</div>
:::caution
若安装失败请查看[安装教程](../guides/install)
:::
</TabItem>
<TabItem value="mac" label="macOS">
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.1/StreamMusic_1.3.1.dmg">立即下载</Button>
<span class="ml-md gray">MD5: 156a5e98e00c9e0287f36169be4cbf38</span>
</div>
:::caution
当前版本修复了与最新版 Mac 系统的兼容问题,安装前需要先在访达 - 应用程序按 `Command + Delete` 删除之前安装的版本,否则会同时存在两个音流。
:::
</TabItem>
</Tabs>
更新内容:
- [DLNA 功能修复](https://github.com/gitbobobo/StreamMusic/issues/254)
- [Windows 新增任务栏快捷操作与播放进度显示](https://github.com/gitbobobo/StreamMusic/issues/220)
- 新增专辑艺术家列表(仅 Emby 和 Jellyfin 有效,其他服务端等同于歌手列表)
- 支持多艺术家跳转(此前默认跳转第一个)
- 支持[配置代理地址](https://github.com/gitbobobo/StreamMusic/issues/447)
- 去掉实时搜索逻辑(可能导致搜索时间过长),需按回车键触发搜索
- 手机端的首页显示资料库别名
- 调整纯色主题配色
- 对话框样式改为各个平台的原生样式,后续将逐步替换其他组件
- 支持[上报播放中的状态](https://github.com/gitbobobo/StreamMusic/issues/437)
- [歌曲详情显示缓存位置](https://github.com/gitbobobo/StreamMusic/issues/151)
- Emby/Jellyfin 增加全部分区的选项
- 封面显示逻辑调整回原来的(歌曲展示歌曲封面,专辑展示专辑封面)
- [修改歌曲列表默认封面](https://github.com/gitbobobo/StreamMusic/issues/468)
- 优化重定向歌曲资源的处理逻辑
- 调整歌词偏移后,按对勾会调用歌词确认接口
- [调整歌词与翻译的间距](https://github.com/gitbobobo/StreamMusic/issues/474)
- 同步数据的 IP 地址现可识别多网卡的 IP 地址
- [恢复自定义 API 保存按钮](https://github.com/gitbobobo/StreamMusic/issues/458)
- [媒体库模式文件夹模糊搜索](https://github.com/gitbobobo/StreamMusic/issues/481)不再对大小写敏感
- [提升歌手详情页按钮可见性](https://github.com/gitbobobo/StreamMusic/issues/477)
- 兼容 [macOS Beta 3](https://github.com/gitbobobo/StreamMusic/issues/414)
- 修复无法导入歌单的问题
- 修复自定义歌单顺序无法保存的问题
- 修复首页批量歌单歌曲时只能下载第一首的问题
- 兼容 [Jellyfin 10.8](https://github.com/gitbobobo/StreamMusic/issues/429)
- 修复 Plex 在 CarPlay 中点击歌曲列表后闪退的问题
- 修复 [Jellyfin 不显示封面的问题](https://github.com/gitbobobo/StreamMusic/issues/435)
- 修复无法删除已下载的歌曲的问题
- 修复媒体库模式下最近与最常播放不显示的问题
- 修复[直连模式下群晖无法按歌手筛选专辑和歌曲的问题](https://github.com/gitbobobo/StreamMusic/issues/433)
- 修复添加 BaseUrl 后无法播放的问题 [#438](https://github.com/gitbobobo/StreamMusic/issues/438) [#396](https://github.com/gitbobobo/StreamMusic/issues/396)
- 修复[无法播放文件夹下歌曲的问题](https://github.com/gitbobobo/StreamMusic/issues/473)
- 修复[媒体库模式下群晖无法按添加时间倒序](https://github.com/gitbobobo/StreamMusic/issues/459)的问题
- 修复[支付宝订单号恢复页面按钮不可用的问题](https://github.com/gitbobobo/StreamMusic/issues/453)
- 修复[低版本安卓无法恢复购买的问题](https://github.com/gitbobobo/StreamMusic/issues/469)
- 修复 [TV 版第二次打开时可能卡在启动页](https://github.com/gitbobobo/StreamMusic/issues/446)的问题
- 修复桌面端搜索到多个歌词时无法滚动选择的问题(添加底部指示器)
- 修复[随机播放歌单内歌曲时随机范围过小](https://github.com/gitbobobo/StreamMusic/issues/530)的问题
- 修复修改系统时区后歌词不会自动滚动的问题
- 修复[播放高码率文件可能出现电流声](https://github.com/gitbobobo/StreamMusic/issues/518)的问题
## V1.3.02024-07-25
:::success 早鸟优惠<sup>2</sup>
为庆祝音流达成适配安卓 TV 的里程碑,特开启第二波早鸟优惠,活动时间为 2024-07-26 至 2024-08-08。
在此期间音流会员价格将降低 10 元,您可以 38 元的特惠价购入音流终身会员。
活动结束后,音流终身会员价格将调整至 58 元。
:::
<Tabs groupId="operating-systems">
<TabItem value="android" label="Android">
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.0/app-arm64-v8a-release.apk">ARM64 版本</Button>
<span class="ml-md gray">MD5: 1cddbc720c19dde02d9d50d9a2106c35</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.0/app-armeabi-v7a-release.apk">ARMV7 版本</Button>
<span class="ml-md gray">MD5: 445eaba3783884ddb4207e99947ebd52</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.0/app-x86_64-release.apk">x86 版本</Button>
<span class="ml-md gray">MD5: b9bb45b1be24ca2efb9a1fcbcdc8b668</span>
</div>
<div class="mv-sm">
<Button variant="contained" startIcon={<AndroidIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.0/app-release.apk">通用版本(体积较大)</Button>
<span class="ml-md gray">MD5: 6ecf08468ec68879f50d78dc14dfd628</span>
</div>
</TabItem>
<TabItem value="win" label="Windows">
<div class="mv-sm">
<Button variant="contained" startIcon={<WindowIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.0/stream_music_1.3.0.5.msix">立即下载</Button>
<span class="ml-md gray">MD5: 94a7f1c000e033c59fbed040590bb94c</span>
</div>
</TabItem>
<TabItem value="mac" label="macOS">
:::caution
Mac OS 请暂时不要升级至 Beta 3 版本,会导致音流无法使用。
:::
<div class="mv-sm">
<Button variant="contained" startIcon={<AppleIcon />} href="https://oss.aqzscn.cn/stream-music/versions/1.3.0/音流v1.3.0.dmg">立即下载</Button>
<span class="ml-md gray">MD5: c622937c89b16df5eb510b129e1dd3c8</span>
</div>
</TabItem>
</Tabs>
更新内容:
- [适配安卓 TV](https://github.com/gitbobobo/StreamMusic/issues/23),建议手机上下载安装包后,通过 [localsend](https://github.com/localsend/localsend) 发送给 TV 端,以便后续更新。
- 新增扫码同步数据的功能(若无法识别请返回重进换一个二维码)
- 支持[多服务器切换](https://github.com/gitbobobo/StreamMusic/issues/35),支持分区选择
- 支持按流派筛选歌曲/专辑/歌手
- 支持自定义歌单排序
- 提升线路切换速度(主线路连接失败后,优先使用最先连接成功的线路)
- 增加标记歌曲为已播放的功能
- 升级歌曲定位功能
- [按评分筛选增加没有评分的选项](https://github.com/gitbobobo/StreamMusic/issues/362)
- 支持[主线路编辑](https://github.com/gitbobobo/StreamMusic/issues/327)
- 依次同步歌曲、专辑和歌手数据以解决[服务器并发请求过多无法正常获取响应](https://github.com/gitbobobo/StreamMusic/issues/365)的问题
- 长音频播放页的上一曲下一曲按钮改为快进快退
- [播放时忽略未完整缓存的歌曲](https://github.com/gitbobobo/StreamMusic/issues/316)
- [切歌之后如果没有图片,显示默认 Logo](https://github.com/gitbobobo/StreamMusic/issues/305)
- 调整 Windows 返回按钮位置
- [Audio Station 支持选择转码比特率](https://github.com/gitbobobo/StreamMusic/issues/286)
- 支持 [Jellyfin 的歌词接口](https://github.com/gitbobobo/StreamMusic/issues/289)
- [Emby/Jellyfin 不校验密码是否填写](https://github.com/gitbobobo/StreamMusic/issues/377)
- [Navidrome 占位图片视为无图片](https://github.com/gitbobobo/StreamMusic/issues/355)
- 修复媒体库模式下歌手页面无法搜索歌手的问题
- 修复[媒体库模式评分和收藏操作界面不更新](https://github.com/gitbobobo/StreamMusic/issues/348)的问题
- 修复自动下载会重复下载歌曲的问题
- 修复[自定义歌词接口切换歌词失效](https://github.com/gitbobobo/StreamMusic/issues/392)
- 修复[重新打开 app 后无法记忆上次播放位置的问题](https://github.com/gitbobobo/StreamMusic/issues/236)
- 修复一些卡在加载中提示的情况
- 修复单曲循环只上报了一次播放记录的问题
- 修复专辑页面和歌单页面的排序问题,[#301](https://github.com/gitbobobo/StreamMusic/issues/301), [#303](https://github.com/gitbobobo/StreamMusic/issues/303)
- 修复 ogg 格式只有第一次能播放的问题(缓存的 ogg 格式数据有问题,临时处理方式:对所有 ogg 格式转码后播放)
- 修复[搜索结果页歌曲无法播放的问题](https://github.com/gitbobobo/StreamMusic/issues/297)
- 修复[流派详情页未筛选数据的问题](https://github.com/gitbobobo/StreamMusic/issues/422)
- 修复 Emby 可能不显示歌词的问题
- 修复 [Emby 最近播放和最常播放顺序颠倒](https://github.com/gitbobobo/StreamMusic/issues/376) 的问题
- 修复 [Audio Station 登录过期后不显示图片,无法播放的问题](https://github.com/gitbobobo/StreamMusic/issues/321)
- 修复[媒体库模式无法识别 MTW 的歌手简介的问题](https://github.com/gitbobobo/StreamMusic/issues/311)
- 修复群晖或 Plex 自动获取的 IP 会重复添加的问题
- [Android] 修复[关闭系统省电模式后,从任务管理器杀死应用,音乐仍在播放的问题](https://github.com/gitbobobo/StreamMusic/issues/239)
文档更新:
使用说明部分有较多更新,建议完整阅读。

View File

@@ -0,0 +1,10 @@
{
"title": {
"message": "Stream Music",
"description": "The title in the navbar"
},
"logo.alt": {
"message": "Stream Music's Logo",
"description": "The alt text of navbar logo"
}
}

343
i18n/zh-Hans/code.json Normal file
View File

@@ -0,0 +1,343 @@
{
"theme.ErrorPageContent.title": {
"message": "页面已崩溃。",
"description": "The title of the fallback page when the page crashed"
},
"theme.BackToTopButton.buttonAriaLabel": {
"message": "回到顶部",
"description": "The ARIA label for the back to top button"
},
"theme.blog.archive.title": {
"message": "历史博文",
"description": "The page & hero title of the blog archive page"
},
"theme.blog.archive.description": {
"message": "历史博文",
"description": "The page & hero description of the blog archive page"
},
"theme.blog.paginator.navAriaLabel": {
"message": "博文列表分页导航",
"description": "The ARIA label for the blog pagination"
},
"theme.blog.paginator.newerEntries": {
"message": "较新的博文",
"description": "The label used to navigate to the newer blog posts page (previous page)"
},
"theme.blog.paginator.olderEntries": {
"message": "较旧的博文",
"description": "The label used to navigate to the older blog posts page (next page)"
},
"theme.blog.post.paginator.navAriaLabel": {
"message": "博文分页导航",
"description": "The ARIA label for the blog posts pagination"
},
"theme.blog.post.paginator.newerPost": {
"message": "较新一篇",
"description": "The blog post button label to navigate to the newer/previous post"
},
"theme.blog.post.paginator.olderPost": {
"message": "较旧一篇",
"description": "The blog post button label to navigate to the older/next post"
},
"theme.tags.tagsPageLink": {
"message": "查看所有标签",
"description": "The label of the link targeting the tag list page"
},
"theme.colorToggle.ariaLabel": {
"message": "切换浅色/暗黑模式(当前为{mode}",
"description": "The ARIA label for the navbar color mode toggle"
},
"theme.colorToggle.ariaLabel.mode.dark": {
"message": "暗黑模式",
"description": "The name for the dark color mode"
},
"theme.colorToggle.ariaLabel.mode.light": {
"message": "浅色模式",
"description": "The name for the light color mode"
},
"theme.docs.DocCard.categoryDescription.plurals": {
"message": "{count} 个项目",
"description": "The default description for a category card in the generated index about how many items this category includes"
},
"theme.docs.breadcrumbs.navAriaLabel": {
"message": "页面路径",
"description": "The ARIA label for the breadcrumbs"
},
"theme.docs.paginator.navAriaLabel": {
"message": "文件选项卡",
"description": "The ARIA label for the docs pagination"
},
"theme.docs.paginator.previous": {
"message": "上一页",
"description": "The label used to navigate to the previous doc"
},
"theme.docs.paginator.next": {
"message": "下一页",
"description": "The label used to navigate to the next doc"
},
"theme.docs.tagDocListPageTitle.nDocsTagged": {
"message": "{count} 篇文档带有标签",
"description": "Pluralized label for \"{count} docs tagged\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.docs.tagDocListPageTitle": {
"message": "{nDocsTagged}「{tagName}」",
"description": "The title of the page for a docs tag"
},
"theme.docs.versions.unreleasedVersionLabel": {
"message": "此为 {siteTitle} {versionLabel} 版尚未发行的文档。",
"description": "The label used to tell the user that he's browsing an unreleased doc version"
},
"theme.docs.versions.unmaintainedVersionLabel": {
"message": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
"description": "The label used to tell the user that he's browsing an unmaintained doc version"
},
"theme.docs.versions.latestVersionSuggestionLabel": {
"message": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
"description": "The label used to tell the user to check the latest version"
},
"theme.docs.versions.latestVersionLinkLabel": {
"message": "最新版本",
"description": "The label used for the latest version suggestion link label"
},
"theme.docs.versionBadge.label": {
"message": "版本:{versionLabel}"
},
"theme.common.headingLinkTitle": {
"message": "{heading}的直接链接",
"description": "Title for link to heading"
},
"theme.common.editThisPage": {
"message": "编辑此页",
"description": "The link label to edit the current page"
},
"theme.lastUpdated.atDate": {
"message": "于 {date} ",
"description": "The words used to describe on which date a page has been last updated"
},
"theme.lastUpdated.byUser": {
"message": "由 {user} ",
"description": "The words used to describe by who the page has been last updated"
},
"theme.lastUpdated.lastUpdatedAtBy": {
"message": "最后{byUser}{atDate}更新",
"description": "The sentence used to display when a page has been last updated, and by who"
},
"theme.navbar.mobileVersionsDropdown.label": {
"message": "选择版本",
"description": "The label for the navbar versions dropdown on mobile view"
},
"theme.NotFound.title": {
"message": "找不到页面",
"description": "The title of the 404 page"
},
"theme.admonition.caution": {
"message": "警告",
"description": "The default label used for the Caution admonition (:::caution)"
},
"theme.admonition.danger": {
"message": "危险",
"description": "The default label used for the Danger admonition (:::danger)"
},
"theme.admonition.info": {
"message": "信息",
"description": "The default label used for the Info admonition (:::info)"
},
"theme.admonition.note": {
"message": "备注",
"description": "The default label used for the Note admonition (:::note)"
},
"theme.admonition.tip": {
"message": "提示",
"description": "The default label used for the Tip admonition (:::tip)"
},
"theme.admonition.warning": {
"message": "注意",
"description": "The default label used for the Warning admonition (:::warning)"
},
"theme.tags.tagsListLabel": {
"message": "标签:",
"description": "The label alongside a tag list"
},
"theme.AnnouncementBar.closeButtonAriaLabel": {
"message": "关闭",
"description": "The ARIA label for close button of announcement bar"
},
"theme.blog.sidebar.navAriaLabel": {
"message": "最近博文导航",
"description": "The ARIA label for recent posts in the blog sidebar"
},
"theme.CodeBlock.copied": {
"message": "复制成功",
"description": "The copied button label on code blocks"
},
"theme.CodeBlock.copyButtonAriaLabel": {
"message": "复制代码到剪贴板",
"description": "The ARIA label for copy code blocks button"
},
"theme.CodeBlock.copy": {
"message": "复制",
"description": "The copy button label on code blocks"
},
"theme.CodeBlock.wordWrapToggle": {
"message": "切换自动换行",
"description": "The title attribute for toggle word wrapping button of code block lines"
},
"theme.DocSidebarItem.expandCategoryAriaLabel": {
"message": "展开侧边栏分类 '{label}'",
"description": "The ARIA label to expand the sidebar category"
},
"theme.DocSidebarItem.collapseCategoryAriaLabel": {
"message": "折叠侧边栏分类 '{label}'",
"description": "The ARIA label to collapse the sidebar category"
},
"theme.NavBar.navAriaLabel": {
"message": "主导航",
"description": "The ARIA label for the main navigation"
},
"theme.NotFound.p1": {
"message": "我们找不到您要找的页面。",
"description": "The first paragraph of the 404 page"
},
"theme.NotFound.p2": {
"message": "请联系原始链接来源网站的所有者,并告知他们链接已损坏。",
"description": "The 2nd paragraph of the 404 page"
},
"theme.TOCCollapsible.toggleButtonLabel": {
"message": "本页总览",
"description": "The label used by the button on the collapsible TOC component"
},
"theme.blog.post.readingTime.plurals": {
"message": "阅读需 {readingTime} 分钟",
"description": "Pluralized label for \"{readingTime} min read\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.navbar.mobileLanguageDropdown.label": {
"message": "选择语言",
"description": "The label for the mobile language switcher dropdown"
},
"theme.blog.post.readMore": {
"message": "阅读更多",
"description": "The label used in blog post item excerpts to link to full blog posts"
},
"theme.blog.post.readMoreLabel": {
"message": "阅读 {title} 的全文",
"description": "The ARIA label for the link to full blog posts from excerpts"
},
"theme.docs.breadcrumbs.home": {
"message": "主页面",
"description": "The ARIA label for the home page in the breadcrumbs"
},
"theme.docs.sidebar.navAriaLabel": {
"message": "文档侧边栏",
"description": "The ARIA label for the sidebar navigation"
},
"theme.docs.sidebar.collapseButtonTitle": {
"message": "收起侧边栏",
"description": "The title attribute for collapse button of doc sidebar"
},
"theme.docs.sidebar.collapseButtonAriaLabel": {
"message": "收起侧边栏",
"description": "The title attribute for collapse button of doc sidebar"
},
"theme.docs.sidebar.closeSidebarButtonAriaLabel": {
"message": "关闭导航栏",
"description": "The ARIA label for close button of mobile sidebar"
},
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": {
"message": "切换导航栏",
"description": "The ARIA label for hamburger menu button of mobile navigation"
},
"theme.docs.sidebar.expandButtonTitle": {
"message": "展开侧边栏",
"description": "The ARIA label and title attribute for expand button of doc sidebar"
},
"theme.docs.sidebar.expandButtonAriaLabel": {
"message": "展开侧边栏",
"description": "The ARIA label and title attribute for expand button of doc sidebar"
},
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": {
"message": "← 回到主菜单",
"description": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)"
},
"theme.blog.post.plurals": {
"message": "{count} 篇博文",
"description": "Pluralized label for \"{count} posts\". Use as much plural forms (separated by \"|\") as your language support (see https://www.unicode.org/cldr/cldr-aux/charts/34/supplemental/language_plural_rules.html)"
},
"theme.blog.tagTitle": {
"message": "{nPosts} 含有标签「{tagName}」",
"description": "The title of the page for a blog tag"
},
"theme.blog.author.pageTitle": {
"message": "{authorName} - {nPosts}",
"description": "The title of the page for a blog author"
},
"theme.blog.authorsList.pageTitle": {
"message": "Authors",
"description": "The title of the authors page"
},
"theme.blog.authorsList.viewAll": {
"message": "View All Authors",
"description": "The label of the link targeting the blog authors page"
},
"theme.blog.author.noPosts": {
"message": "This author has not written any posts yet.",
"description": "The text for authors with 0 blog post"
},
"theme.contentVisibility.unlistedBanner.title": {
"message": "未列出页",
"description": "The unlisted content banner title"
},
"theme.contentVisibility.unlistedBanner.message": {
"message": "此页面未列出。搜索引擎不会对其索引,只有拥有直接链接的用户才能访问。",
"description": "The unlisted content banner message"
},
"theme.contentVisibility.draftBanner.title": {
"message": "Draft page",
"description": "The draft content banner title"
},
"theme.contentVisibility.draftBanner.message": {
"message": "This page is a draft. It will only be visible in dev and be excluded from the production build.",
"description": "The draft content banner message"
},
"theme.ErrorPageContent.tryAgain": {
"message": "重试",
"description": "The label of the button to try again rendering when the React error boundary captures an error"
},
"theme.common.skipToMainContent": {
"message": "跳到主要内容",
"description": "The skip to content label used for accessibility, allowing to rapidly navigate to main content with keyboard tab/enter navigation"
},
"theme.tags.tagsPageTitle": {
"message": "标签",
"description": "The title of the tag list page"
},
"StreamMusic": {
"message": "音流"
},
"Download": {
"message": "立即下载"
},
"QuickStart": {
"message": "快速开始"
},
"Enjoy your Music": {
"message": "连接你的音乐"
},
"Carefully designed interface allows you to get started quickly": {
"message": "精心设计的操作界面,让您可以快速上手"
},
"Supports common music services, allowing you to access multiple music services through one client": {
"message": "支持常见的音乐服务,让您可以通过一个客户端访问多种音乐服务"
},
"Available on Android, iOS, macOS, and Windows, providing a consistent experience across platforms": {
"message": "可在 Android、iOS、macOS 和 Windows 上使用,并提供与平台一致的体验"
},
"Easy to Use": {
"message": "易于使用"
},
"Focus on Music": {
"message": "专注于音乐"
},
"Cross-Platform Support": {
"message": "跨平台支持"
}
}

View File

@@ -0,0 +1,54 @@
{
"version.label": {
"message": "Next",
"description": "The label for version current"
},
"sidebar.tutorialSidebar.category.guides": {
"message": "使用说明",
"description": "The label for category guides in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.guides.link.generated-index.description": {
"message": "音流安装及使用说明。",
"description": "The generated-index page description for category guides in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.tips": {
"message": "实用技巧",
"description": "The label for category tips in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.tips.link.generated-index.description": {
"message": "光有好剑是不够的,你还需要好的剑谱。",
"description": "The generated-index page description for category tips in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.versions": {
"message": "版本列表",
"description": "The label for category versions in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.versions.link.generated-index.description": {
"message": "包含历史版本更新说明和安装包下载地址。",
"description": "The generated-index page description for category versions in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.developmentNotes": {
"message": "开发笔记",
"description": "The label for category developmentNotes in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.developmentNotes.link.generated-index.description": {
"message": "音流开发过程的经验分享,随缘记录。",
"description": "The generated-index page description for category developmentNotes in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.musicServices": {
"message": "音乐服务",
"description": "The label for category musicServices in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.musicServices.link.generated-index.description": {
"message": "记录音流用到的一些音乐服务接口(非全部接口,仅记录与音乐相关的),一是方便自己查阅,二是可以让有需要的人少走些弯路。可能有些地方理解不到位,欢迎大家指正和补充。",
"description": "The generated-index page description for category musicServices in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.adaptation": {
"message": "功能适配",
"description": "The label for category adaptation in sidebar tutorialSidebar"
},
"sidebar.tutorialSidebar.category.adaptation.link.generated-index.description": {
"message": "音流开发过程的经验分享,随缘记录。",
"description": "The generated-index page description for category adaptation in sidebar tutorialSidebar"
}
}

View File

@@ -0,0 +1,10 @@
{
"title": {
"message": "音流",
"description": "The title in the navbar"
},
"logo.alt": {
"message": "Stream Music's Logo",
"description": "The alt text of navbar logo"
}
}

14706
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -15,17 +15,17 @@
"gen-link": "node ./scripts/link.js 1.3.4 /Users/godbobo/work/music/release"
},
"dependencies": {
"@docusaurus/core": "3.1.1",
"@docusaurus/preset-classic": "3.1.1",
"@docusaurus/core": "3.7.0",
"@docusaurus/preset-classic": "3.7.0",
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.0",
"@mdx-js/react": "^3.0.0",
"@mdx-js/react": "^3.0.1",
"@mui/icons-material": "^5.15.13",
"@mui/material": "^5.15.13",
"clsx": "^2.0.0",
"prism-react-renderer": "^2.3.0",
"react": "^18.0.0",
"react-dom": "^18.0.0",
"clsx": "^2.1.0",
"prism-react-renderer": "^2.3.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"yargs": "^17.7.2"
},
"devDependencies": {

4687
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,40 +1,43 @@
import clsx from 'clsx';
import Heading from '@theme/Heading';
import styles from './styles.module.css';
import clsx from "clsx";
import Heading from "@theme/Heading";
import Translate, { translate } from "@docusaurus/Translate";
import styles from "./styles.module.css";
const FeatureList = [
{
title: '易于使用',
Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
title: translate({ message: "Easy to Use" }),
Svg: require("@site/static/img/undraw_docusaurus_tree.svg").default,
description: (
<>
精心设计的操作界面让您可以快速上手
</>
<Translate>
Carefully designed interface allows you to get started quickly
</Translate>
),
},
{
title: '专注于音乐',
Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
title: translate({ message: "Focus on Music" }),
Svg: require("@site/static/img/undraw_docusaurus_mountain.svg").default,
description: (
<>
支持常见的音乐服务让您可以通过一个客户端访问多种音乐服务
</>
<Translate>
Supports common music services, allowing you to access multiple music
services through one client
</Translate>
),
},
{
title: '跨平台支持',
Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
title: translate({ message: "Cross-Platform Support" }),
Svg: require("@site/static/img/undraw_docusaurus_react.svg").default,
description: (
<>
可在 AndroidiOSmacOS Windows 上使用并提供与平台一致的体验
</>
<Translate>
Available on Android, iOS, macOS, and Windows, providing a consistent
experience across platforms
</Translate>
),
},
];
function Feature({Svg, title, description}) {
function Feature({ Svg, title, description }) {
return (
<div className={clsx('col col--4')}>
<div className={clsx("col col--4")}>
<div className="text--center">
<Svg className={styles.featureSvg} role="img" />
</div>

View File

@@ -1,31 +1,41 @@
import clsx from 'clsx';
import Link from '@docusaurus/Link';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
import HomepageFeatures from '@site/src/components/HomepageFeatures';
import Button from '@mui/material/Button';
import DownloadIcon from '@mui/icons-material/Download';
import ArrowForwardIcon from '@mui/icons-material/ArrowForward';
import Heading from '@theme/Heading';
import styles from './index.module.css';
import clsx from "clsx";
import Link from "@docusaurus/Link";
import Layout from "@theme/Layout";
import HomepageFeatures from "@site/src/components/HomepageFeatures";
import Button from "@mui/material/Button";
import DownloadIcon from "@mui/icons-material/Download";
import ArrowForwardIcon from "@mui/icons-material/ArrowForward";
import Translate from "@docusaurus/Translate";
import Heading from "@theme/Heading";
import styles from "./index.module.css";
function HomepageHeader() {
const {siteConfig} = useDocusaurusContext();
return (
<header className={clsx('hero hero--primary', styles.heroBanner)}>
<header className={clsx("hero hero--primary", styles.heroBanner)}>
<div className="container">
<Heading as="h1" className="hero__title">
{siteConfig.title}
<Translate>StreamMusic</Translate>
</Heading>
<p className="hero__subtitle">{siteConfig.tagline}</p>
<p className="hero__subtitle">
<Translate>Enjoy your Music</Translate>
</p>
<div className={styles.buttons}>
<Link to="/docs/versions/latest" className={styles.buttonWrapper}>
<Button variant="contained" startIcon={<DownloadIcon />} size="large">立即下载</Button>
<Button
variant="contained"
startIcon={<DownloadIcon />}
size="large">
<Translate>Download</Translate>
</Button>
</Link>
<Link to="/docs/intro" className={styles.buttonWrapper}>
<Button variant="contained" endIcon={<ArrowForwardIcon />} size="large">快速开始</Button>
<Button
variant="contained"
endIcon={<ArrowForwardIcon />}
size="large">
<Translate>QuickStart</Translate>
</Button>
</Link>
</div>
</div>
@@ -35,8 +45,7 @@ function HomepageHeader() {
export default function Home() {
return (
<Layout
description="音流是一款跨平台的 NAS 音乐播放器。">
<Layout description="音流是一款跨平台的 NAS 音乐播放器。">
<HomepageHeader />
<main>
<HomepageFeatures />