mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-06 14:52:50 +08:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af25300917 | ||
|
|
f18b2f49bf | ||
|
|
db1e4e6fc4 | ||
|
|
dc49f63a37 | ||
|
|
6837841872 | ||
|
|
637347ae0c | ||
|
|
ff968c4db4 | ||
|
|
ca547e0d81 | ||
|
|
f0931c447b | ||
|
|
d098b5eb60 | ||
|
|
09111e849d | ||
|
|
49a76dee60 | ||
|
|
637672473e | ||
|
|
e4e1d13b69 | ||
|
|
7736f8c5b4 | ||
|
|
29db69b52f | ||
|
|
37fe51771b | ||
|
|
77ece713dc | ||
|
|
4436cc3a15 |
51
README.md
51
README.md
@@ -11,6 +11,8 @@
|
||||
|
||||
使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。
|
||||
|
||||
<https://github.com/hanxi/xiaomusic>
|
||||
|
||||
## 最简配置运行
|
||||
|
||||
已经支持在 web 页面配置其他参数,docker compose 配置如下:
|
||||
@@ -28,8 +30,22 @@ services:
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_VERBOSE: 'true'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
```
|
||||
|
||||
对应的 docker 启动命令如下:
|
||||
|
||||
```yaml
|
||||
docker run -e MI_USER='小米账号' \
|
||||
-e MI_PASS='小米密码' \
|
||||
-e XIAOMUSIC_VERBOSE='true' \
|
||||
-e XIAOMUSIC_HOSTNAME='docker 主机 ip' \
|
||||
-p 8090:8090 \
|
||||
-v ./music:/app/music \
|
||||
hanxi/xiaomusic
|
||||
```
|
||||
|
||||
启动成功后,在 web 页面可以配置 MI_DID, MI_HARDWARE, XIAOMUSIC_SEARCH, XIAOMUSIC_PROXY 参数。
|
||||
|
||||
如果需要修改 8090 端口为其他端口,比如 5678,需要这样配,3个数字都需要是 5678
|
||||
@@ -46,10 +62,13 @@ services:
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_VERBOSE: 'true'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
XIAOMUSIC_PORT: 5678
|
||||
```
|
||||
|
||||
其中 XIAOMUSIC_VERBOSE 设置为 'true' 时表示开启 debug 日志,遇到问题可以去 web 设置页面底部【下载日志文件】按钮,然后搜索一下日志文件内容确保里面没有账号密码信息后(有就删除这些敏感信息),然后在提 issues 反馈问题时把下载的日志文件带上。
|
||||
|
||||
## 开发环境运行
|
||||
|
||||
- 使用 install_dependencies.sh 下载依赖
|
||||
@@ -87,28 +106,34 @@ pdm run xiaomusic.py
|
||||
## 已测试支持的设备
|
||||
|
||||
```txt
|
||||
- L06A
|
||||
- L07A
|
||||
- S12
|
||||
- S12A
|
||||
- LX5A
|
||||
- LX05
|
||||
- L16A
|
||||
- L17A
|
||||
- LX06
|
||||
- LX01
|
||||
- L05B
|
||||
- L05C
|
||||
````
|
||||
|
||||
型号与产品名称对照可以在这里查询 <https://home.miot-spec.com/s/xiaomi.wifispeaker>
|
||||
|
||||
> 如果你的设备支持播放,请反馈给我添加到支持列表里,谢谢。
|
||||
|
||||
## 支持音乐格式
|
||||
|
||||
- mp3
|
||||
- flac
|
||||
- wav
|
||||
- ape
|
||||
- ogg
|
||||
|
||||
> 本地音乐会搜索 mp3 和 flac 格式的文件,下载的歌曲是 mp3 格式的。
|
||||
|
||||
## 其他参数
|
||||
|
||||
- XIAOMUSIC_ACTIVE_CMD 环境变量,配置成'play,random_play',在非播放状态下,只有这两个指令(播放歌曲和随机播放)可以触发,触发后,xiaomusic进入playing状态,其他指令则可以正常触发。
|
||||
> 本地音乐会搜索目录下上面格式的文件,下载的歌曲是 mp3 格式的。
|
||||
> 已知 L05B L05C 不支持 flac 格式。
|
||||
|
||||
## 在 Docker 里使用
|
||||
|
||||
@@ -199,7 +224,7 @@ services:
|
||||
XIAOMUSIC_HOSTNAME: '192.168.2.5'
|
||||
```
|
||||
|
||||
setting.json 文件不存到 music 可以这样写,会把 setting.json 文件放到容器的 /app/conf 目录且映射到本地的 ./conf 目录:
|
||||
如果想让 setting.json 文件不存储到 music 目录,可以这样配,下面的示例会把 setting.json 文件放到容器的 /app/conf 目录且映射到本地的 ./conf 目录:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
@@ -226,11 +251,14 @@ services:
|
||||
|
||||
- ip 是 XIAOMUSIC_HOSTNAME 设置的
|
||||
- 8090 是默认端口
|
||||
- 新功能
|
||||
- 支持功能
|
||||
- 显示正在播放的歌曲
|
||||
- 模糊搜索本地歌曲
|
||||
- 播放列表
|
||||
- 删除歌曲
|
||||
- 设置页面
|
||||
|
||||
- 配置网络歌单
|
||||
- 日志文件下载
|
||||
|
||||
采用新的设置页面之后,必须在启动前配置的环境变量只剩下:
|
||||
- MI_USER
|
||||
@@ -245,18 +273,19 @@ services:
|
||||
|
||||
## 网络歌单功能
|
||||
|
||||
可以配置一个 json 格式的歌单,支持电台和歌曲,也可以直接用别人分享的链接,具体用法见 <https://github.com/hanxi/xiaomusic/issues/78>
|
||||
可以配置一个 json 格式的歌单,支持电台和歌曲,也可以直接用别人分享的链接,同时配备了 m3u 文件格式转换工具,可以很方便的把 m3u 电台文件转换成网络歌单格式的 json 文件,具体用法见 <https://github.com/hanxi/xiaomusic/issues/78>
|
||||
|
||||
> 欢迎有想法的朋友们制作更多的歌单转换工具。
|
||||
|
||||
## 更多其他可选配置
|
||||
|
||||
- XIAOMUSIC_ACTIVE_CMD 配置唤醒命令,具体见 <https://github.com/hanxi/xiaomusic/pull/43>
|
||||
- XIAOMUSIC_ACTIVE_CMD 环境变量,用于唤醒口令,配置成'play,random_play',在非播放状态下,只有这两个指令(播放歌曲和随机播放)可以触发,触发后,xiaomusic进入playing状态,其他指令则可以正常触发。具体见 <https://github.com/hanxi/xiaomusic/pull/43>
|
||||
- XIAOMUSIC_EXCLUDE_DIRS 配置歌曲目录里需要忽略的目录
|
||||
- XIAOMUSIC_MUSIC_PATH_DEPTH 配置歌曲目录搜索深度,具体见 <https://github.com/hanxi/xiaomusic/issues/76>
|
||||
- XIAOMUSIC_DISABLE_HTTPAUTH 配置成 false 表示开启密码访问web控制台,具体见 <https://github.com/hanxi/xiaomusic/issues/47>
|
||||
- XIAOMUSIC_HTTPAUTH_USERNAME 配置 web 控制台用户
|
||||
- XIAOMUSIC_HTTPAUTH_PASSWORD 配置 web 控制台密码
|
||||
- XIAOMUSIC_CONF_PATH 用来存放配置文件的目录,记得把目录映射到主机,默认情况会把配置存放在music目录,具体见 <https://github.com/hanxi/xiaomusic/issues/74>
|
||||
- XIAOMUSIC_VERBOSE 设置为 true 时开启 debug 日志,用于排查问题
|
||||
- XIAOMUSIC_DISABLE_DOWNLOAD 设为 true 时关闭下载功能,见 <https://github.com/hanxi/xiaomusic/issues/82>
|
||||
- XIAOMUSIC_USE_MUSIC_API 设为 true 时使用 player_play_music 接口播放音乐,用于兼容不能播放的型号
|
||||
- XIAOMUSIC_KEYWORDS_PLAY 用来播放歌曲的口令前缀,默认是 "播放歌曲,放歌曲" ,可以用英文逗号分割配置多个
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.1.74"
|
||||
version = "0.1.77"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.1.74"
|
||||
__version__ = "0.1.77"
|
||||
|
||||
@@ -61,7 +61,9 @@ class Config:
|
||||
"XIAOMUSIC_SEARCH", "ytsearch:"
|
||||
) # "bilisearch:" or "ytsearch:"
|
||||
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
|
||||
active_cmd: str = os.getenv("XIAOMUSIC_ACTIVE_CMD", "play,random_play,playlocal,play_music_list")
|
||||
active_cmd: str = os.getenv(
|
||||
"XIAOMUSIC_ACTIVE_CMD", "play,random_play,playlocal,play_music_list,stop"
|
||||
)
|
||||
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir")
|
||||
music_path_depth: int = int(os.getenv("XIAOMUSIC_MUSIC_PATH_DEPTH", "10"))
|
||||
disable_httpauth: bool = (
|
||||
@@ -80,6 +82,12 @@ class Config:
|
||||
os.getenv("XIAOMUSIC_USE_MUSIC_API", "false").lower() == "true"
|
||||
)
|
||||
log_file: str = os.getenv("XIAOMUSIC_MUSIC_LOG_FILE", "/tmp/xiaomusic.txt")
|
||||
# 模糊搜索匹配的最低相似度阈值
|
||||
fuzzy_match_cutoff: float = float(os.getenv("XIAOMUSIC_FUZZY_MATCH_CUTOFF", "0.6"))
|
||||
# 开启模糊搜索
|
||||
enable_fuzzy_match: bool = (
|
||||
os.getenv("XIAOMUSIC_ENABLE_FUZZY_MATCH", "true").lower() == "true"
|
||||
)
|
||||
|
||||
def append_keyword(self, keys, action):
|
||||
for key in keys.split(","):
|
||||
|
||||
@@ -3,6 +3,7 @@ SUPPORT_MUSIC_TYPE = [
|
||||
".flac",
|
||||
".wav",
|
||||
".ape",
|
||||
".ogg",
|
||||
]
|
||||
|
||||
LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation?source=dialogu&hardware={hardware}×tamp={timestamp}&limit=2"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import os
|
||||
from threading import Thread
|
||||
|
||||
from flask import Flask, request, send_from_directory, send_file
|
||||
from flask import Flask, request, send_file, send_from_directory
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from waitress import serve
|
||||
|
||||
@@ -162,11 +162,21 @@ def downloadjson():
|
||||
"content": content,
|
||||
}
|
||||
|
||||
|
||||
@app.route("/downloadlog", methods=["GET"])
|
||||
@auth.login_required
|
||||
def downloadlog():
|
||||
return send_file(xiaomusic.config.log_file, as_attachment=True)
|
||||
|
||||
|
||||
@app.route("/playurl", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def playurl():
|
||||
url = request.args.get("url")
|
||||
log.info(f"play_url:{url}")
|
||||
return await xiaomusic.call_main_thread_function(xiaomusic.play_url, arg1=url)
|
||||
|
||||
|
||||
def static_path_handler(filename):
|
||||
log.debug(filename)
|
||||
log.debug(static_path)
|
||||
|
||||
@@ -82,6 +82,13 @@ $(function(){
|
||||
}
|
||||
});
|
||||
|
||||
$("#playurl").on("click", () => {
|
||||
var url = $("#music-url").val();
|
||||
$.get(`/playurl?url=${url}`, function(data, status) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
|
||||
function append_op_button_name(name) {
|
||||
append_op_button(name, name);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,12 @@
|
||||
<button id="play_music_list">播放列表歌曲</button>
|
||||
<button id="del_music">删除选中歌曲</button>
|
||||
|
||||
<hr>
|
||||
<div>
|
||||
<input id="music-url" type="text" placeholder="链接(http://ngcdn001.cnr.cn/live/zgzs/index.m3u8)"></input>
|
||||
</div>
|
||||
<button id="playurl">播放链接</button>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
<button onclick="location.href='/';">返回首页</button>
|
||||
<button id="get_music_list">获取歌单</button>
|
||||
<button id="save">保存</button>
|
||||
<a class="button" href="/downloadlog" download="xiaomusic.txt">下载日志文件</a>
|
||||
<hr>
|
||||
|
||||
<a href="/static/m3u.html" target="_blank">m3u文件转换工具</a>
|
||||
<a href="/downloadlog" download="xiaomusic.txt">下载日志文件</a>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
button {
|
||||
.button {
|
||||
line-height: 50px;
|
||||
font-size: 14px;
|
||||
}
|
||||
button, .button {
|
||||
margin: 10px;
|
||||
width: 100px;
|
||||
height: 50px;
|
||||
@@ -10,7 +14,7 @@ button {
|
||||
border-radius: 10px;
|
||||
background-color: #008CBA;
|
||||
}
|
||||
button:active {
|
||||
button:active, .button:active {
|
||||
font-weight:bold;
|
||||
background-color: #007CBA;
|
||||
transform: translateY(2px);
|
||||
|
||||
@@ -72,7 +72,12 @@ def validate_proxy(proxy_str: str) -> bool:
|
||||
|
||||
# 模糊搜索
|
||||
def fuzzyfinder(user_input, collection):
|
||||
return difflib.get_close_matches(user_input, collection, 10, cutoff=0.1)
|
||||
return difflib.get_close_matches(user_input, collection, n=10, cutoff=0.1)
|
||||
|
||||
|
||||
def find_best_match(user_input, collection, cutoff=0.6):
|
||||
matches = difflib.get_close_matches(user_input, collection, n=1, cutoff=cutoff)
|
||||
return matches[0] if matches else None
|
||||
|
||||
|
||||
# 歌曲排序
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
import asyncio
|
||||
import copy
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
@@ -9,10 +10,9 @@ import re
|
||||
import time
|
||||
import traceback
|
||||
import urllib.parse
|
||||
from pathlib import Path
|
||||
import copy
|
||||
|
||||
from logging.handlers import RotatingFileHandler
|
||||
from pathlib import Path
|
||||
|
||||
from aiohttp import ClientSession, ClientTimeout
|
||||
from miservice import MiAccount, MiIOService, MiNAService
|
||||
|
||||
@@ -31,6 +31,7 @@ from xiaomusic.const import (
|
||||
from xiaomusic.httpserver import StartHTTPServer
|
||||
from xiaomusic.utils import (
|
||||
custom_sort_key,
|
||||
find_best_match,
|
||||
fuzzyfinder,
|
||||
get_local_music_duration,
|
||||
get_random,
|
||||
@@ -117,15 +118,17 @@ class XiaoMusic:
|
||||
os.makedirs(log_path)
|
||||
if os.path.exists(log_file):
|
||||
os.remove(log_file)
|
||||
handler = RotatingFileHandler(self.config.log_file, maxBytes=10*1024*1024, backupCount=1)
|
||||
handler = RotatingFileHandler(
|
||||
self.config.log_file, maxBytes=10 * 1024 * 1024, backupCount=1
|
||||
)
|
||||
self.log = logging.getLogger("xiaomusic")
|
||||
self.log.addHandler(handler)
|
||||
self.log.setLevel(logging.DEBUG if self.config.verbose else logging.INFO)
|
||||
debug_config = copy.deepcopy(self.config)
|
||||
debug_config.account = '******'
|
||||
debug_config.password = '******'
|
||||
debug_config.httpauth_username = '******'
|
||||
debug_config.httpauth_password = '******'
|
||||
debug_config.account = "******"
|
||||
debug_config.password = "******"
|
||||
debug_config.httpauth_username = "******"
|
||||
debug_config.httpauth_password = "******"
|
||||
self.log.info(debug_config)
|
||||
|
||||
async def poll_latest_ask(self):
|
||||
@@ -287,10 +290,13 @@ class XiaoMusic:
|
||||
await self.mina_service.text_to_speech(self.device_id, value)
|
||||
except Exception as e:
|
||||
self.log.error(f"Execption {e}")
|
||||
|
||||
# 最大等8秒
|
||||
sec = min(8, int(len(value) / 3.3))
|
||||
await asyncio.sleep(sec)
|
||||
self.log.debug(f"do_tts. cur_music:{self.cur_music}")
|
||||
if self._playing and not self.is_downloading():
|
||||
# 继续播放歌曲
|
||||
self.log.info("继续播放歌曲")
|
||||
await self.play()
|
||||
|
||||
async def do_set_volume(self, value):
|
||||
@@ -303,7 +309,10 @@ class XiaoMusic:
|
||||
self.log.error(f"Execption {e}")
|
||||
|
||||
async def force_stop_xiaoai(self):
|
||||
await self.mina_service.player_stop(self.device_id)
|
||||
ret = await self.mina_service.player_pause(self.device_id)
|
||||
self.log.debug(f"force_stop_xiaoai player_pause ret:{ret}")
|
||||
ret = await self.mina_service.player_stop(self.device_id)
|
||||
self.log.debug(f"force_stop_xiaoai player_stop ret:{ret}")
|
||||
|
||||
# 是否在下载中
|
||||
def is_downloading(self):
|
||||
@@ -587,7 +596,7 @@ class XiaoMusic:
|
||||
self.polling_event.clear() # stop polling when processing the question
|
||||
query = new_record.get("query", "").strip()
|
||||
ctrl_panel = new_record.get("ctrl_panel", False)
|
||||
self.log.debug("收到消息:%s 控制面板:%s", query, ctrl_panel)
|
||||
self.log.info("收到消息:%s 控制面板:%s", query, ctrl_panel)
|
||||
|
||||
# 匹配命令
|
||||
opvalue, oparg = self.match_cmd(query, ctrl_panel)
|
||||
@@ -633,7 +642,7 @@ class XiaoMusic:
|
||||
return (opvalue, oparg)
|
||||
if self._playing:
|
||||
self.log.info("未匹配到指令,自动停止")
|
||||
return ("stop", {})
|
||||
return ("stop", "notts")
|
||||
return (None, None)
|
||||
|
||||
# 判断是否播放下一首歌曲
|
||||
@@ -667,7 +676,8 @@ class XiaoMusic:
|
||||
{"startaudioid": audio_id, "music": json.dumps(music)},
|
||||
)
|
||||
|
||||
async def play_url(self, url):
|
||||
async def play_url(self, **kwargs):
|
||||
url = kwargs.get("arg1", "")
|
||||
if self.config.use_music_api:
|
||||
ret = await self._play_by_music_url(self.device_id, url)
|
||||
self.log.debug(
|
||||
@@ -678,6 +688,21 @@ class XiaoMusic:
|
||||
self.log.debug(
|
||||
f"play_url play_by_url {self.config.hardware}. ret:{ret} url:{url}"
|
||||
)
|
||||
return ret
|
||||
|
||||
def find_real_music_name(self, name):
|
||||
if not self.config.enable_fuzzy_match:
|
||||
self.log.debug("没开启模糊匹配")
|
||||
return name
|
||||
|
||||
all_music_list = list(self._all_music.keys())
|
||||
real_name = find_best_match(
|
||||
name, all_music_list, cutoff=self.config.fuzzy_match_cutoff
|
||||
)
|
||||
if real_name:
|
||||
self.log.info(f"根据【{name}】找到歌曲【{real_name}】")
|
||||
return real_name
|
||||
self.log.info(f"没找到歌曲【{name}】")
|
||||
|
||||
# 播放本地歌曲
|
||||
async def playlocal(self, **kwargs):
|
||||
@@ -692,6 +717,7 @@ class XiaoMusic:
|
||||
self.log.info(f"playlocal. name:{name}")
|
||||
|
||||
# 本地歌曲不存在时下载
|
||||
name = self.find_real_music_name(name)
|
||||
if not self.is_music_exist(name):
|
||||
await self.do_tts(f"本地不存在歌曲{name}")
|
||||
return
|
||||
@@ -704,7 +730,7 @@ class XiaoMusic:
|
||||
sec, url = await self.get_music_sec_url(name)
|
||||
self.log.info(f"播放 {url}")
|
||||
await self.force_stop_xiaoai()
|
||||
await self.play_url(url)
|
||||
await self.play_url(arg1=url)
|
||||
self.log.info("已经开始播放了")
|
||||
# 设置下一首歌曲的播放定时器
|
||||
await self.set_next_music_timeout(sec)
|
||||
@@ -727,6 +753,7 @@ class XiaoMusic:
|
||||
self.log.info("play. search_key:%s name:%s", search_key, name)
|
||||
|
||||
# 本地歌曲不存在时下载
|
||||
name = self.find_real_music_name(name)
|
||||
if not self.is_music_exist(name):
|
||||
if self.config.disable_download:
|
||||
await self.do_tts(f"本地不存在歌曲{name}")
|
||||
@@ -788,10 +815,26 @@ class XiaoMusic:
|
||||
self.log.error(f"del ${filename} failed")
|
||||
self._gen_all_music_list()
|
||||
|
||||
def find_real_music_list_name(self, list_name):
|
||||
if not self.config.enable_fuzzy_match:
|
||||
self.log.debug("没开启模糊匹配")
|
||||
return list_name
|
||||
|
||||
# 模糊搜一个播放列表
|
||||
real_name = find_best_match(
|
||||
list_name, self._music_list, cutoff=self.config.fuzzy_match_cutoff
|
||||
)
|
||||
if real_name:
|
||||
self.log.info(f"根据【{list_name}】找到播放列表【{real_name}】")
|
||||
list_name = real_name
|
||||
self.log.info(f"没找到播放列表【{list_name}】")
|
||||
|
||||
# 播放一个播放列表
|
||||
async def play_music_list(self, **kwargs):
|
||||
parts = kwargs.get("arg1").split("|")
|
||||
list_name = parts[0]
|
||||
|
||||
list_name = self.find_real_music_list_name(list_name)
|
||||
if list_name not in self._music_list:
|
||||
await self.do_tts(f"播放列表{list_name}不存在")
|
||||
return
|
||||
@@ -809,6 +852,8 @@ class XiaoMusic:
|
||||
|
||||
async def stop(self, **kwargs):
|
||||
self._playing = False
|
||||
if kwargs.get("arg1", "") != "notts":
|
||||
await self.do_tts("收到关机口令,再见")
|
||||
if self._next_timer:
|
||||
self._next_timer.cancel()
|
||||
self.log.info("定时器已取消")
|
||||
@@ -823,12 +868,12 @@ class XiaoMusic:
|
||||
async def _do_stop():
|
||||
await asyncio.sleep(minute * 60)
|
||||
try:
|
||||
await self.stop()
|
||||
await self.stop(arg1="notts")
|
||||
except Exception as e:
|
||||
self.log.warning(f"执行出错 {str(e)}\n{traceback.format_exc()}")
|
||||
|
||||
self._stop_timer = asyncio.ensure_future(_do_stop())
|
||||
self.log.info(f"{minute}分钟后将关机")
|
||||
await self.do_tts(f"收到,{minute}分钟后将关机")
|
||||
|
||||
async def set_volume(self, **kwargs):
|
||||
value = kwargs.get("arg1", 0)
|
||||
@@ -838,7 +883,7 @@ class XiaoMusic:
|
||||
playing_info = await self.mina_service.player_get_status(self.device_id)
|
||||
self.log.debug("get_volume. playing_info:%s", playing_info)
|
||||
self._volume = json.loads(playing_info.get("data", {}).get("info", "{}")).get(
|
||||
"volume", 5
|
||||
"volume", 0
|
||||
)
|
||||
self.log.info("get_volume. volume:%s", self._volume)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user