1
0
mirror of https://github.com/hanxi/xiaomusic.git synced 2025-12-14 16:08:14 +08:00

Compare commits

...

56 Commits

Author SHA1 Message Date
涵曦
76aeb20268 new version v0.1.26 2024-05-08 14:15:15 +00:00
涵曦
de36ff7d24 默认允许播放歌曲和随机播放唤醒 2024-05-08 14:15:10 +00:00
涵曦
4b5d5b3a0a Update README.md 2024-05-07 07:22:37 +08:00
涵曦
59f150ebbd Update README.md 2024-05-07 07:21:28 +08:00
涵曦
4e2d39abac new version v0.1.25 2024-05-06 10:54:43 +00:00
涵曦
a35cde5d4a Merge pull request #43 from ominkk/main
可配置xiaomuisc激活指令,其他指令需要激活后才能使用
2024-05-02 00:21:05 +08:00
lv99
bbdf41f334 可配置xiaomuisc激活指令,其他指令需要激活后才能使用 2024-05-01 09:35:14 +08:00
涵曦
529aedede0 update readme 2024-04-30 14:04:58 +00:00
涵曦
55eaa6e751 new version v0.1.24 2024-04-30 13:52:20 +00:00
涵曦
ca59e594b4 歌名不换行 2024-04-30 13:52:16 +00:00
涵曦
836fde01b7 new version v0.1.23 2024-04-30 13:48:35 +00:00
涵曦
050ded6b2e 新增显示当前正在播放的音乐 2024-04-30 13:47:45 +00:00
涵曦
b9e1abff6b new version v0.1.22 2024-04-30 12:48:10 +00:00
涵曦
f962fcaa99 新增本地音乐模糊搜索 2024-04-30 12:47:57 +00:00
涵曦
eb35da595f Update README.md 2024-04-29 22:47:54 +08:00
涵曦
26a8b2412f new version v0.1.21 2024-04-08 07:48:02 +08:00
涵曦
601bff4404 修改input显示宽度 2024-04-08 07:47:57 +08:00
涵曦
1fadc9a479 new version v0.1.20 2024-04-08 07:41:16 +08:00
涵曦
69e53569ca 处理空值问题 2024-04-08 07:41:07 +08:00
涵曦
49a43fb997 new version v0.1.19 2024-04-04 20:41:15 +08:00
涵曦
5145ae399d Merge pull request #33 from zhanggaolei001/main
将搜索词分为搜索词及文件名两部分,便于更精确搜索以及实现保存下载保存文件名的自定义
2024-04-03 23:16:44 +08:00
张高磊
612eb636be 将搜索词分为搜索词及文件名两部分,便于更精确搜索以及实现保存下载保存文件名的自定义 2024-04-03 14:12:26 +08:00
涵曦
657af667ef Update README.md 2024-03-18 16:07:50 +08:00
涵曦
9541071c3a new version v0.1.18 2024-02-24 13:26:52 +08:00
涵曦
dfc78b6af5 new version script 2024-02-24 13:26:33 +08:00
涵曦
bea7b2d4eb new version v 2024-02-24 13:23:10 +08:00
涵曦
ddb3e9e03b newversion script 2024-02-24 13:23:03 +08:00
涵曦
812965f054 new version script 2024-02-24 13:22:12 +08:00
涵曦
006ea2d283 new version v0.1.16 2024-02-24 13:08:35 +08:00
涵曦
08a22ca03f 命令行支持 ffmpeg 路径参数 #15 2024-02-24 13:05:36 +08:00
涵曦
7a32917b63 启动时生成一次播放列表,修复下一首越界判断问题 2024-02-24 12:58:01 +08:00
涵曦
54b4417069 支持配置 ffmpeg 路径 #15 2024-02-24 12:49:17 +08:00
涵曦
17d7f54c20 歌曲目录支持子目录,优化随机播放列表 #18 2024-02-24 12:41:26 +08:00
涵曦
2261b5ba53 add ci docker 2024-02-04 14:11:40 +08:00
涵曦
833cb1a24a open debug log 2024-02-04 14:04:18 +08:00
涵曦
4494b54c15 new version v0.1.15 2024-02-03 14:51:14 +08:00
涵曦
594db5aa0c update requirements 2024-02-03 14:51:03 +08:00
涵曦
15966df548 new version v0.1.14 2024-02-03 14:24:16 +08:00
涵曦
6914dca9dc 更新 yt-dlp 版本,修复哔哩哔哩下载问题 2024-02-03 08:26:40 +08:00
涵曦
cbfb5e9531 Update README.md 2024-02-02 22:33:18 +08:00
涵曦
e6c98dd3f3 Update README.md 2024-02-02 22:24:12 +08:00
涵曦
c68fa71d24 new version v0.1.13 2024-02-02 22:11:54 +08:00
涵曦
24b46729e3 优化控制面板,声音设置改为进度条 2024-02-02 22:10:55 +08:00
涵曦
13336cd02c 支持配置歌曲下载源 #12 2024-02-02 20:56:18 +08:00
涵曦
67be9125d8 Update README.md 2024-02-01 23:40:30 +08:00
涵曦
1b0a6dd7f4 Update README.md 2024-01-31 09:17:13 +08:00
涵曦
11053ecfa7 Update README.md 2024-01-31 09:03:38 +08:00
涵曦
0736cb0fb7 new version v0.1.12 2024-01-30 08:21:48 +08:00
涵曦
2acb668101 fix: set volume failed 2024-01-30 08:21:31 +08:00
涵曦
32fb0e9548 add script to update version 2024-01-29 23:28:31 +08:00
涵曦
c69f8e4e65 new version v0.1.11 2024-01-29 23:27:59 +08:00
涵曦
42f91f6ab4 add script to update version 2024-01-29 23:25:42 +08:00
涵曦
f615f21773 new version v0.1.10 2024-01-29 23:24:07 +08:00
涵曦
cad7b53aa4 新增设置声音按钮 2024-01-29 23:10:16 +08:00
涵曦
714cae9bd1 update version 2024-01-28 19:15:08 +08:00
涵曦
15036c3755 fix: arg1 漏修改 2024-01-28 19:14:48 +08:00
14 changed files with 736 additions and 298 deletions

30
.github/workflows/ci.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: ci
on:
push:
branches: [ main ]
workflow_dispatch:
jobs:
build-image:
runs-on: ubuntu-latest
# run unless event type is pull_request
if: github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}

4
.gitignore vendored
View File

@@ -160,3 +160,7 @@ cython_debug/
# and can be added to the global gitignore or merged into this file. For a more nuclear # and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder. # option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/ #.idea/
ffmpeg
music
test.sh

View File

@@ -1,6 +1,6 @@
# xiaomusic # xiaomusic
使用小爱同学播放音乐,音乐使用 yt-dlp 下载。 使用小爱/红米音箱播放音乐,音乐使用 yt-dlp 下载。
## 运行 ## 运行
@@ -12,6 +12,7 @@
export MI_USER="xxxxx" export MI_USER="xxxxx"
export MI_PASS="xxxx" export MI_PASS="xxxx"
export MI_DID=00000 export MI_DID=00000
export XIAOMUSIC_SEARCH='bilisearch:'
``` ```
然后启动即可。默认监听了端口 8090 , 使用其他端口自行修改。 然后启动即可。默认监听了端口 8090 , 使用其他端口自行修改。
@@ -28,6 +29,8 @@ pdm run xiaomusic.py
- 单曲循环 - 单曲循环
- 全部循环 - 全部循环
> 隐藏玩法: 对小爱同学说播放歌曲小猪佩奇的故事,会播放小猪佩奇的故事。
## 已测试设备 ## 已测试设备
```txt ```txt
@@ -40,16 +43,33 @@ pdm run xiaomusic.py
> 本地音乐会搜索 mp3 和 flac 格式的文件,下载的歌曲是 mp3 格式的。 > 本地音乐会搜索 mp3 和 flac 格式的文件,下载的歌曲是 mp3 格式的。
## 其他参数
- XIAOMUSIC_ACTIVE_CMD 环境变量,配置成'play,random_play'在非播放状态下只有这两个指令播放歌曲和随机播放可以触发触发后xiaomusic进入playing状态其他指令则可以正常触发。
## 在 Docker 里使用 ## 在 Docker 里使用
```shell ```shell
docker run -e MI_USER=<your-xiaomi-account> -e MI_PASS=<your-xiaomi-password> -e MI_DID=<your-xiaomi-speaker-mid> -e MI_HARDWARE='L07A' -e XIAOMUSIC_PROXY=<proxy-for-yt-dlp> -e XIAOMUSIC_HOSTNAME=192.168.2.5 -p 8090:8090 -v ./music:/app/music hanxi/xiaomusic docker run -e MI_USER=<your-xiaomi-account> -e MI_PASS=<your-xiaomi-password> -e MI_DID=<your-xiaomi-speaker-mid> -e MI_HARDWARE='L07A' -e XIAOMUSIC_PROXY=<proxy-for-yt-dlp> -e XIAOMUSIC_HOSTNAME=192.168.2.5 -e XIAOMUSIC_SEARCH='bilisearch:' -p 8090:8090 -v ./music:/app/music hanxi/xiaomusic
```
- XIAOMUSIC_SEARCH 可以配置为 'bilisearch:' 表示歌曲从哔哩哔哩下载;
- 配置为 'ytsearch:' 表示歌曲从 youtube 下载。
- XIAOMUSIC_PROXY 用于配置代理,默认为空;
- 当 XIAOMUSIC_SEARCH 配置为 'ytsearch:' 时在国内需要用到。
- MI_HARDWARE 是小米音箱的型号,默认为'L07A'
- 注意端口必须映射为与容器内一致, XIAOMUSIC_HOSTNAME 需要设置为宿主机的 IP 地址,否则小爱无法正常播放。
- 可以把 /app/music 目录映射到本地,用于保存下载的歌曲。
XIAOMUSIC_PROXY 参数格式参考 yt-dlp 文档说明:
```
Use the specified HTTP/HTTPS/SOCKS proxy. To
enable SOCKS proxy, specify a proper scheme,
e.g. socks5://user:pass@127.0.0.1:1080/.
Pass in an empty string (--proxy "") for
direct connection
``` ```
- XIAOMUSIC_PROXY 用于配置代理默认为空yt-dlp 工具下载歌曲会用到。 见 <https://github.com/hanxi/xiaomusic/issues/2> 和 <https://github.com/hanxi/xiaomusic/issues/11>
- MI_HARDWARE 是小米音箱的型号,默认为'L07A'
- 注意端口必须映射为与容器内一致XIAOMUSIC_HOSTNAME 需要设置为宿主机的 IP 地址,否则小爱无法正常播放。
- 可以把 /app/music 目录映射到本地,用于保存下载的歌曲。
### 本地编译Docker Image ### 本地编译Docker Image
@@ -57,17 +77,77 @@ docker run -e MI_USER=<your-xiaomi-account> -e MI_PASS=<your-xiaomi-password> -e
docker build -t xiaomusic . docker build -t xiaomusic .
``` ```
### docker compose 示例
使用哔哩哔哩下载歌曲:
```yaml
version: '3'
services:
xiaomusic:
image: hanxi/xiaomusic
container_name: xiaomusic
restart: unless-stopped
ports:
- 8090:8090
volumes:
- ./music:/app/music
environment:
MI_USER: '小米账号'
MI_PASS: '小米密码'
MI_DID: 00000
MI_HARDWARE: 'L07A'
XIAOMUSIC_SEARCH: 'bilisearch:'
XIAOMUSIC_HOSTNAME: '192.168.2.5'
```
使用 youtobe 下载歌曲:
```yaml
version: '3'
services:
xiaomusic:
image: hanxi/xiaomusic
container_name: xiaomusic
restart: unless-stopped
ports:
- 8090:8090
volumes:
- ./music:/app/music
environment:
MI_USER: '小米账号'
MI_PASS: '小米密码'
MI_DID: 00000
MI_HARDWARE: 'L07A'
XIAOMUSIC_SEARCH: 'ytsearch:'
XIAOMUSIC_PROXY: 'http://192.168.2.5:8080'
XIAOMUSIC_HOSTNAME: '192.168.2.5'
```
## 简易的控制面板 ## 简易的控制面板
浏览器进入 <http://192.168.2.5:8090> 浏览器进入 <http://192.168.2.5:8090>
- ip 是 XIAOMUSIC_HOSTNAME 设置的 - ip 是 XIAOMUSIC_HOSTNAME 设置的
- 8090 是默认端口 - 8090 是默认端口
- 新功能
- 显示正在播放的歌曲
- 模糊搜索本地歌曲
## 感谢 ## 感谢
- [xiaomi](https://www.mi.com/) - [xiaomi](https://www.mi.com/)
- [PDM](https://pdm.fming.dev/latest/) - [PDM](https://pdm.fming.dev/latest/)
- [xiaogpt](https://github.com/yihong0618/xiaogpt) - [xiaogpt](https://github.com/yihong0618/xiaogpt)
- [MiService](https://github.com/yihong0618/MiService)
- [yt-dlp](https://github.com/yt-dlp/yt-dlp) - [yt-dlp](https://github.com/yt-dlp/yt-dlp)
- [NAS部署教程](https://post.m.smzdm.com/p/avpe7n99/)
- [群晖部署教程](https://post.m.smzdm.com/p/a7px7dol/)
## Star History
[![Star History Chart](https://api.star-history.com/svg?repos=hanxi/xiaomusic&type=Date)](https://star-history.com/#hanxi/xiaomusic&Date)

34
newversion.sh Executable file
View File

@@ -0,0 +1,34 @@
#!/bin/bash
set -e
version_file=./pyproject.toml
# 获取当前版本号
current_version=$(grep -oE "version = \"[0-9]+\.[0-9]+\.[0-9]+\"" $version_file | cut -d'"' -f2)
echo "当前版本号: "$current_version
# 将版本号分割成三部分
major=$(echo $current_version | cut -d'.' -f1)
minor=$(echo $current_version | cut -d'.' -f2)
patch=$(echo $current_version | cut -d'.' -f3)
echo "major: $major"
echo "minor: $minor"
echo "patch: $patch"
# 将补丁号加1
patch=$((patch + 1))
# 生成新版本号
new_version="$major.$minor.$patch"
# 将新版本号写入文件
sed -i "s/version.*/version = \"$new_version\"/g" $version_file
echo "新版本号:$new_version"
git diff
git add $version_file
git commit -m "new version v$new_version"
git tag v$new_version
git push -u origin main --tags

208
pdm.lock generated
View File

@@ -6,54 +6,68 @@ groups = ["default"]
cross_platform = true cross_platform = true
static_urls = false static_urls = false
lock_version = "4.3" lock_version = "4.3"
content_hash = "sha256:091ebbfd2c575745f3dae0440e7aaa775c6e2121050f4c101b0676a0bcef7606" content_hash = "sha256:d21199e11013c9db9343d7868f7f582ff85a6c8ad29b3f5caca7ce7fe669b841"
[[package]] [[package]]
name = "aiohttp" name = "aiohttp"
version = "3.8.6" version = "3.9.3"
requires_python = ">=3.6" requires_python = ">=3.8"
summary = "Async http client/server framework (asyncio)" summary = "Async http client/server framework (asyncio)"
dependencies = [ dependencies = [
"aiosignal>=1.1.2", "aiosignal>=1.1.2",
"async-timeout<5.0,>=4.0.0a3", "async-timeout<5.0,>=4.0; python_version < \"3.11\"",
"attrs>=17.3.0", "attrs>=17.3.0",
"charset-normalizer<4.0,>=2.0",
"frozenlist>=1.1.1", "frozenlist>=1.1.1",
"multidict<7.0,>=4.5", "multidict<7.0,>=4.5",
"yarl<2.0,>=1.0", "yarl<2.0,>=1.0",
] ]
files = [ files = [
{file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1"}, {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"},
{file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566"}, {file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"},
{file = "aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e"}, {file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096"}, {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22"}, {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93"}, {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47"}, {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543"}, {file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965"}, {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5"}, {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d"}, {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2"}, {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed"}, {file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"},
{file = "aiohttp-3.8.6-cp310-cp310-win32.whl", hash = "sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2"}, {file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"},
{file = "aiohttp-3.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865"}, {file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"},
{file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34"}, {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"},
{file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca"}, {file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"},
{file = "aiohttp-3.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321"}, {file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9"}, {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad"}, {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358"}, {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d"}, {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403"}, {file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a"}, {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8"}, {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684"}, {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887"}, {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f"}, {file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"},
{file = "aiohttp-3.8.6-cp311-cp311-win32.whl", hash = "sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb"}, {file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"},
{file = "aiohttp-3.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0"}, {file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"},
{file = "aiohttp-3.8.6.tar.gz", hash = "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"}, {file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60"},
{file = "aiohttp-3.9.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869"},
{file = "aiohttp-3.9.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679"},
{file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96"},
{file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d"},
{file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11"},
{file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53"},
{file = "aiohttp-3.9.3-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5"},
{file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca"},
{file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1"},
{file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5"},
{file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6"},
{file = "aiohttp-3.9.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f"},
{file = "aiohttp-3.9.3-cp312-cp312-win32.whl", hash = "sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38"},
{file = "aiohttp-3.9.3-cp312-cp312-win_amd64.whl", hash = "sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5"},
{file = "aiohttp-3.9.3.tar.gz", hash = "sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7"},
] ]
[[package]] [[package]]
@@ -494,15 +508,16 @@ files = [
[[package]] [[package]]
name = "miservice-fork" name = "miservice-fork"
version = "2.2.1" version = "2.3.2"
requires_python = ">=3.7" requires_python = ">=3.7"
summary = "XiaoMi Cloud Service fork from https://github.com/Yonsm/MiService" summary = "XiaoMi Cloud Service fork from https://github.com/Yonsm/MiService"
dependencies = [ dependencies = [
"aiohttp", "aiohttp",
"mutagen",
] ]
files = [ files = [
{file = "miservice_fork-2.2.1-py3-none-any.whl", hash = "sha256:cf8f3e30b3008de29a69d9a8293cca8428e670ae10a0f791840428ee947fc27e"}, {file = "miservice_fork-2.3.2-py3-none-any.whl", hash = "sha256:f24c40366df99d5db706f09528692bc490390fe7db950aa32f4948bafdc1a03d"},
{file = "miservice_fork-2.2.1.tar.gz", hash = "sha256:f3f742ccd7cb4a1ed22cfdf95da14f791eff0c6c3a54032dcfe445ae540664df"}, {file = "miservice_fork-2.3.2.tar.gz", hash = "sha256:1c907289cd354c349ead5e5b1f08e22aa23b8fa01114ecc7a2800e463751ba5b"},
] ]
[[package]] [[package]]
@@ -621,7 +636,7 @@ files = [
[[package]] [[package]]
name = "rich" name = "rich"
version = "13.6.0" version = "13.7.0"
requires_python = ">=3.7.0" requires_python = ">=3.7.0"
summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
dependencies = [ dependencies = [
@@ -629,8 +644,8 @@ dependencies = [
"pygments<3.0.0,>=2.13.0", "pygments<3.0.0,>=2.13.0",
] ]
files = [ files = [
{file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"}, {file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"},
{file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"}, {file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"},
] ]
[[package]] [[package]]
@@ -655,49 +670,60 @@ files = [
[[package]] [[package]]
name = "websockets" name = "websockets"
version = "11.0.3" version = "12.0"
requires_python = ">=3.7" requires_python = ">=3.8"
summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
files = [ files = [
{file = "websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac"}, {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"},
{file = "websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d"}, {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"},
{file = "websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f"}, {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"},
{file = "websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564"}, {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"},
{file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11"}, {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"},
{file = "websockets-11.0.3-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca"}, {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"},
{file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54"}, {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"},
{file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4"}, {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"},
{file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526"}, {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"},
{file = "websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69"}, {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"},
{file = "websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f"}, {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"},
{file = "websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb"}, {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"},
{file = "websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288"}, {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"},
{file = "websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d"}, {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"},
{file = "websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3"}, {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"},
{file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b"}, {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"},
{file = "websockets-11.0.3-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6"}, {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"},
{file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97"}, {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"},
{file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf"}, {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"},
{file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd"}, {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"},
{file = "websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c"}, {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"},
{file = "websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8"}, {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf"}, {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5"}, {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998"}, {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b"}, {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb"}, {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20"}, {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931"}, {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9"}, {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280"}, {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b"}, {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82"}, {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c"}, {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d"}, {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4"}, {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602"}, {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"},
{file = "websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6"}, {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"},
{file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"}, {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"},
{file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"},
{file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"},
{file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"},
{file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"},
{file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"},
{file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"},
{file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"},
{file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"},
{file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"},
{file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"},
{file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"},
] ]
[[package]] [[package]]
@@ -758,18 +784,20 @@ files = [
[[package]] [[package]]
name = "yt-dlp" name = "yt-dlp"
version = "2023.10.13" version = "2024.2.2.232707.dev0"
requires_python = ">=3.7" requires_python = ">=3.8"
summary = "A youtube-dl fork with additional features and patches" summary = "A youtube-dl fork with additional features and patches"
dependencies = [ dependencies = [
"brotli; platform_python_implementation == \"CPython\"", "brotli; implementation_name == \"cpython\"",
"brotlicffi; platform_python_implementation != \"CPython\"", "brotlicffi; implementation_name != \"cpython\"",
"certifi", "certifi",
"mutagen", "mutagen",
"pycryptodomex", "pycryptodomex",
"websockets", "requests<3,>=2.31.0",
"urllib3<3,>=1.26.17",
"websockets>=12.0",
] ]
files = [ files = [
{file = "yt-dlp-2023.10.13.tar.gz", hash = "sha256:e026ea1c435ff36eef1215bc4c5bb8c479938b90054997ba99f63a4541fe63b4"}, {file = "yt-dlp-2024.2.2.232707.dev0.tar.gz", hash = "sha256:fd8d85f64842038cbdaaf7ee5812d98beed64fdcb4612f6e80b2c721bad13262"},
{file = "yt_dlp-2023.10.13-py2.py3-none-any.whl", hash = "sha256:2b069f22675532eebacdfd6372b1825651a751fef848de9ae6efe6491b2dc38a"}, {file = "yt_dlp-2024.2.2.232707.dev0-py2.py3-none-any.whl", hash = "sha256:7ff05434979d89e2a7c344d6771cc60229901fe4182c19a756472bb49a50e3b8"},
] ]

View File

@@ -1,6 +1,6 @@
[project] [project]
name = "xiaomusic" name = "xiaomusic"
version = "0.1.8" version = "0.1.26"
description = "Play Music with xiaomi AI speaker" description = "Play Music with xiaomi AI speaker"
authors = [ authors = [
{name = "涵曦", email = "im.hanxi@gmail.com"}, {name = "涵曦", email = "im.hanxi@gmail.com"},
@@ -11,7 +11,7 @@ dependencies = [
"aiohttp>=3.8.6", "aiohttp>=3.8.6",
"miservice-fork>=2.2.1", "miservice-fork>=2.2.1",
"mutagen>=1.47.0", "mutagen>=1.47.0",
"yt-dlp>=2023.10.13", "yt-dlp>=2024.2.2.232707.dev0",
"flask[async]>=3.0.1", "flask[async]>=3.0.1",
] ]
requires-python = ">=3.10" requires-python = ">=3.10"

View File

@@ -1,38 +1,53 @@
# This file is @generated by PDM. # This file is @generated by PDM.
# Please do not edit it manually. # Please do not edit it manually.
aiohttp==3.8.6 \ aiohttp==3.9.3 \
--hash=sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47 \ --hash=sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb \
--hash=sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9 \ --hash=sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5 \
--hash=sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887 \ --hash=sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc \
--hash=sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358 \ --hash=sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4 \
--hash=sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566 \ --hash=sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc \
--hash=sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e \ --hash=sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e \
--hash=sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93 \ --hash=sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60 \
--hash=sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad \ --hash=sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38 \
--hash=sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0 \ --hash=sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b \
--hash=sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096 \ --hash=sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53 \
--hash=sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321 \ --hash=sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5 \
--hash=sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1 \ --hash=sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96 \
--hash=sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f \ --hash=sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae \
--hash=sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22 \ --hash=sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce \
--hash=sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34 \ --hash=sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8 \
--hash=sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8 \ --hash=sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf \
--hash=sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d \ --hash=sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d \
--hash=sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5 \ --hash=sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869 \
--hash=sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865 \ --hash=sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b \
--hash=sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d \ --hash=sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52 \
--hash=sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543 \ --hash=sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5 \
--hash=sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684 \ --hash=sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4 \
--hash=sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed \ --hash=sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7 \
--hash=sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c \ --hash=sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5 \
--hash=sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2 \ --hash=sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54 \
--hash=sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403 \ --hash=sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3 \
--hash=sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965 \ --hash=sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5 \
--hash=sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a \ --hash=sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c \
--hash=sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca \ --hash=sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29 \
--hash=sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2 \ --hash=sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747 \
--hash=sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb --hash=sha256:b791a3143681a520c0a17e26ae7465f1b6f99461a28019d1a2f425236e6eedb5 \
--hash=sha256:b955ed993491f1a5da7f92e98d5dad3c1e14dc175f74517c4e610b1f2456fb11 \
--hash=sha256:ba39e9c8627edc56544c8628cc180d88605df3892beeb2b94c9bc857774848ca \
--hash=sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768 \
--hash=sha256:c3452ea726c76e92f3b9fae4b34a151981a9ec0a4847a627c43d71a15ac32aa6 \
--hash=sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2 \
--hash=sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6 \
--hash=sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266 \
--hash=sha256:dc9b311743a78043b26ffaeeb9715dc360335e5517832f5a8e339f8a43581e4d \
--hash=sha256:df822ee7feaaeffb99c1a9e5e608800bd8eda6e5f18f5cfb0dc7eeb2eaa6bbec \
--hash=sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5 \
--hash=sha256:e5e46b578c0e9db71d04c4b506a2121c0cb371dd89af17a0586ff6769d4c58c1 \
--hash=sha256:ee43080e75fc92bf36219926c8e6de497f9b247301bbf88c5c7593d931426679 \
--hash=sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283 \
--hash=sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b \
--hash=sha256:ff30218887e62209942f91ac1be902cc80cddb86bf00fbc6783b7a43b2bea26f
aiosignal==1.3.1 \ aiosignal==1.3.1 \
--hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \ --hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \
--hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17 --hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17
@@ -222,9 +237,9 @@ MarkupSafe==2.1.4 \
mdurl==0.1.2 \ mdurl==0.1.2 \
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
miservice-fork==2.2.1 \ miservice-fork==2.3.2 \
--hash=sha256:cf8f3e30b3008de29a69d9a8293cca8428e670ae10a0f791840428ee947fc27e \ --hash=sha256:1c907289cd354c349ead5e5b1f08e22aa23b8fa01114ecc7a2800e463751ba5b \
--hash=sha256:f3f742ccd7cb4a1ed22cfdf95da14f791eff0c6c3a54032dcfe445ae540664df --hash=sha256:f24c40366df99d5db706f09528692bc490390fe7db950aa32f4948bafdc1a03d
multidict==6.0.4 \ multidict==6.0.4 \
--hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \ --hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \
--hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \ --hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \
@@ -288,55 +303,66 @@ pygments==2.16.1 \
requests==2.31.0 \ requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \ --hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1 --hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
rich==13.6.0 \ rich==13.7.0 \
--hash=sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245 \ --hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \
--hash=sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef --hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235
typing-extensions==4.9.0 \ typing-extensions==4.9.0 \
--hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \ --hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
--hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd --hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
urllib3==2.0.6 \ urllib3==2.0.6 \
--hash=sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2 \ --hash=sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2 \
--hash=sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564 --hash=sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564
websockets==11.0.3 \ websockets==12.0 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \ --hash=sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b \
--hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 \ --hash=sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6 \
--hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 \ --hash=sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df \
--hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f \ --hash=sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b \
--hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 \ --hash=sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2 \
--hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 \ --hash=sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed \
--hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac \ --hash=sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd \
--hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 \ --hash=sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b \
--hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb \ --hash=sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931 \
--hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 \ --hash=sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30 \
--hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf \ --hash=sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370 \
--hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 \ --hash=sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be \
--hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 \ --hash=sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf \
--hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 \ --hash=sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b \
--hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f \ --hash=sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402 \
--hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 \ --hash=sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f \
--hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 \ --hash=sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123 \
--hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 \ --hash=sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603 \
--hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b \ --hash=sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45 \
--hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 \ --hash=sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558 \
--hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 \ --hash=sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4 \
--hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d \ --hash=sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480 \
--hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d \ --hash=sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447 \
--hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca \ --hash=sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8 \
--hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 \ --hash=sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04 \
--hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b \ --hash=sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c \
--hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d \ --hash=sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb \
--hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c \ --hash=sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b \
--hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 \ --hash=sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c \
--hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 \ --hash=sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92 \
--hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b \ --hash=sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113 \
--hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 \ --hash=sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f \
--hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c \ --hash=sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468 \
--hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 \ --hash=sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611 \
--hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 \ --hash=sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d \
--hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb \ --hash=sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca \
--hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 \ --hash=sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f \
--hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf \ --hash=sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2 \
--hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564 --hash=sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077 \
--hash=sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2 \
--hash=sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374 \
--hash=sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc \
--hash=sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e \
--hash=sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53 \
--hash=sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399 \
--hash=sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547 \
--hash=sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3 \
--hash=sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870 \
--hash=sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5 \
--hash=sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7
Werkzeug==3.0.1 \ Werkzeug==3.0.1 \
--hash=sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc \ --hash=sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc \
--hash=sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10 --hash=sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10
@@ -372,6 +398,6 @@ yarl==1.9.2 \
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \ --hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \ --hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560 --hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560
yt-dlp==2023.10.13 \ yt-dlp==2024.2.2.232707.dev0 \
--hash=sha256:2b069f22675532eebacdfd6372b1825651a751fef848de9ae6efe6491b2dc38a \ --hash=sha256:7ff05434979d89e2a7c344d6771cc60229901fe4182c19a756472bb49a50e3b8 \
--hash=sha256:e026ea1c435ff36eef1215bc4c5bb8c479938b90054997ba99f63a4541fe63b4 --hash=sha256:fd8d85f64842038cbdaaf7ee5812d98beed64fdcb4612f6e80b2c721bad13262

View File

@@ -53,6 +53,11 @@ def main():
dest="config", dest="config",
help="config file path", help="config file path",
) )
parser.add_argument(
"--ffmpeg_location",
dest="ffmpeg_location",
help="ffmpeg bin path",
)
options = parser.parse_args() options = parser.parse_args()
config = Config.from_options(options) config = Config.from_options(options)

View File

@@ -12,26 +12,26 @@ LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation
COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}" COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}"
HARDWARE_COMMAND_DICT = { HARDWARE_COMMAND_DICT = {
# hardware: (tts_command, wakeup_command) # hardware: (tts_command, wakeup_command, volume_command)
"LX06": ("5-1", "5-5"), "LX06": ("5-1", "5-5", "2-1"),
"L05B": ("5-3", "5-4"), "L05B": ("5-3", "5-4", "2-1"),
"S12A": ("5-1", "5-5"), "S12A": ("5-1", "5-5", "2-1"),
"LX01": ("5-1", "5-5"), "LX01": ("5-1", "5-5", "2-1"),
"L06A": ("5-1", "5-5"), "L06A": ("5-1", "5-5", "2-1"),
"LX04": ("5-1", "5-4"), "LX04": ("5-1", "5-4", "2-1"),
"L05C": ("5-3", "5-4"), "L05C": ("5-3", "5-4", "2-1"),
"L17A": ("7-3", "7-4"), "L17A": ("7-3", "7-4", "2-1"),
"X08E": ("7-3", "7-4"), "X08E": ("7-3", "7-4", "2-1"),
"LX05A": ("5-1", "5-5"), # 小爱红外版 "LX05A": ("5-1", "5-5", "2-1"), # 小爱红外版
"LX5A": ("5-1", "5-5"), # 小爱红外版 "LX5A": ("5-1", "5-5", "2-1"), # 小爱红外版
"L07A": ("5-1", "5-5"), # Redmi小爱音箱Play(l7a) "L07A": ("5-1", "5-5", "2-1"), # Redmi小爱音箱Play(l7a)
"L15A": ("7-3", "7-4"), "L15A": ("7-3", "7-4", "2-1"),
"X6A": ("7-3", "7-4"), # 小米智能家庭屏6 "X6A": ("7-3", "7-4", "2-1"), # 小米智能家庭屏6
"X10A": ("7-3", "7-4"), # 小米智能家庭屏10 "X10A": ("7-3", "7-4", "2-1"), # 小米智能家庭屏10
# add more here # add more here
} }
DEFAULT_COMMAND = ("5-1", "5-5") DEFAULT_COMMAND = ("5-1", "5-5", "2-1")
KEY_WORD_DICT = { KEY_WORD_DICT = {
"播放歌曲": "play", "播放歌曲": "play",
@@ -43,6 +43,7 @@ KEY_WORD_DICT = {
"关机": "stop", "关机": "stop",
"停止播放": "stop", "停止播放": "stop",
"分钟后关机": "stop_after_minute", "分钟后关机": "stop_after_minute",
"set_volume#": "set_volume",
} }
# 命令参数在前面 # 命令参数在前面
@@ -52,6 +53,7 @@ KEY_WORD_ARG_BEFORE_DICT = {
# 匹配优先级 # 匹配优先级
KEY_MATCH_ORDER = [ KEY_MATCH_ORDER = [
"set_volume#",
"分钟后关机", "分钟后关机",
"播放歌曲", "播放歌曲",
"放歌曲", "放歌曲",
@@ -64,8 +66,8 @@ KEY_MATCH_ORDER = [
] ]
SUPPORT_MUSIC_TYPE = [ SUPPORT_MUSIC_TYPE = [
"mp3", ".mp3",
"flac", ".flac",
] ]
@@ -77,12 +79,17 @@ class Config:
mi_did: str = os.getenv("MI_DID", "") mi_did: str = os.getenv("MI_DID", "")
mute_xiaoai: bool = True mute_xiaoai: bool = True
cookie: str = "" cookie: str = ""
use_command: bool = True use_command: bool = False
verbose: bool = False verbose: bool = False
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music") music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
hostname: str = os.getenv("XIAOMUSIC_HOSTNAME", "192.168.2.5") hostname: str = os.getenv("XIAOMUSIC_HOSTNAME", "192.168.2.5")
port: int = int(os.getenv("XIAOMUSIC_PORT", "8090")) port: int = int(os.getenv("XIAOMUSIC_PORT", "8090"))
proxy: str | None = os.getenv("XIAOMUSIC_PROXY", None) proxy: str | None = os.getenv("XIAOMUSIC_PROXY", None)
search_prefix: str = os.getenv(
"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")
def __post_init__(self) -> None: def __post_init__(self) -> None:
if self.proxy: if self.proxy:
@@ -96,6 +103,10 @@ class Config:
def wakeup_command(self) -> str: def wakeup_command(self) -> str:
return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[1] return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[1]
@property
def volume_command(self) -> str:
return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[2]
@classmethod @classmethod
def from_options(cls, options: argparse.Namespace) -> Config: def from_options(cls, options: argparse.Namespace) -> Config:
config = {} config = {}

View File

@@ -22,6 +22,21 @@ def allcmds():
return KEY_WORD_DICT return KEY_WORD_DICT
@app.route("/getvolume", methods=["GET"])
def getvolume():
return {
"volume": xiaomusic.get_volume(),
}
@app.route("/searchmusic", methods=["GET"])
def searchmusic():
name = request.args.get('name')
return xiaomusic.searchmusic(name)
@app.route("/playingmusic", methods=["GET"])
def playingmusic():
return xiaomusic.playingmusic()
@app.route("/", methods=["GET"]) @app.route("/", methods=["GET"])
def redirect_to_index(): def redirect_to_index():
return send_from_directory("static", "index.html") return send_from_directory("static", "index.html")

View File

@@ -1,52 +1,56 @@
$(function(){ $(function(){
// 拉取所有可操作的命令 $container=$("#cmds");
$.get("/allcmds", function(data, status) { append_op_button_name("下一首");
console.log(data, status); append_op_button_name("全部循环");
append_op_button_name("关机");
append_op_button_name("单曲循环");
append_op_button_name("播放歌曲");
append_op_button_name("随机播放");
$container=$("#cmds"); $container.append($("<hr>"));
// 遍历数据
for (const [key, value] of Object.entries(data)) {
if (key != "分钟后关机" && key != "放歌曲") {
append_op_button(key);
}
}
append_op_button("5分钟后关机"); append_op_button_name("10分钟后关机");
append_op_button("10分钟后关机"); append_op_button_name("30分钟后关机");
append_op_button("30分钟后关机"); append_op_button_name("60分钟后关机");
append_op_button("60分钟后关机");
// 拉取声音
$.get("/getvolume", function(data, status) {
console.log(data, status, data["volume"]);
$("#volume").val(data.volume);
}); });
function append_op_button(name) { function append_op_button_name(name) {
// 创建按钮 append_op_button(name, name);
const $button = $("<button>"); }
$button.text(name);
$button.attr("type", "button");
// 设置按钮点击事件 function append_op_button(name, cmd) {
$button.on("click", () => { // 创建按钮
// 发起post请求 const $button = $("<button>");
$.ajax({ $button.text(name);
type: "POST", $button.attr("type", "button");
url: "/cmd",
contentType: "application/json",
data: JSON.stringify({cmd: name}),
success: () => {
// 请求成功时执行的操作
},
error: () => {
// 请求失败时执行的操作
}
});
});
// 添加按钮到容器 // 设置按钮点击事件
$container.append($button); $button.on("click", () => {
sendcmd(cmd);
});
// 添加按钮到容器
$container.append($button);
} }
$("#play").on("click", () => { $("#play").on("click", () => {
name = $("#music-name").val(); var search_key = $("#music-name").val();
let cmd = "播放歌曲"+name; var filename=$("#music-filename").val();
let cmd = "播放歌曲"+search_key+"|"+filename;
sendcmd(cmd);
});
$("#volume").on('input', function () {
var value = $(this).val();
sendcmd("set_volume#"+value);
});
function sendcmd(cmd) {
$.ajax({ $.ajax({
type: "POST", type: "POST",
url: "/cmd", url: "/cmd",
@@ -59,5 +63,40 @@ $(function(){
// 请求失败时执行的操作 // 请求失败时执行的操作
} }
}); });
}
// 监听输入框的输入事件
$("#music-name").on('input', function() {
var inputValue = $(this).val();
// 发送Ajax请求
$.ajax({
url: "searchmusic", // 服务器端处理脚本
type: "GET",
dataType: "json",
data: {
name: inputValue
},
success: function(data) {
// 清空datalist
$("#autocomplete-list").empty();
// 添加新的option元素
$.each(data, function(i, item) {
$('<option>').val(item).appendTo("#autocomplete-list");
});
}
});
}); });
function get_playing_music() {
$.get("/playingmusic", function(data, status) {
console.log(data);
$("#playering-music").text(data);
});
}
// 每3秒获取下正在播放的音乐
get_playing_music();
setInterval(() => {
get_playing_music();
}, 3000);
}); });

View File

@@ -10,10 +10,53 @@
margin: 10px; margin: 10px;
width: 100px; width: 100px;
height: 50px; height: 50px;
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
border-radius: 10px;
background-color: #008CBA;
}
button:active {
font-weight:bold;
background-color: #007CBA;
transform: translateY(2px);
} }
input { input {
margin: 10px;
width: 300px;
height: 40px; height: 40px;
} }
.container{
width: 280px;
overflow: hidden;
display: inline-block;
}
@keyframes text-scroll {
0% {
left: 100%;
}
25% {
left: 50%;
}
50% {
left: 0%;
}
75% {
left: -50%;
}
100% {
left: -100%;
}
}
.text {
white-space: nowrap;
font-weight: bold;
position: relative;
animation: text-scroll 10s linear infinite;
}
</style> </style>
</head> </head>
<body> <body>
@@ -22,9 +65,21 @@
<div id="cmds"> <div id="cmds">
</div> </div>
<hr> <hr>
<div style="margin-left: 20px;">
<div style="display: flex; align-items: center;">
<svg class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#8e43e7" style="height: 48px; width: 48px;"><path d="M550.826667 154.666667a47.786667 47.786667 0 0 0-19.84 4.48L298.666667 298.666667H186.453333A80 80 0 0 0 106.666667 378.453333v267.093334A80 80 0 0 0 186.453333 725.333333H298.666667l232.32 139.52a47.786667 47.786667 0 0 0 19.84 4.48A46.506667 46.506667 0 0 0 597.333333 822.826667V201.173333a46.506667 46.506667 0 0 0-46.506666-46.506666zM554.666667 822.826667c0 3.413333-3.84 3.84-3.84 3.84L320 688.853333l-9.6-6.186666H186.453333A37.12 37.12 0 0 1 149.333333 645.546667V378.453333A37.12 37.12 0 0 1 186.453333 341.333333h123.946667l10.24-6.186666 229.546667-137.6s3.84 0 3.84 3.84zM667.52 346.026667a21.333333 21.333333 0 0 0 0 30.293333 192 192 0 0 1 0 271.36 21.333333 21.333333 0 0 0 0 30.293333 21.333333 21.333333 0 0 0 30.293333 0 234.666667 234.666667 0 0 0 0-331.946666 21.333333 21.333333 0 0 0-30.293333 0z"></path><path d="M804.48 219.52a21.333333 21.333333 0 0 0-30.293333 30.293333 370.986667 370.986667 0 0 1 0 524.373334 21.333333 21.333333 0 0 0 0 30.293333 21.333333 21.333333 0 0 0 30.293333 0 414.08 414.08 0 0 0 0-584.96z"></path></svg>
<input id="volume" type="range"></input>
</div>
</div>
<hr>
<div> <div>
<input id="music-name" type="text" placeholder="请输入歌曲名称"></input> <datalist id="autocomplete-list"></datalist>
<button id="play">播放</button> <input id="music-name" type="text" placeholder="请输入搜索关键词(如:MV高清版 周杰伦 七里香)" list="autocomplete-list"></input>
<input id="music-filename" type="text" placeholder="请输入保存为的文件名称(如:周杰伦七里香)"></input>
</div>
<button id="play">播放</button>
<div class="container">
<div id="playering-music" class="text"></div>
</div> </div>
</body> </body>
</html> </html>

View File

@@ -7,6 +7,7 @@ import socket
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
from typing import AsyncIterator from typing import AsyncIterator
from urllib.parse import urlparse from urllib.parse import urlparse
import difflib
from requests.utils import cookiejar_from_dict from requests.utils import cookiejar_from_dict
@@ -61,3 +62,6 @@ def validate_proxy(proxy_str: str) -> bool:
return True return True
# 模糊搜索
def fuzzyfinder(user_input, collection):
return difflib.get_close_matches(user_input, collection, 10, cutoff=0.1)

View File

@@ -30,6 +30,7 @@ from xiaomusic.config import (
from xiaomusic.utils import ( from xiaomusic.utils import (
calculate_tts_elapse, calculate_tts_elapse,
parse_cookie_string, parse_cookie_string,
fuzzyfinder,
) )
EOF = object() EOF = object()
@@ -56,6 +57,9 @@ class XiaoMusic:
self.hostname = config.hostname self.hostname = config.hostname
self.port = config.port self.port = config.port
self.proxy = config.proxy self.proxy = config.proxy
self.search_prefix = config.search_prefix
self.ffmpeg_location = config.ffmpeg_location
self.active_cmd = config.active_cmd.split(",")
# 下载对象 # 下载对象
self.download_proc = None self.download_proc = None
@@ -64,6 +68,10 @@ class XiaoMusic:
self.cur_music = "" self.cur_music = ""
self._next_timer = None self._next_timer = None
self._timeout = 0 self._timeout = 0
self._volume = 50
self._all_music = {}
self._play_list = []
self._playing = False
# 关机定时器 # 关机定时器
self._stop_timer = None self._stop_timer = None
@@ -74,20 +82,25 @@ class XiaoMusic:
self.log.addHandler(RichHandler()) self.log.addHandler(RichHandler())
self.log.debug(config) self.log.debug(config)
# 启动时重新生成一次播放列表
self.gen_all_music_list()
self.log.debug("ffmpeg_location: %s", self.ffmpeg_location)
async def poll_latest_ask(self): async def poll_latest_ask(self):
async with ClientSession() as session: async with ClientSession() as session:
session._cookie_jar = self.cookie_jar session._cookie_jar = self.cookie_jar
while True: while True:
# self.log.debug( self.log.debug(
# "Listening new message, timestamp: %s", self.last_timestamp "Listening new message, timestamp: %s", self.last_timestamp
# ) )
await self.get_latest_ask_from_xiaoai(session) await self.get_latest_ask_from_xiaoai(session)
start = time.perf_counter() start = time.perf_counter()
# self.log.debug("Polling_event, timestamp: %s", self.last_timestamp) self.log.debug("Polling_event, timestamp: %s", self.last_timestamp)
await self.polling_event.wait() await self.polling_event.wait()
if (d := time.perf_counter() - start) < 1: if (d := time.perf_counter() - start) < 1:
# sleep to avoid too many request # sleep to avoid too many request
# self.log.debug("Sleep %f, timestamp: %s", d, self.last_timestamp) self.log.debug("Sleep %f, timestamp: %s", d, self.last_timestamp)
await asyncio.sleep(1 - d) await asyncio.sleep(1 - d)
async def init_all_data(self, session): async def init_all_data(self, session):
@@ -95,7 +108,6 @@ class XiaoMusic:
await self._init_data_hardware() await self._init_data_hardware()
session.cookie_jar.update_cookies(self.get_cookie()) session.cookie_jar.update_cookies(self.get_cookie())
self.cookie_jar = session.cookie_jar self.cookie_jar = session.cookie_jar
StartHTTPServer(self.port, self.music_path, self)
async def login_miboy(self, session): async def login_miboy(self, session):
account = MiAccount( account = MiAccount(
@@ -209,11 +221,19 @@ class XiaoMusic:
def set_last_record(self, query): def set_last_record(self, query):
self.last_record = { self.last_record = {
"query": query, "query": query,
"ctrl_panel": True,
} }
self.new_record_event.set() self.new_record_event.set()
async def do_tts(self, value, wait_for_finish=False): async def do_tts(self, value, wait_for_finish=False):
self.log.info("do_tts: %s", value) self.log.info("do_tts: %s", value)
if self.config.mute_xiaoai:
await self.stop_if_xiaoai_is_playing()
else:
# waiting for xiaoai speaker done
await asyncio.sleep(8)
if not self.config.use_command: if not self.config.use_command:
try: try:
await self.mina_service.text_to_speech(self.device_id, value) await self.mina_service.text_to_speech(self.device_id, value)
@@ -230,6 +250,22 @@ class XiaoMusic:
await asyncio.sleep(elapse) await asyncio.sleep(elapse)
await self.wait_for_tts_finish() await self.wait_for_tts_finish()
async def do_set_volume(self, value):
value = int(value)
if not self.config.use_command:
try:
self.log.debug("do_set_volume not use_command value:%d", value)
await self.mina_service.player_set_volume(self.device_id, value)
except Exception:
pass
else:
self.log.debug("do_set_volume use_command value:%d", value)
await miio_command(
self.miio_service,
self.config.mi_did,
f"{self.config.volume_command}=#{value}",
)
async def wait_for_tts_finish(self): async def wait_for_tts_finish(self):
while True: while True:
if not await self.get_if_xiaoai_is_playing(): if not await self.get_if_xiaoai_is_playing():
@@ -267,7 +303,7 @@ class XiaoMusic:
return True return True
# 下载歌曲 # 下载歌曲
async def download(self, name): async def download(self, search_key, name):
if self.download_proc: if self.download_proc:
try: try:
self.download_proc.kill() self.download_proc.kill()
@@ -276,7 +312,7 @@ class XiaoMusic:
sbp_args = ( sbp_args = (
"yt-dlp", "yt-dlp",
f"ytsearch:{name}", f"{self.search_prefix}{search_key}",
"-x", "-x",
"--audio-format", "--audio-format",
"mp3", "mp3",
@@ -285,51 +321,84 @@ class XiaoMusic:
"-o", "-o",
f"{name}.mp3", f"{name}.mp3",
"--ffmpeg-location", "--ffmpeg-location",
"./ffmpeg/bin", f"{self.ffmpeg_location}",
"--no-playlist",
) )
if self.proxy: if self.proxy:
sbp_args += ("--proxy", f"{self.proxy}") sbp_args += ("--proxy", f"{self.proxy}")
self.download_proc = await asyncio.create_subprocess_exec(*sbp_args) self.download_proc = await asyncio.create_subprocess_exec(*sbp_args)
await self.do_tts(f"正在下载歌曲{name}") await self.do_tts(f"正在下载歌曲{search_key}")
def get_filename(self, name):
filename = os.path.join(self.music_path, name)
return filename
# 本地是否存在歌曲 # 本地是否存在歌曲
def local_exist(self, name): def get_filename(self, name):
for tp in SUPPORT_MUSIC_TYPE: if name not in self._all_music:
filename = self.get_filename(f"{name}.{tp}") self.log.debug("get_filename not in. name:%s", name)
self.log.debug("try local_exist. filename:%s", filename) return ""
if os.path.exists(filename): filename = self._all_music[name]
return filename self.log.debug("try get_filename. filename:%s", filename)
if os.path.exists(filename):
return filename
return "" return ""
# 获取歌曲播放地址 # 获取歌曲播放地址
def get_file_url(self, filename): def get_file_url(self, name):
self.log.debug("get_file_url. filename:%s", filename) filename = self.get_filename(name)
self.log.debug("get_file_url. name:%s, filename:%s", name, filename)
encoded_name = urllib.parse.quote(filename) encoded_name = urllib.parse.quote(filename)
return f"http://{self.hostname}:{self.port}/{encoded_name}" return f"http://{self.hostname}:{self.port}/{encoded_name}"
# 随机获取一首音乐 # 递归获取目录下所有歌曲,生成随机播放列表
def random_music(self): def gen_all_music_list(self):
files = os.listdir(self.music_path) self._all_music = {}
# 过滤音乐文件 for root, dirs, filenames in os.walk(self.music_path):
music_files = [] for filename in filenames:
for file in files: self.log.debug("gen_all_music_list. filename:%s", filename)
for tp in SUPPORT_MUSIC_TYPE: # 过滤隐藏文件
if file.endswith(f".{tp}"): if filename.startswith("."):
music_files.append(file) continue
# 过滤非音乐文件
(name, extension) = os.path.splitext(filename)
self.log.debug(
"gen_all_music_list. filename:%s, name:%s, extension:%s",
filename,
name,
extension,
)
if extension not in SUPPORT_MUSIC_TYPE:
continue
if len(music_files) == 0: # 歌曲名字相同会覆盖
self._all_music[name] = os.path.join(root, filename)
self._play_list = list(self._all_music.keys())
random.shuffle(self._play_list)
self.log.debug(self._all_music)
# 把下载的音乐加入播放列表
def add_download_music(self, name):
self._all_music[name] = os.path.join(self.music_path, f"{name}.mp3")
if name not in self._play_list:
self._play_list.append(name)
self.log.debug("add_music %s", name)
self.log.debug(self._play_list)
# 获取下一首
def get_next_music(self):
play_list_len = len(self._play_list)
if play_list_len == 0:
self.log.warning(f"没有随机到歌曲") self.log.warning(f"没有随机到歌曲")
return "" return ""
# 随机选择一个文件 # 随机选择一个文件
music_file = random.choice(music_files) index = 0
(filename, extension) = os.path.splitext(music_file) try:
self.log.info(f"随机到歌曲{filename}{extension}") index = self._play_list.index(self.cur_music)
except ValueError:
pass
next_index = index + 1
if next_index >= play_list_len:
next_index = 0
filename = self._play_list[next_index]
return filename return filename
# 获取文件播放时长 # 获取文件播放时长
@@ -342,8 +411,9 @@ class XiaoMusic:
# 设置下一首歌曲的播放定时器 # 设置下一首歌曲的播放定时器
def set_next_music_timeout(self): def set_next_music_timeout(self):
sec = int(self.get_file_duration(self.cur_music)) filename = self.get_filename(self.cur_music)
self.log.info(f"歌曲{self.cur_music}的时长{sec}") sec = int(self.get_file_duration(filename))
self.log.info(f"歌曲 {self.cur_music} : {filename} 的时长 {sec}")
if self._next_timer: if self._next_timer:
self._next_timer.cancel() self._next_timer.cancel()
self.log.info(f"定时器已取消") self.log.info(f"定时器已取消")
@@ -363,6 +433,7 @@ class XiaoMusic:
async with ClientSession() as session: async with ClientSession() as session:
self.session = session self.session = session
await self.init_all_data(session) await self.init_all_data(session)
StartHTTPServer(self.port, self.music_path, self)
task = asyncio.create_task(self.poll_latest_ask()) task = asyncio.create_task(self.poll_latest_ask())
assert task is not None # to keep the reference to task, do not remove this assert task is not None # to keep the reference to task, do not remove this
self.log.info( self.log.info(
@@ -376,20 +447,15 @@ class XiaoMusic:
new_record = self.last_record new_record = self.last_record
self.polling_event.clear() # stop polling when processing the question self.polling_event.clear() # stop polling when processing the question
query = new_record.get("query", "").strip() query = new_record.get("query", "").strip()
self.log.debug("收到消息:%s", query) ctrl_panel = new_record.get("ctrl_panel", False)
self.log.debug("收到消息:%s 控制面板:%s", query, ctrl_panel)
# 匹配命令 # 匹配命令
opvalue, oparg = self.match_cmd(query) opvalue, oparg = self.match_cmd(query, ctrl_panel)
if not opvalue: if not opvalue:
await asyncio.sleep(1) await asyncio.sleep(1)
continue continue
if self.config.mute_xiaoai:
await self.stop_if_xiaoai_is_playing()
else:
# waiting for xiaoai speaker done
await asyncio.sleep(8)
try: try:
func = getattr(self, opvalue) func = getattr(self, opvalue)
await func(arg1=oparg) await func(arg1=oparg)
@@ -397,12 +463,13 @@ class XiaoMusic:
self.log.warning(f"执行出错 {str(e)}\n{traceback.format_exc()}") self.log.warning(f"执行出错 {str(e)}\n{traceback.format_exc()}")
# 匹配命令 # 匹配命令
def match_cmd(self, query): def match_cmd(self, query, ctrl_panel):
for opkey in KEY_MATCH_ORDER: for opkey in KEY_MATCH_ORDER:
patternarg = rf"(.*){opkey}(.*)" patternarg = rf"(.*){opkey}(.*)"
# 匹配参数 # 匹配参数
matcharg = re.match(patternarg, query) matcharg = re.match(patternarg, query)
if not matcharg: if not matcharg:
# self.log.debug(patternarg)
continue continue
argpre = matcharg.groups()[0] argpre = matcharg.groups()[0]
@@ -415,28 +482,45 @@ class XiaoMusic:
) )
oparg = argafter oparg = argafter
opvalue = KEY_WORD_DICT[opkey] opvalue = KEY_WORD_DICT[opkey]
if not ctrl_panel and not self._playing:
if self.active_cmd and opvalue not in self.active_cmd:
self.log.debug(f"不在激活命令中 {opvalue}")
continue
if opkey in KEY_WORD_ARG_BEFORE_DICT: if opkey in KEY_WORD_ARG_BEFORE_DICT:
oparg = argpre oparg = argpre
self.log.info("匹配到指令. opkey:%s opvalue:%s oparg:%s", opkey, opvalue, oparg) self.log.info(
"匹配到指令. opkey:%s opvalue:%s oparg:%s", opkey, opvalue, oparg
)
return (opvalue, oparg) return (opvalue, oparg)
if self._playing:
self.log.info("未匹配到指令,自动停止")
return ("stop", {})
return (None, None) return (None, None)
# 播放歌曲 # 播放歌曲
async def play(self, **kwargs): async def play(self, **kwargs):
name = kwargs["arg1"] self._playing = True
if name == "": parts = kwargs["arg1"].split("|")
search_key = parts[0]
name = parts[1] if len(parts) > 1 else search_key
if search_key == "" and name == "":
await self.play_next() await self.play_next()
return return
if name == "":
name = search_key
self.log.debug("play. search_key:%s name:%s", search_key, name)
filename = self.get_filename(name)
filename = self.local_exist(name)
if len(filename) <= 0: if len(filename) <= 0:
await self.download(name) await self.download(search_key, name)
self.log.info("正在下载中 %s", name) self.log.info("正在下载中 %s", search_key + ":" + name)
filename = self.get_filename(f"{name}.mp3")
await self.download_proc.wait() await self.download_proc.wait()
# 把文件插入到播放列表里
self.add_download_music(name)
self.cur_music = filename self.cur_music = name
url = self.get_file_url(filename) self.log.info("cur_music %s", self.cur_music)
url = self.get_file_url(name)
self.log.info("播放 %s", url) self.log.info("播放 %s", url)
await self.stop_if_xiaoai_is_playing() await self.stop_if_xiaoai_is_playing()
await self.mina_service.play_by_url(self.device_id, url) await self.mina_service.play_by_url(self.device_id, url)
@@ -447,14 +531,14 @@ class XiaoMusic:
# 下一首 # 下一首
async def play_next(self, **kwargs): async def play_next(self, **kwargs):
self.log.info("下一首") self.log.info("下一首")
(name, _) = os.path.splitext(os.path.basename(self.cur_music)) name = self.cur_music
self.log.debug("play_next. name:%s, cur_music:%s", name, self.cur_music) self.log.debug("play_next. name:%s, cur_music:%s", name, self.cur_music)
if self.play_type == PLAY_TYPE_ALL or name == "": if self.play_type == PLAY_TYPE_ALL or name == "":
name = self.random_music() name = self.get_next_music()
if name == "": if name == "":
await self.do_tts(f"本地没有歌曲") await self.do_tts(f"本地没有歌曲")
return return
await self.play(name=name) await self.play(arg1=name)
# 单曲循环 # 单曲循环
async def set_play_type_one(self, **kwargs): async def set_play_type_one(self, **kwargs):
@@ -470,9 +554,12 @@ class XiaoMusic:
async def random_play(self, **kwargs): async def random_play(self, **kwargs):
self.play_type = PLAY_TYPE_ALL self.play_type = PLAY_TYPE_ALL
await self.do_tts(f"已经设置为全部循环并随机播放") await self.do_tts(f"已经设置为全部循环并随机播放")
# 重新生成随机播放列表
self.gen_all_music_list()
await self.play_next() await self.play_next()
async def stop(self, **kwargs): async def stop(self, **kwargs):
self._playing = False
if self._next_timer: if self._next_timer:
self._next_timer.cancel() self._next_timer.cancel()
self.log.info(f"定时器已取消") self.log.info(f"定时器已取消")
@@ -493,3 +580,23 @@ class XiaoMusic:
self._stop_timer = asyncio.ensure_future(_do_stop()) self._stop_timer = asyncio.ensure_future(_do_stop())
self.log.info(f"{minute}分钟后将关机") self.log.info(f"{minute}分钟后将关机")
async def set_volume(self, **kwargs):
value = kwargs["arg1"]
await self.do_set_volume(value)
self._volume = int(value)
self.log.info(f"声音设置为{value}")
def get_volume(self):
return self._volume
# 搜索音乐
def searchmusic(self, name):
search_list = fuzzyfinder(name, self._play_list)
self.log.debug("searchmusic. name:%s search_list:%s", name, search_list)
return search_list
# 正在播放中的音乐
def playingmusic(self):
self.log.debug("playingmusic. cur_music:%s", self.cur_music)
return self.cur_music