mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-06 14:52:50 +08:00
Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb0cf943ef | ||
|
|
9f520eac11 | ||
|
|
d9301dce23 | ||
|
|
609fc9f661 | ||
|
|
22704e15fd | ||
|
|
eead12643d | ||
|
|
4838070f50 | ||
|
|
9e03c26f3f | ||
|
|
c7c54e9446 | ||
|
|
0690f4846e | ||
|
|
eb39281eb7 | ||
|
|
f12af9b8e8 |
11
CHANGELOG.md
11
CHANGELOG.md
@@ -1,3 +1,14 @@
|
||||
## v0.3.80 (2025-05-18)
|
||||
|
||||
### Feat
|
||||
|
||||
- 新增 OH2 型号的支持
|
||||
- 支持配置最大搜索歌曲数量 see #462
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复获取在线歌曲长度 (#469)
|
||||
|
||||
## v0.3.79 (2025-04-29)
|
||||
|
||||
### Fix
|
||||
|
||||
@@ -208,6 +208,7 @@ docker build -t xiaomusic .
|
||||
| X08C X08E X8F | 已经不需要设置了. ~需要设置【型号兼容模式】选项为 true~ |
|
||||
| M01/XMYX01JY | 小米小爱音箱HD 需要设置【特殊型号获取对话记录】选项为 true 才能语音播放|
|
||||
| OH2P | XIAOMI 智能音箱 Pro |
|
||||
| OH2 | XIAOMI 智能音箱 |
|
||||
|
||||
型号与产品名称对照可以在这里查询 <https://home.miot-spec.com/s/xiaomi.wifispeaker>
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ docker tag m.daocloud.io/docker.io/hanxi/xiaomusic:latest hanxi/xiaomusic:latest
|
||||
|
||||
---
|
||||
|
||||
### 评论 4 - ginitaimeiyty
|
||||
### 评论 4 - SenyFish
|
||||
|
||||
如果手头上有能科学上网的机器,直接把群辉的代理服务器IP填写成可以科学上网的机器IP+端口,翻墙软件打开允许局域网连接就可以
|
||||
|
||||
|
||||
@@ -70,5 +70,40 @@ docker compose down
|
||||
|
||||
## 评论
|
||||
|
||||
没有评论。
|
||||
|
||||
### 评论 1 - tiger326
|
||||
|
||||
我用这个是可以正常启动和搭建好xiaomusic, 一切都OK.
|
||||
不过我的NAS是qnap, 已禁用默认的admin用户, 使用自建的管理员账户登录.
|
||||
但这个配置会默认使用admin用户执行, 导致一旦产生tmp和download目录以及相关文件, 都归属于admin用户.
|
||||
结果我自建的用户在NAS上无法删除和编辑这些下载的文件.
|
||||
|
||||
xiaomusic是否支持创建时指定用户和用户组?
|
||||
|
||||
---
|
||||
|
||||
### 评论 2 - hanxi
|
||||
|
||||
@tiger326 把下面的 username 换成普通的用户名即可,换成 uid 数字也行,一般是 1000
|
||||
|
||||
```shell
|
||||
mkdir -p /xiaomusic
|
||||
cat <<EOF > /xiaomusic/docker-compose.yml
|
||||
services:
|
||||
xiaomusic:
|
||||
image: docker.hanxi.cc/hanxi/xiaomusic
|
||||
container_name: xiaomusic
|
||||
restart: unless-stopped
|
||||
user: username
|
||||
ports:
|
||||
- 58090:8090
|
||||
environment:
|
||||
XIAOMUSIC_PUBLIC_PORT: 58090
|
||||
volumes:
|
||||
- /xiaomusic_conf:/app/conf
|
||||
- /xiaomusic_music:/app/music
|
||||
EOF
|
||||
```
|
||||
|
||||
---
|
||||
[链接到 GitHub Issue](https://github.com/hanxi/xiaomusic/issues/360)
|
||||
|
||||
@@ -4,7 +4,7 @@ title: 微信交流群二维码
|
||||
|
||||
# 微信交流群二维码
|
||||
|
||||

|
||||

|
||||
|
||||
如果你刚好在买流量卡,可以在我的微信卡店里看看有没有合适的。
|
||||

|
||||
|
||||
@@ -1639,5 +1639,23 @@ ZZZZZZ最后发现是没刷新页面, 收藏没刷新出来. 语音命令是有
|
||||
|
||||
部署在我台式机上,关闭了防火墙,台式机与小爱音箱连接了同一个热点
|
||||
|
||||
---
|
||||
|
||||
### 评论 105 - ocean412257013
|
||||
|
||||
请教 在build的时候报错,是哪个意思
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
### 评论 106 - hanxi
|
||||
|
||||
> 请教 在build的时候报错,是哪个意思
|
||||
>
|
||||
> 
|
||||
|
||||
换个国内的镜像。
|
||||
|
||||
---
|
||||
[链接到 GitHub Issue](https://github.com/hanxi/xiaomusic/issues/99)
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
# 版本日志
|
||||
|
||||
## v0.3.79 (2025-04-29)
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复型号LX05不能播放问题
|
||||
|
||||
## v0.3.78 (2025-04-09)
|
||||
|
||||
### Feat
|
||||
|
||||
@@ -208,6 +208,7 @@ docker build -t xiaomusic .
|
||||
| X08C X08E X8F | 已经不需要设置了. ~需要设置【型号兼容模式】选项为 true~ |
|
||||
| M01/XMYX01JY | 小米小爱音箱HD 需要设置【特殊型号获取对话记录】选项为 true 才能语音播放|
|
||||
| OH2P | XIAOMI 智能音箱 Pro |
|
||||
| OH2 | XIAOMI 智能音箱 |
|
||||
|
||||
型号与产品名称对照可以在这里查询 <https://home.miot-spec.com/s/xiaomi.wifispeaker>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.3.79"
|
||||
version = "0.3.80"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.3.79"
|
||||
__version__ = "0.3.80"
|
||||
|
||||
@@ -216,6 +216,8 @@ class Config:
|
||||
enable_cmd_del_music: bool = (
|
||||
os.getenv("XIAOMUSIC_ENABLE_CMD_DEL_MUSIC", "false").lower() == "true"
|
||||
)
|
||||
# 搜索歌曲数量
|
||||
search_music_count: int = int(os.getenv("XIAOMUSIC_SEARCH_MUSIC_COUNT", "100"))
|
||||
|
||||
def append_keyword(self, keys, action):
|
||||
for key in keys.split(","):
|
||||
|
||||
@@ -29,10 +29,13 @@ NEED_USE_PLAY_MUSIC_API = [
|
||||
"X8F",
|
||||
"X4B",
|
||||
"LX05",
|
||||
"OH2",
|
||||
"OH2P",
|
||||
]
|
||||
|
||||
# 有 tts command 的设备型号
|
||||
TTS_COMMAND = {
|
||||
"OH2": "5-3",
|
||||
"OH2P": "7-3",
|
||||
"LX06": "5-1",
|
||||
"S12": "5-1",
|
||||
|
||||
4
xiaomusic/static/default/debug.html
vendored
4
xiaomusic/static/default/debug.html
vendored
@@ -6,9 +6,9 @@
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Debug For XiaoMusic</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1745941221">
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1747549809">
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script src="./jquery-3.7.1.min.js?version=1745941221"></script>
|
||||
<script src="./jquery-3.7.1.min.js?version=1747549809"></script>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
4
xiaomusic/static/default/downloadtool.html
vendored
4
xiaomusic/static/default/downloadtool.html
vendored
@@ -4,8 +4,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>歌曲下载工具</title>
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1745941221">
|
||||
<script src="./jquery-3.7.1.min.js?version=1745941221"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1747549809">
|
||||
<script src="./jquery-3.7.1.min.js?version=1747549809"></script>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
6
xiaomusic/static/default/index.html
vendored
6
xiaomusic/static/default/index.html
vendored
@@ -6,8 +6,8 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<link href="https://fonts.googleapis.com/css?family=Material+Icons|Material+Icons+Outlined" rel="stylesheet">
|
||||
<script src="./jquery-3.7.1.min.js?version=1745941221"></script>
|
||||
<link rel="stylesheet" href="./main.css?version=1745941221">
|
||||
<script src="./jquery-3.7.1.min.js?version=1747549809"></script>
|
||||
<link rel="stylesheet" href="./main.css?version=1747549809">
|
||||
<link rel="icon" href="./favicon.ico">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
@@ -219,7 +219,7 @@
|
||||
Powered by XiaoMusic
|
||||
</div>
|
||||
|
||||
<script src="./md.js?version=1745941221">
|
||||
<script src="./md.js?version=1747549809">
|
||||
</script>
|
||||
</body>
|
||||
|
||||
|
||||
2
xiaomusic/static/default/m3u.html
vendored
2
xiaomusic/static/default/m3u.html
vendored
@@ -5,7 +5,7 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>M3U to JSON Converter</title>
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1745941221">
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1747549809">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
9
xiaomusic/static/default/setting.html
vendored
9
xiaomusic/static/default/setting.html
vendored
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<script src="./jquery-3.7.1.min.js?version=1745941221"></script>
|
||||
<script src="./setting.js?version=1745941221"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1745941221">
|
||||
<script src="./jquery-3.7.1.min.js?version=1747549809"></script>
|
||||
<script src="./setting.js?version=1747549809"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./main.css?version=1747549809">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
@@ -120,6 +120,9 @@ var vConsole = new window.VConsole();
|
||||
<label for="music_path_depth">目录深度:</label>
|
||||
<input id="music_path_depth" type="number" value="10" />
|
||||
|
||||
<label for="search_music_count">搜索歌曲数量:</label>
|
||||
<input id="search_music_count" type="number" value="100" />
|
||||
|
||||
<label for="search_prefix">XIAOMUSIC_SEARCH(歌曲下载方式):</label>
|
||||
<select id="search_prefix">
|
||||
<option value="bilisearch:">bilisearch:</option>
|
||||
|
||||
@@ -292,16 +292,41 @@ def is_m4a(url):
|
||||
|
||||
|
||||
async def _get_web_music_duration(session, url, config, start=0, end=500):
|
||||
"""
|
||||
异步获取网络音乐文件的部分内容并估算其时长。
|
||||
|
||||
通过请求 URL 的前几个字节(默认 0-500)下载部分文件,
|
||||
写入临时文件后调用本地工具(如 ffprobe)获取音频时长。
|
||||
|
||||
:param session: aiohttp.ClientSession 实例
|
||||
:param url: 音乐文件的 URL 地址
|
||||
:param config: 包含配置信息的对象(如 ffmpeg 路径)
|
||||
:param start: 请求的起始字节位置
|
||||
:param end: 请求的结束字节位置
|
||||
:return: 返回音频的持续时间(秒),如果失败则返回 0
|
||||
"""
|
||||
duration = 0
|
||||
# 设置请求头 Range,只请求部分内容(用于快速获取元数据)
|
||||
headers = {"Range": f"bytes={start}-{end}"}
|
||||
|
||||
# 使用 aiohttp 异步发起 GET 请求,获取部分音频内容
|
||||
async with session.get(url, headers=headers) as response:
|
||||
array_buffer = await response.read()
|
||||
with tempfile.NamedTemporaryFile() as tmp:
|
||||
tmp.write(array_buffer)
|
||||
try:
|
||||
duration = await get_local_music_duration(tmp, config)
|
||||
except Exception as e:
|
||||
log.error(f"Error _get_web_music_duration: {e}")
|
||||
array_buffer = await response.read() # 读取响应的二进制内容
|
||||
|
||||
# 创建一个命名的临时文件,并禁用自动删除(以便后续读取)
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
||||
tmp.write(array_buffer) # 将下载的部分内容写入临时文件
|
||||
tmp_path = tmp.name # 获取该临时文件的真实路径
|
||||
|
||||
try:
|
||||
# 调用 get_local_music_duration 并传入文件路径,而不是文件对象
|
||||
duration = await get_local_music_duration(tmp_path, config)
|
||||
except Exception as e:
|
||||
log.error(f"Error _get_web_music_duration: {e}")
|
||||
finally:
|
||||
# 手动删除临时文件,避免残留
|
||||
os.unlink(tmp_path)
|
||||
|
||||
return duration
|
||||
|
||||
|
||||
|
||||
@@ -956,7 +956,7 @@ class XiaoMusic:
|
||||
self.log.info(f"未匹配到指令 {query} {ctrl_panel}")
|
||||
return (None, None)
|
||||
|
||||
def find_real_music_name(self, name, n=100):
|
||||
def find_real_music_name(self, name, n):
|
||||
if not self.config.enable_fuzzy_match:
|
||||
self.log.debug("没开启模糊匹配")
|
||||
return []
|
||||
@@ -1572,7 +1572,9 @@ class XiaoMusicDevice:
|
||||
if exact:
|
||||
names = self.xiaomusic.find_real_music_name(name, n=1)
|
||||
else:
|
||||
names = self.xiaomusic.find_real_music_name(name)
|
||||
names = self.xiaomusic.find_real_music_name(
|
||||
name, n=self.config.search_music_count
|
||||
)
|
||||
if len(names) > 0:
|
||||
if not exact:
|
||||
if len(names) > 1: # 大于一首歌才更新
|
||||
@@ -1659,7 +1661,9 @@ class XiaoMusicDevice:
|
||||
if exact:
|
||||
names = self.xiaomusic.find_real_music_name(name, n=1)
|
||||
else:
|
||||
names = self.xiaomusic.find_real_music_name(name)
|
||||
names = self.xiaomusic.find_real_music_name(
|
||||
name, n=self.config.search_music_count
|
||||
)
|
||||
if len(names) > 0:
|
||||
if not exact:
|
||||
if len(names) > 1: # 大于一首歌才更新
|
||||
@@ -1931,7 +1935,7 @@ class XiaoMusicDevice:
|
||||
# 有 tts command 优先使用 tts command 说话
|
||||
if self.hardware in TTS_COMMAND:
|
||||
tts_cmd = TTS_COMMAND[self.hardware]
|
||||
self.log.debug("Call MiIOService tts.")
|
||||
self.log.info("Call MiIOService tts.")
|
||||
value = value.replace(" ", ",") # 不能有空格
|
||||
await miio_command(
|
||||
self.xiaomusic.miio_service,
|
||||
|
||||
Reference in New Issue
Block a user