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

Compare commits

...

59 Commits

Author SHA1 Message Date
涵曦
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
涵曦
8f5e2f0560 update version 2024-01-28 18:45:58 +08:00
涵曦
a940fcd236 fix: http server listen host 2024-01-28 18:45:36 +08:00
涵曦
b32e2e29d8 update version 2024-01-28 18:35:04 +08:00
涵曦
8f22e2c66e update requirements 2024-01-28 18:34:34 +08:00
涵曦
8801bb73f4 update readme 2024-01-28 18:29:14 +08:00
涵曦
82a215e3bc update version 2024-01-28 18:26:28 +08:00
涵曦
88e5d98c68 新增输入框输入歌曲名 2024-01-28 18:25:22 +08:00
涵曦
c7ab57c06a 新增定时关机命令,新增控制面板界面 2024-01-28 18:17:45 +08:00
涵曦
f1938b9096 update readme 2024-01-27 23:09:30 +08:00
涵曦
5242deea33 update version 2024-01-27 23:00:31 +08:00
涵曦
d06b3cd2a5 新增随机播放指令 2024-01-27 23:00:17 +08:00
涵曦
2a59d1f69c 推送docker修改 2024-01-27 22:44:23 +08:00
涵曦
358f7ccb98 推送docker修改 2024-01-27 22:41:02 +08:00
涵曦
1043b6f32f update version to v0.1.4 2024-01-27 22:31:13 +08:00
涵曦
8f2d26ac10 修复本地flac音乐播放后去下载错误音乐的问题 2024-01-27 22:26:53 +08:00
涵曦
8e8a605816 支持flac格式的本地文件 2024-01-27 20:56:07 +08:00
涵曦
63eb0c22cb bugfix: kill download progress don't raise error 2023-10-16 22:53:02 +08:00
涵曦
ca07ed0dd3 fix: error when play next 2023-10-16 22:41:00 +08:00
涵曦
7d158ff40e some feat 2023-10-16 22:40:21 +08:00
涵曦
90243b395a Merge pull request #3 from dzhuang/allow_hardware_param
Use MI_HARDWARE in env.
2023-10-16 19:25:11 +08:00
涵曦
653bd417e5 Merge branch 'main' into allow_hardware_param 2023-10-16 19:24:51 +08:00
涵曦
6d89a24b28 Merge pull request #4 from dzhuang/set_proxy_to_null
Default proxy to None.
2023-10-16 19:17:30 +08:00
dzhuang
0ca2adb014 Default proxy to None. 2023-10-16 18:13:09 +08:00
dzhuang
a8a9e2bc45 Use MI_HARDWARE in env. 2023-10-16 18:07:07 +08:00
涵曦
7e7bb256b5 Update README.md 2023-10-15 21:41:12 +08:00
涵曦
35c43646cb Update README.md 2023-10-15 21:40:13 +08:00
16 changed files with 1092 additions and 304 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 }}

View File

@@ -63,4 +63,4 @@ jobs:
context: .
platforms: linux/amd64,linux/arm64
push: true
tags: hanxi/xiaomusic:${{ github.ref_name }}
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}, ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:latest, ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:stable

3
.gitignore vendored
View File

@@ -160,3 +160,6 @@ cython_debug/
# 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.
#.idea/
ffmpeg
music

View File

@@ -1,6 +1,6 @@
# xiaomusic
使用小爱同学播放音乐,音乐使用 yt-dlp 下载。
使用小爱/红米音箱播放音乐,音乐使用 yt-dlp 下载。
## 运行
@@ -12,6 +12,7 @@
export MI_USER="xxxxx"
export MI_PASS="xxxx"
export MI_DID=00000
export XIAOMUSIC_SEARCH='bilisearch:'
```
然后启动即可。默认监听了端口 8090 , 使用其他端口自行修改。
@@ -28,21 +29,44 @@ pdm run xiaomusic.py
- 单曲循环
- 全部循环
> 隐藏玩法: 对小爱同学说播放歌曲小猪佩奇的故事,会播放小猪佩奇的故事。
## 已测试设备
```txt
"L07A": ("5-1", "5-5"), # Redmi小爱音箱Play(l7a)
````
## 支持音乐格式
- mp3
- flac
> 本地音乐会搜索 mp3 和 flac 格式的文件,下载的歌曲是 mp3 格式的。
## 在 Docker 里使用
```shell
docker run -e MI_USER=<your-xiaomi-account> -e MI_PASS=<your-xiaomi-password> -e MI_DID=<your-xiaomi-speaker-mid> -e XIAOMUSIC_PROXY=<proxy-for-yt-dlp> -e XIAOMUSIC_HOSTNAME=192.168.2.5 -p 8090:8090 -v ./music:/app/music hanxi/xiaomusic --hardware=<L07A> -
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 工具下载歌曲会用到。
- 注意端口必须映射为与容器内一致XIAOMUSIC_HOSTNAME 需要设置为宿主机的 IP 地址,否则小爱无法正常播放。
- 可以把 /app/music 目录映射到本地,用于保存下载的歌曲。
<https://github.com/hanxi/xiaomusic/issues/2><https://github.com/hanxi/xiaomusic/issues/11>
### 本地编译Docker Image
@@ -50,10 +74,74 @@ docker run -e MI_USER=<your-xiaomi-account> -e MI_PASS=<your-xiaomi-password> -e
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>
- ip 是 XIAOMUSIC_HOSTNAME 设置的
- 8090 是默认端口
## 感谢
- [xiaomi](https://www.mi.com/)
- [PDM](https://pdm.fming.dev/latest/)
- [xiaogpt](https://github.com/yihong0618/xiaogpt)
- [MiService](https://github.com/yihong0618/MiService)
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
## 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

371
pdm.lock generated
View File

@@ -6,54 +6,68 @@ groups = ["default"]
cross_platform = true
static_urls = false
lock_version = "4.3"
content_hash = "sha256:c123354af86c15de519dfa703c59361f09898eb635df198f3dcf9ef6ed41ffba"
content_hash = "sha256:d21199e11013c9db9343d7868f7f582ff85a6c8ad29b3f5caca7ce7fe669b841"
[[package]]
name = "aiohttp"
version = "3.8.6"
requires_python = ">=3.6"
version = "3.9.3"
requires_python = ">=3.8"
summary = "Async http client/server framework (asyncio)"
dependencies = [
"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",
"charset-normalizer<4.0,>=2.0",
"frozenlist>=1.1.1",
"multidict<7.0,>=4.5",
"yarl<2.0,>=1.0",
]
files = [
{file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1"},
{file = "aiohttp-3.8.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566"},
{file = "aiohttp-3.8.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93"},
{file = "aiohttp-3.8.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47"},
{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.8.6-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2"},
{file = "aiohttp-3.8.6-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed"},
{file = "aiohttp-3.8.6-cp310-cp310-win32.whl", hash = "sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2"},
{file = "aiohttp-3.8.6-cp310-cp310-win_amd64.whl", hash = "sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865"},
{file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34"},
{file = "aiohttp-3.8.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca"},
{file = "aiohttp-3.8.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358"},
{file = "aiohttp-3.8.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d"},
{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.8.6-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887"},
{file = "aiohttp-3.8.6-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f"},
{file = "aiohttp-3.8.6-cp311-cp311-win32.whl", hash = "sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb"},
{file = "aiohttp-3.8.6-cp311-cp311-win_amd64.whl", hash = "sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0"},
{file = "aiohttp-3.8.6.tar.gz", hash = "sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c"},
{file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54"},
{file = "aiohttp-3.9.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc"},
{file = "aiohttp-3.9.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5"},
{file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f56455b0c2c7cc3b0c584815264461d07b177f903a04481dfc33e08a89f0c26b"},
{file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bca77a198bb6e69795ef2f09a5f4c12758487f83f33d63acde5f0d4919815768"},
{file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e083c285857b78ee21a96ba1eb1b5339733c3563f72980728ca2b08b53826ca5"},
{file = "aiohttp-3.9.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29"},
{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.9.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747"},
{file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cd73265a9e5ea618014802ab01babf1940cecb90c9762d8b9e7d2cc1e1969ec6"},
{file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c"},
{file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf"},
{file = "aiohttp-3.9.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52"},
{file = "aiohttp-3.9.3-cp310-cp310-win32.whl", hash = "sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b"},
{file = "aiohttp-3.9.3-cp310-cp310-win_amd64.whl", hash = "sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5"},
{file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d"},
{file = "aiohttp-3.9.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c46956ed82961e31557b6857a5ca153c67e5476972e5f7190015018760938da2"},
{file = "aiohttp-3.9.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc"},
{file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad46e6f620574b3b4801c68255492e0159d1712271cc99d8bdf35f2043ec266"},
{file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce"},
{file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb"},
{file = "aiohttp-3.9.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b"},
{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.9.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae"},
{file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3"},
{file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:f033d80bc6283092613882dfe40419c6a6a1527e04fc69350e87a9df02bbc283"},
{file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e"},
{file = "aiohttp-3.9.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4"},
{file = "aiohttp-3.9.3-cp311-cp311-win32.whl", hash = "sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5"},
{file = "aiohttp-3.9.3-cp311-cp311-win_amd64.whl", hash = "sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8"},
{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]]
@@ -69,6 +83,19 @@ files = [
{file = "aiosignal-1.3.1.tar.gz", hash = "sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc"},
]
[[package]]
name = "asgiref"
version = "3.7.2"
requires_python = ">=3.7"
summary = "ASGI specs, helper code, and adapters"
dependencies = [
"typing-extensions>=4; python_version < \"3.11\"",
]
files = [
{file = "asgiref-3.7.2-py3-none-any.whl", hash = "sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e"},
{file = "asgiref-3.7.2.tar.gz", hash = "sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed"},
]
[[package]]
name = "async-timeout"
version = "4.0.3"
@@ -89,6 +116,16 @@ files = [
{file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"},
]
[[package]]
name = "blinker"
version = "1.7.0"
requires_python = ">=3.8"
summary = "Fast, simple object-to-object and broadcast signaling"
files = [
{file = "blinker-1.7.0-py3-none-any.whl", hash = "sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9"},
{file = "blinker-1.7.0.tar.gz", hash = "sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182"},
]
[[package]]
name = "brotli"
version = "1.1.0"
@@ -280,6 +317,61 @@ files = [
{file = "charset_normalizer-3.3.0-py3-none-any.whl", hash = "sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2"},
]
[[package]]
name = "click"
version = "8.1.7"
requires_python = ">=3.7"
summary = "Composable command line interface toolkit"
dependencies = [
"colorama; platform_system == \"Windows\"",
]
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
]
[[package]]
name = "colorama"
version = "0.4.6"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
summary = "Cross-platform colored terminal text."
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "flask"
version = "3.0.1"
requires_python = ">=3.8"
summary = "A simple framework for building complex web applications."
dependencies = [
"Jinja2>=3.1.2",
"Werkzeug>=3.0.0",
"blinker>=1.6.2",
"click>=8.1.3",
"itsdangerous>=2.1.2",
]
files = [
{file = "flask-3.0.1-py3-none-any.whl", hash = "sha256:ca631a507f6dfe6c278ae20112cea3ff54ff2216390bf8880f6b035a5354af13"},
{file = "flask-3.0.1.tar.gz", hash = "sha256:6489f51bb3666def6f314e15f19d50a1869a19ae0e8c9a3641ffe66c77d42403"},
]
[[package]]
name = "flask"
version = "3.0.1"
extras = ["async"]
requires_python = ">=3.8"
summary = "A simple framework for building complex web applications."
dependencies = [
"asgiref>=3.2",
"flask==3.0.1",
]
files = [
{file = "flask-3.0.1-py3-none-any.whl", hash = "sha256:ca631a507f6dfe6c278ae20112cea3ff54ff2216390bf8880f6b035a5354af13"},
{file = "flask-3.0.1.tar.gz", hash = "sha256:6489f51bb3666def6f314e15f19d50a1869a19ae0e8c9a3641ffe66c77d42403"},
]
[[package]]
name = "frozenlist"
version = "1.4.0"
@@ -329,6 +421,29 @@ files = [
{file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
]
[[package]]
name = "itsdangerous"
version = "2.1.2"
requires_python = ">=3.7"
summary = "Safely pass data to untrusted environments and back."
files = [
{file = "itsdangerous-2.1.2-py3-none-any.whl", hash = "sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44"},
{file = "itsdangerous-2.1.2.tar.gz", hash = "sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a"},
]
[[package]]
name = "jinja2"
version = "3.1.3"
requires_python = ">=3.7"
summary = "A very fast and expressive template engine."
dependencies = [
"MarkupSafe>=2.0",
]
files = [
{file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"},
{file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"},
]
[[package]]
name = "markdown-it-py"
version = "3.0.0"
@@ -342,6 +457,45 @@ files = [
{file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"},
]
[[package]]
name = "markupsafe"
version = "2.1.4"
requires_python = ">=3.7"
summary = "Safely add untrusted strings to HTML/XML markup."
files = [
{file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84"},
{file = "MarkupSafe-2.1.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b"},
{file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8"},
{file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e"},
{file = "MarkupSafe-2.1.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d"},
{file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858"},
{file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e"},
{file = "MarkupSafe-2.1.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26"},
{file = "MarkupSafe-2.1.4-cp310-cp310-win32.whl", hash = "sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0"},
{file = "MarkupSafe-2.1.4-cp310-cp310-win_amd64.whl", hash = "sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2"},
{file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863"},
{file = "MarkupSafe-2.1.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69"},
{file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc"},
{file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6"},
{file = "MarkupSafe-2.1.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb"},
{file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7"},
{file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea"},
{file = "MarkupSafe-2.1.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131"},
{file = "MarkupSafe-2.1.4-cp311-cp311-win32.whl", hash = "sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74"},
{file = "MarkupSafe-2.1.4-cp311-cp311-win_amd64.whl", hash = "sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56"},
{file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e"},
{file = "MarkupSafe-2.1.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc"},
{file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc"},
{file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250"},
{file = "MarkupSafe-2.1.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f"},
{file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74"},
{file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6"},
{file = "MarkupSafe-2.1.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d"},
{file = "MarkupSafe-2.1.4-cp312-cp312-win32.whl", hash = "sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475"},
{file = "MarkupSafe-2.1.4-cp312-cp312-win_amd64.whl", hash = "sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656"},
{file = "MarkupSafe-2.1.4.tar.gz", hash = "sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f"},
]
[[package]]
name = "mdurl"
version = "0.1.2"
@@ -354,15 +508,16 @@ files = [
[[package]]
name = "miservice-fork"
version = "2.2.1"
version = "2.3.2"
requires_python = ">=3.7"
summary = "XiaoMi Cloud Service fork from https://github.com/Yonsm/MiService"
dependencies = [
"aiohttp",
"mutagen",
]
files = [
{file = "miservice_fork-2.2.1-py3-none-any.whl", hash = "sha256:cf8f3e30b3008de29a69d9a8293cca8428e670ae10a0f791840428ee947fc27e"},
{file = "miservice_fork-2.2.1.tar.gz", hash = "sha256:f3f742ccd7cb4a1ed22cfdf95da14f791eff0c6c3a54032dcfe445ae540664df"},
{file = "miservice_fork-2.3.2-py3-none-any.whl", hash = "sha256:f24c40366df99d5db706f09528692bc490390fe7db950aa32f4948bafdc1a03d"},
{file = "miservice_fork-2.3.2.tar.gz", hash = "sha256:1c907289cd354c349ead5e5b1f08e22aa23b8fa01114ecc7a2800e463751ba5b"},
]
[[package]]
@@ -481,7 +636,7 @@ files = [
[[package]]
name = "rich"
version = "13.6.0"
version = "13.7.0"
requires_python = ">=3.7.0"
summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
dependencies = [
@@ -489,8 +644,18 @@ dependencies = [
"pygments<3.0.0,>=2.13.0",
]
files = [
{file = "rich-13.6.0-py3-none-any.whl", hash = "sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245"},
{file = "rich-13.6.0.tar.gz", hash = "sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef"},
{file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"},
{file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"},
]
[[package]]
name = "typing-extensions"
version = "4.9.0"
requires_python = ">=3.8"
summary = "Backported and Experimental Type Hints for Python 3.8+"
files = [
{file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"},
{file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"},
]
[[package]]
@@ -505,49 +670,73 @@ files = [
[[package]]
name = "websockets"
version = "11.0.3"
requires_python = ">=3.7"
version = "12.0"
requires_python = ">=3.8"
summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
files = [
{file = "websockets-11.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac"},
{file = "websockets-11.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d"},
{file = "websockets-11.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f"},
{file = "websockets-11.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564"},
{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-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-11.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54"},
{file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4"},
{file = "websockets-11.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526"},
{file = "websockets-11.0.3-cp310-cp310-win32.whl", hash = "sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69"},
{file = "websockets-11.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f"},
{file = "websockets-11.0.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb"},
{file = "websockets-11.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288"},
{file = "websockets-11.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d"},
{file = "websockets-11.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3"},
{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-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-11.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97"},
{file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf"},
{file = "websockets-11.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd"},
{file = "websockets-11.0.3-cp311-cp311-win32.whl", hash = "sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c"},
{file = "websockets-11.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf"},
{file = "websockets-11.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5"},
{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-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-11.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20"},
{file = "websockets-11.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931"},
{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-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-11.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82"},
{file = "websockets-11.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c"},
{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-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-11.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602"},
{file = "websockets-11.0.3-py3-none-any.whl", hash = "sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6"},
{file = "websockets-11.0.3.tar.gz", hash = "sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016"},
{file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"},
{file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"},
{file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"},
{file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"},
{file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"},
{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-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"},
{file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"},
{file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"},
{file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"},
{file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"},
{file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"},
{file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"},
{file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"},
{file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"},
{file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"},
{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-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"},
{file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"},
{file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"},
{file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"},
{file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"},
{file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"},
{file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"},
{file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"},
{file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"},
{file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"},
{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-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"},
{file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"},
{file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"},
{file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"},
{file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"},
{file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"},
{file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"},
{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-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-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"},
{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]]
name = "werkzeug"
version = "3.0.1"
requires_python = ">=3.8"
summary = "The comprehensive WSGI web application library."
dependencies = [
"MarkupSafe>=2.1.1",
]
files = [
{file = "werkzeug-3.0.1-py3-none-any.whl", hash = "sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10"},
{file = "werkzeug-3.0.1.tar.gz", hash = "sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc"},
]
[[package]]
@@ -595,18 +784,20 @@ files = [
[[package]]
name = "yt-dlp"
version = "2023.10.13"
requires_python = ">=3.7"
version = "2024.2.2.232707.dev0"
requires_python = ">=3.8"
summary = "A youtube-dl fork with additional features and patches"
dependencies = [
"brotli; platform_python_implementation == \"CPython\"",
"brotlicffi; platform_python_implementation != \"CPython\"",
"brotli; implementation_name == \"cpython\"",
"brotlicffi; implementation_name != \"cpython\"",
"certifi",
"mutagen",
"pycryptodomex",
"websockets",
"requests<3,>=2.31.0",
"urllib3<3,>=1.26.17",
"websockets>=12.0",
]
files = [
{file = "yt-dlp-2023.10.13.tar.gz", hash = "sha256:e026ea1c435ff36eef1215bc4c5bb8c479938b90054997ba99f63a4541fe63b4"},
{file = "yt_dlp-2023.10.13-py2.py3-none-any.whl", hash = "sha256:2b069f22675532eebacdfd6372b1825651a751fef848de9ae6efe6491b2dc38a"},
{file = "yt-dlp-2024.2.2.232707.dev0.tar.gz", hash = "sha256:fd8d85f64842038cbdaaf7ee5812d98beed64fdcb4612f6e80b2c721bad13262"},
{file = "yt_dlp-2024.2.2.232707.dev0-py2.py3-none-any.whl", hash = "sha256:7ff05434979d89e2a7c344d6771cc60229901fe4182c19a756472bb49a50e3b8"},
]

View File

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

View File

@@ -1,47 +1,68 @@
# This file is @generated by PDM.
# Please do not edit it manually.
aiohttp==3.8.6 \
--hash=sha256:0fa375b3d34e71ccccf172cab401cd94a72de7a8cc01847a7b3386204093bb47 \
--hash=sha256:14cd52ccf40006c7a6cd34a0f8663734e5363fd981807173faf3a017e202fec9 \
--hash=sha256:16d330b3b9db87c3883e565340d292638a878236418b23cc8b9b11a054aaa887 \
--hash=sha256:1bed815f3dc3d915c5c1e556c397c8667826fbc1b935d95b0ad680787896a358 \
--hash=sha256:1d84166673694841d8953f0a8d0c90e1087739d24632fe86b1a08819168b4566 \
--hash=sha256:253bf92b744b3170eb4c4ca2fa58f9c4b87aeb1df42f71d4e78815e6e8b73c9e \
--hash=sha256:2817b2f66ca82ee699acd90e05c95e79bbf1dc986abb62b61ec8aaf851e81c93 \
--hash=sha256:2d5b785c792802e7b275c420d84f3397668e9d49ab1cb52bd916b3b3ffcf09ad \
--hash=sha256:3b2ab182fc28e7a81f6c70bfbd829045d9480063f5ab06f6e601a3eddbbd49a0 \
--hash=sha256:3fd194939b1f764d6bb05490987bfe104287bbf51b8d862261ccf66f48fb4096 \
--hash=sha256:41bdc2ba359032e36c0e9de5a3bd00d6fb7ea558a6ce6b70acedf0da86458321 \
--hash=sha256:41d55fc043954cddbbd82503d9cc3f4814a40bcef30b3569bc7b5e34130718c1 \
--hash=sha256:42c89579f82e49db436b69c938ab3e1559e5a4409eb8639eb4143989bc390f2f \
--hash=sha256:6c5f938d199a6fdbdc10bbb9447496561c3a9a565b43be564648d81e1102ac22 \
--hash=sha256:6e2f9cc8e5328f829f6e1fb74a0a3a939b14e67e80832975e01929e320386b34 \
--hash=sha256:76b36b3124f0223903609944a3c8bf28a599b2cc0ce0be60b45211c8e9be97f8 \
--hash=sha256:7bc88fc494b1f0311d67f29fee6fd636606f4697e8cc793a2d912ac5b19aa38d \
--hash=sha256:8e31e9db1bee8b4f407b77fd2507337a0a80665ad7b6c749d08df595d88f1cf5 \
--hash=sha256:93c15c8e48e5e7b89d5cb4613479d144fda8344e2d886cf694fd36db4cc86865 \
--hash=sha256:96603a562b546632441926cd1293cfcb5b69f0b4159e6077f7c7dbdfb686af4d \
--hash=sha256:9de50a199b7710fa2904be5a4a9b51af587ab24c8e540a7243ab737b45844543 \
--hash=sha256:a2ece4af1f3c967a4390c284797ab595a9f1bc1130ef8b01828915a05a6ae684 \
--hash=sha256:ad1407db8f2f49329729564f71685557157bfa42b48f4b93e53721a16eb813ed \
--hash=sha256:b0cf2a4501bff9330a8a5248b4ce951851e415bdcce9dc158e76cfd55e15085c \
--hash=sha256:ccc360e87341ad47c777f5723f68adbb52b37ab450c8bc3ca9ca1f3e849e5fe2 \
--hash=sha256:d76e8b13161a202d14c9584590c4df4d068c9567c99506497bdd67eaedf36403 \
--hash=sha256:e1d8cb0b56b3587c5c01de3bf2f600f186da7e7b5f7353d1bf26a8ddca57f965 \
--hash=sha256:e3f1e3f1a1751bb62b4a1b7f4e435afcdade6c17a4fd9b9d43607cebd242924a \
--hash=sha256:e6a00ffcc173e765e200ceefb06399ba09c06db97f401f920513a10c803604ca \
--hash=sha256:ec00c3305788e04bf6d29d42e504560e159ccaf0be30c09203b468a6c1ccd3b2 \
--hash=sha256:efd2fcf7e7b9d7ab16e6b7d54205beded0a9c8566cb30f09c1abe42b4e22bdcb
aiohttp==3.9.3 \
--hash=sha256:039df344b45ae0b34ac885ab5b53940b174530d4dd8a14ed8b0e2155b9dddccb \
--hash=sha256:055ce4f74b82551678291473f66dc9fb9048a50d8324278751926ff0ae7715e5 \
--hash=sha256:07b837ef0d2f252f96009e9b8435ec1fef68ef8b1461933253d318748ec1acdc \
--hash=sha256:1f5a71d25cd8106eab05f8704cd9167b6e5187bcdf8f090a66c6d88b634802b4 \
--hash=sha256:1f5cd333fcf7590a18334c90f8c9147c837a6ec8a178e88d90a9b96ea03194cc \
--hash=sha256:2c895a656dd7e061b2fd6bb77d971cc38f2afc277229ce7dd3552de8313a483e \
--hash=sha256:38a19bc3b686ad55804ae931012f78f7a534cce165d089a2059f658f6c91fa60 \
--hash=sha256:38f307b41e0bea3294a9a2a87833191e4bcf89bb0365e83a8be3a58b31fb7f38 \
--hash=sha256:3e59c23c52765951b69ec45ddbbc9403a8761ee6f57253250c6e1536cacc758b \
--hash=sha256:504b6981675ace64c28bf4a05a508af5cde526e36492c98916127f5a02354d53 \
--hash=sha256:50fca156d718f8ced687a373f9e140c1bb765ca16e3d6f4fe116e3df7c05b2c5 \
--hash=sha256:52df73f14ed99cee84865b95a3d9e044f226320a87af208f068ecc33e0c35b96 \
--hash=sha256:5eafe2c065df5401ba06821b9a054d9cb2848867f3c59801b5d07a0be3a380ae \
--hash=sha256:5ed3e046ea7b14938112ccd53d91c1539af3e6679b222f9469981e3dac7ba1ce \
--hash=sha256:5fe9ce6c09668063b8447f85d43b8d1c4e5d3d7e92c63173e6180b2ac5d46dd8 \
--hash=sha256:6b0e029353361f1746bac2e4cc19b32f972ec03f0f943b390c4ab3371840aabf \
--hash=sha256:6b88f9386ff1ad91ace19d2a1c0225896e28815ee09fc6a8932fded8cda97c3d \
--hash=sha256:770d015888c2a598b377bd2f663adfd947d78c0124cfe7b959e1ef39f5b13869 \
--hash=sha256:7943c414d3a8d9235f5f15c22ace69787c140c80b718dcd57caaade95f7cd93b \
--hash=sha256:7cf5c9458e1e90e3c390c2639f1017a0379a99a94fdfad3a1fd966a2874bba52 \
--hash=sha256:82e6aa28dd46374f72093eda8bcd142f7771ee1eb9d1e223ff0fa7177a96b4a5 \
--hash=sha256:84871a243359bb42c12728f04d181a389718710129b36b6aad0fc4655a7647d4 \
--hash=sha256:90842933e5d1ff760fae6caca4b2b3edba53ba8f4b71e95dacf2818a2aca06f7 \
--hash=sha256:938a9653e1e0c592053f815f7028e41a3062e902095e5a7dc84617c87267ebd5 \
--hash=sha256:939677b61f9d72a4fa2a042a5eee2a99a24001a67c13da113b2e30396567db54 \
--hash=sha256:9d3c9b50f19704552f23b4eaea1fc082fdd82c63429a6506446cbd8737823da3 \
--hash=sha256:a6fe5571784af92b6bc2fda8d1925cccdf24642d49546d3144948a6a1ed58ca5 \
--hash=sha256:a78ed8a53a1221393d9637c01870248a6f4ea5b214a59a92a36f18151739452c \
--hash=sha256:ab40e6251c3873d86ea9b30a1ac6d7478c09277b32e14745d0d3c6e76e3c7e29 \
--hash=sha256:acef0899fea7492145d2bbaaaec7b345c87753168589cc7faf0afec9afe9b747 \
--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 \
--hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \
--hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17
asgiref==3.7.2 \
--hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
--hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
async-timeout==4.0.3 \
--hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
--hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
attrs==23.1.0 \
--hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \
--hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015
blinker==1.7.0 \
--hash=sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9 \
--hash=sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182
brotli==1.1.0 \
--hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \
--hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \
@@ -131,6 +152,12 @@ charset-normalizer==3.3.0 \
--hash=sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293 \
--hash=sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e \
--hash=sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e
click==8.1.7 \
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
flask==3.0.1 \
--hash=sha256:6489f51bb3666def6f314e15f19d50a1869a19ae0e8c9a3641ffe66c77d42403 \
--hash=sha256:ca631a507f6dfe6c278ae20112cea3ff54ff2216390bf8880f6b035a5354af13
frozenlist==1.4.0 \
--hash=sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01 \
--hash=sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251 \
@@ -166,15 +193,53 @@ frozenlist==1.4.0 \
idna==3.4 \
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
itsdangerous==2.1.2 \
--hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
--hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
Jinja2==3.1.3 \
--hash=sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa \
--hash=sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90
markdown-it-py==3.0.0 \
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
MarkupSafe==2.1.4 \
--hash=sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69 \
--hash=sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0 \
--hash=sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d \
--hash=sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74 \
--hash=sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d \
--hash=sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f \
--hash=sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6 \
--hash=sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656 \
--hash=sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc \
--hash=sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56 \
--hash=sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc \
--hash=sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250 \
--hash=sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc \
--hash=sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863 \
--hash=sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8 \
--hash=sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f \
--hash=sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2 \
--hash=sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e \
--hash=sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e \
--hash=sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb \
--hash=sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26 \
--hash=sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131 \
--hash=sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858 \
--hash=sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e \
--hash=sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84 \
--hash=sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7 \
--hash=sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea \
--hash=sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b \
--hash=sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6 \
--hash=sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475 \
--hash=sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74
mdurl==0.1.2 \
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
miservice-fork==2.2.1 \
--hash=sha256:cf8f3e30b3008de29a69d9a8293cca8428e670ae10a0f791840428ee947fc27e \
--hash=sha256:f3f742ccd7cb4a1ed22cfdf95da14f791eff0c6c3a54032dcfe445ae540664df
miservice-fork==2.3.2 \
--hash=sha256:1c907289cd354c349ead5e5b1f08e22aa23b8fa01114ecc7a2800e463751ba5b \
--hash=sha256:f24c40366df99d5db706f09528692bc490390fe7db950aa32f4948bafdc1a03d
multidict==6.0.4 \
--hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \
--hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \
@@ -238,52 +303,69 @@ pygments==2.16.1 \
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
rich==13.6.0 \
--hash=sha256:2b38e2fe9ca72c9a00170a1a2d20c63c790d0e10ef1fe35eba76e1e7b1d7d245 \
--hash=sha256:5c14d22737e6d5084ef4771b62d5d4363165b403455a30a1c8ca39dc7b644bef
rich==13.7.0 \
--hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \
--hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235
typing-extensions==4.9.0 \
--hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
--hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
urllib3==2.0.6 \
--hash=sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2 \
--hash=sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564
websockets==11.0.3 \
--hash=sha256:01f5567d9cf6f502d655151645d4e8b72b453413d3819d2b6f1185abc23e82dd \
--hash=sha256:0ac56b661e60edd453585f4bd68eb6a29ae25b5184fd5ba51e97652580458998 \
--hash=sha256:0ee68fe502f9031f19d495dae2c268830df2760c0524cbac5d759921ba8c8e82 \
--hash=sha256:1d2256283fa4b7f4c7d7d3e84dc2ece74d341bce57d5b9bf385df109c2a1a82f \
--hash=sha256:1d5023a4b6a5b183dc838808087033ec5df77580485fc533e7dab2567851b0a4 \
--hash=sha256:2d903ad4419f5b472de90cd2d40384573b25da71e33519a67797de17ef849b69 \
--hash=sha256:3ccc8a0c387629aec40f2fc9fdcb4b9d5431954f934da3eaf16cdc94f67dbfac \
--hash=sha256:41f696ba95cd92dc047e46b41b26dd24518384749ed0d99bea0a941ca87404c4 \
--hash=sha256:42cc5452a54a8e46a032521d7365da775823e21bfba2895fb7b77633cce031bb \
--hash=sha256:54c6e5b3d3a8936a4ab6870d46bdd6ec500ad62bde9e44462c32d18f1e9a8e54 \
--hash=sha256:619d9f06372b3a42bc29d0cd0354c9bb9fb39c2cbc1a9c5025b4538738dbffaf \
--hash=sha256:660e2d9068d2bedc0912af508f30bbeb505bbbf9774d98def45f68278cea20d3 \
--hash=sha256:6681ba9e7f8f3b19440921e99efbb40fc89f26cd71bf539e45d8c8a25c976dc6 \
--hash=sha256:7622a89d696fc87af8e8d280d9b421db5133ef5b29d3f7a1ce9f1a7bf7fcfa11 \
--hash=sha256:84d27a4832cc1a0ee07cdcf2b0629a8a72db73f4cf6de6f0904f6661227f256f \
--hash=sha256:8531fdcad636d82c517b26a448dcfe62f720e1922b33c81ce695d0edb91eb931 \
--hash=sha256:86d2a77fd490ae3ff6fae1c6ceaecad063d3cc2320b44377efdde79880e11526 \
--hash=sha256:88fc51d9a26b10fc331be344f1781224a375b78488fc343620184e95a4b27016 \
--hash=sha256:92b2065d642bf8c0a82d59e59053dd2fdde64d4ed44efe4870fa816c1232647b \
--hash=sha256:aa5003845cdd21ac0dc6c9bf661c5beddd01116f6eb9eb3c8e272353d45b3288 \
--hash=sha256:b30c6590146e53149f04e85a6e4fcae068df4289e31e4aee1fdf56a0dead8f97 \
--hash=sha256:b58cbf0697721120866820b89f93659abc31c1e876bf20d0b3d03cef14faf84d \
--hash=sha256:b67c6f5e5a401fc56394f191f00f9b3811fe843ee93f4a70df3c389d1adf857d \
--hash=sha256:bceab846bac555aff6427d060f2fcfff71042dba6f5fca7dc4f75cac815e57ca \
--hash=sha256:c114e8da9b475739dde229fd3bc6b05a6537a88a578358bc8eb29b4030fac9c9 \
--hash=sha256:c1f0524f203e3bd35149f12157438f406eff2e4fb30f71221c8a5eceb3617b6b \
--hash=sha256:d67ac60a307f760c6e65dad586f556dde58e683fab03323221a4e530ead6f74d \
--hash=sha256:dcacf2c7a6c3a84e720d1bb2b543c675bf6c40e460300b628bab1b1efc7c034c \
--hash=sha256:de36fe9c02995c7e6ae6efe2e205816f5f00c22fd1fbf343d4d18c3d5ceac2f5 \
--hash=sha256:def07915168ac8f7853812cc593c71185a16216e9e4fa886358a17ed0fd9fcf6 \
--hash=sha256:e052b8467dd07d4943936009f46ae5ce7b908ddcac3fda581656b1b19c083d9b \
--hash=sha256:e063b1865974611313a3849d43f2c3f5368093691349cf3c7c8f8f75ad7cb280 \
--hash=sha256:e1459677e5d12be8bbc7584c35b992eea142911a6236a3278b9b5ce3326f282c \
--hash=sha256:e6316827e3e79b7b8e7d8e3b08f4e331af91a48e794d5d8b099928b6f0b85f20 \
--hash=sha256:e7837cb169eca3b3ae94cc5787c4fed99eef74c0ab9506756eea335e0d6f3ed8 \
--hash=sha256:e848f46a58b9fcf3d06061d17be388caf70ea5b8cc3466251963c8345e13f7eb \
--hash=sha256:ed058398f55163a79bb9f06a90ef9ccc063b204bb346c4de78efc5d15abfe602 \
--hash=sha256:f2e58f2c36cc52d41f2659e4c0cbf7353e28c8c9e63e30d8c6d3494dc9fdedcf \
--hash=sha256:ffd7dcaf744f25f82190856bc26ed81721508fc5cbf2a330751e135ff1283564
websockets==12.0 \
--hash=sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b \
--hash=sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6 \
--hash=sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df \
--hash=sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b \
--hash=sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2 \
--hash=sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed \
--hash=sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd \
--hash=sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b \
--hash=sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931 \
--hash=sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30 \
--hash=sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370 \
--hash=sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be \
--hash=sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf \
--hash=sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b \
--hash=sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402 \
--hash=sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f \
--hash=sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123 \
--hash=sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603 \
--hash=sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45 \
--hash=sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558 \
--hash=sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4 \
--hash=sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480 \
--hash=sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447 \
--hash=sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8 \
--hash=sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04 \
--hash=sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c \
--hash=sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb \
--hash=sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b \
--hash=sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c \
--hash=sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92 \
--hash=sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113 \
--hash=sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f \
--hash=sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468 \
--hash=sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611 \
--hash=sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d \
--hash=sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca \
--hash=sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f \
--hash=sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2 \
--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 \
--hash=sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc \
--hash=sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10
yarl==1.9.2 \
--hash=sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571 \
--hash=sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7 \
@@ -316,6 +398,6 @@ yarl==1.9.2 \
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560
yt-dlp==2023.10.13 \
--hash=sha256:2b069f22675532eebacdfd6372b1825651a751fef848de9ae6efe6491b2dc38a \
--hash=sha256:e026ea1c435ff36eef1215bc4c5bb8c479938b90054997ba99f63a4541fe63b4
yt-dlp==2024.2.2.232707.dev0 \
--hash=sha256:7ff05434979d89e2a7c344d6771cc60229901fe4182c19a756472bb49a50e3b8 \
--hash=sha256:fd8d85f64842038cbdaaf7ee5812d98beed64fdcb4612f6e80b2c721bad13262

1
update-requirements.sh Normal file
View File

@@ -0,0 +1 @@
pdm export -o requirements.txt

View File

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

View File

@@ -12,51 +12,83 @@ LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation
COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}"
HARDWARE_COMMAND_DICT = {
# hardware: (tts_command, wakeup_command)
"LX06": ("5-1", "5-5"),
"L05B": ("5-3", "5-4"),
"S12A": ("5-1", "5-5"),
"LX01": ("5-1", "5-5"),
"L06A": ("5-1", "5-5"),
"LX04": ("5-1", "5-4"),
"L05C": ("5-3", "5-4"),
"L17A": ("7-3", "7-4"),
"X08E": ("7-3", "7-4"),
"LX05A": ("5-1", "5-5"), # 小爱红外版
"LX5A": ("5-1", "5-5"), # 小爱红外版
"L07A": ("5-1", "5-5"), # Redmi小爱音箱Play(l7a)
"L15A": ("7-3", "7-4"),
"X6A": ("7-3", "7-4"), # 小米智能家庭屏6
"X10A": ("7-3", "7-4"), # 小米智能家庭屏10
# hardware: (tts_command, wakeup_command, volume_command)
"LX06": ("5-1", "5-5", "2-1"),
"L05B": ("5-3", "5-4", "2-1"),
"S12A": ("5-1", "5-5", "2-1"),
"LX01": ("5-1", "5-5", "2-1"),
"L06A": ("5-1", "5-5", "2-1"),
"LX04": ("5-1", "5-4", "2-1"),
"L05C": ("5-3", "5-4", "2-1"),
"L17A": ("7-3", "7-4", "2-1"),
"X08E": ("7-3", "7-4", "2-1"),
"LX05A": ("5-1", "5-5", "2-1"), # 小爱红外版
"LX5A": ("5-1", "5-5", "2-1"), # 小爱红外版
"L07A": ("5-1", "5-5", "2-1"), # Redmi小爱音箱Play(l7a)
"L15A": ("7-3", "7-4", "2-1"),
"X6A": ("7-3", "7-4", "2-1"), # 小米智能家庭屏6
"X10A": ("7-3", "7-4", "2-1"), # 小米智能家庭屏10
# add more here
}
DEFAULT_COMMAND = ("5-1", "5-5")
DEFAULT_COMMAND = ("5-1", "5-5", "2-1")
KEY_WORD_DICT = {
"播放歌曲": "play",
"放歌曲": "play",
"下一首": "play_next",
"单曲循环":"set_play_type_one",
"全部循环":"set_play_type_all",
"关机":"stop",
"停止播放":"stop",
"单曲循环": "set_play_type_one",
"全部循环": "set_play_type_all",
"随机播放": "random_play",
"关机": "stop",
"停止播放": "stop",
"分钟后关机": "stop_after_minute",
"set_volume#": "set_volume",
}
# 命令参数在前面
KEY_WORD_ARG_BEFORE_DICT = {
"分钟后关机": True,
}
# 匹配优先级
KEY_MATCH_ORDER = [
"set_volume#",
"分钟后关机",
"播放歌曲",
"放歌曲",
"下一首",
"单曲循环",
"全部循环",
"随机播放",
"关机",
"停止播放",
]
SUPPORT_MUSIC_TYPE = [
".mp3",
".flac",
]
@dataclass
class Config:
hardware: str = "L07A"
hardware: str = os.getenv("MI_HARDWARE", "L07A")
account: str = os.getenv("MI_USER", "")
password: str = os.getenv("MI_PASS", "")
mi_did: str = os.getenv("MI_DID", "")
mute_xiaoai: bool = True
cookie: str = ""
use_command: bool = True
use_command: bool = False
verbose: bool = False
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
hostname: str = os.getenv("XIAOMUSIC_HOSTNAME", "192.168.2.5")
port: int = int(os.getenv("XIAOMUSIC_PORT", "8090"))
proxy: str = os.getenv("XIAOMUSIC_PROXY", "http://192.168.2.5:8080")
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")
def __post_init__(self) -> None:
if self.proxy:
@@ -70,6 +102,10 @@ class Config:
def wakeup_command(self) -> str:
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
def from_options(cls, options: argparse.Namespace) -> Config:
config = {}

74
xiaomusic/httpserver.py Normal file
View File

@@ -0,0 +1,74 @@
#!/usr/bin/env python3
import os
import traceback
from flask import Flask, request, send_from_directory
from threading import Thread
from xiaomusic.config import (
KEY_WORD_DICT,
)
app = Flask(__name__)
host = "0.0.0.0"
port = 8090
static_path = "music"
xiaomusic = None
log = None
@app.route("/allcmds")
def allcmds():
return KEY_WORD_DICT
@app.route("/getvolume")
def getvolume():
return {
"volume": xiaomusic.get_volume(),
}
@app.route("/", methods=["GET"])
def redirect_to_index():
return send_from_directory("static", "index.html")
@app.route("/cmd", methods=["POST"])
async def do_cmd():
data = request.get_json()
cmd = data.get("cmd")
if len(cmd) > 0:
log.debug("docmd. cmd:%s", cmd)
xiaomusic.set_last_record(cmd)
return {"ret": "OK"}
return {"ret": "Unknow cmd"}
def static_path_handler(filename):
log.debug(filename)
log.debug(static_path)
absolute_path = os.path.abspath(static_path)
log.debug(absolute_path)
return send_from_directory(absolute_path, filename)
def run_app():
app.run(host=host, port=port)
def StartHTTPServer(_port, _static_path, _xiaomusic):
global port, static_path, xiaomusic, log
port = _port
static_path = _static_path
xiaomusic = _xiaomusic
log = xiaomusic.log
app.add_url_rule(
f"/{static_path}/<path:filename>", "static_path_handler", static_path_handler
)
server_thread = Thread(target=run_app)
server_thread.daemon = True
server_thread.start()
xiaomusic.log.info(f"Serving on {host}:{port}")

66
xiaomusic/static/app.js Normal file
View File

@@ -0,0 +1,66 @@
$(function(){
$container=$("#cmds");
append_op_button_name("下一首");
append_op_button_name("全部循环");
append_op_button_name("关机");
append_op_button_name("单曲循环");
append_op_button_name("播放歌曲");
append_op_button_name("随机播放");
$container.append($("<hr>"));
append_op_button_name("10分钟后关机");
append_op_button_name("30分钟后关机");
append_op_button_name("60分钟后关机");
// 拉取声音
$.get("/getvolume", function(data, status) {
console.log(data, status, data["volume"]);
$("#volume").val(data.volume);
});
function append_op_button_name(name) {
append_op_button(name, name);
}
function append_op_button(name, cmd) {
// 创建按钮
const $button = $("<button>");
$button.text(name);
$button.attr("type", "button");
// 设置按钮点击事件
$button.on("click", () => {
sendcmd(cmd);
});
// 添加按钮到容器
$container.append($button);
}
$("#play").on("click", () => {
name = $("#music-name").val();
let cmd = "播放歌曲"+name;
sendcmd(cmd);
});
$("#volume").on('input', function () {
var value = $(this).val();
sendcmd("set_volume#"+value);
});
function sendcmd(cmd) {
$.ajax({
type: "POST",
url: "/cmd",
contentType: "application/json",
data: JSON.stringify({cmd: cmd}),
success: () => {
// 请求成功时执行的操作
},
error: () => {
// 请求失败时执行的操作
}
});
}
});

View File

@@ -0,0 +1,51 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width">
<title>小爱音箱操控面板</title>
<script src="/static/jquery-3.7.1.min.js"></script>
<script src="/static/app.js"></script>
<style>
button {
margin: 10px;
width: 100px;
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 {
margin: 10px;
width: 200px;
height: 40px;
}
</style>
</head>
<body>
<h2>小爱音箱操控面板</h2>
<hr>
<div id="cmds">
</div>
<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>
<input id="music-name" type="text" placeholder="请输入歌曲名称"></input>
<button id="play">播放</button>
</div>
</body>
</html>

2
xiaomusic/static/jquery-3.7.1.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@@ -1,22 +1,15 @@
#!/usr/bin/env python3
import asyncio
import functools
import http.server
import io
import json
import logging
import os
import random
import re
import shutil
import socket
import socketserver
import tempfile
import threading
import time
import urllib.parse
import traceback
import mutagen.mp3
import mutagen
from xiaomusic.httpserver import StartHTTPServer
from pathlib import Path
@@ -29,6 +22,9 @@ from xiaomusic.config import (
COOKIE_TEMPLATE,
LATEST_ASK_API,
KEY_WORD_DICT,
KEY_WORD_ARG_BEFORE_DICT,
KEY_MATCH_ORDER,
SUPPORT_MUSIC_TYPE,
Config,
)
from xiaomusic.utils import (
@@ -38,28 +34,9 @@ from xiaomusic.utils import (
EOF = object()
PLAY_TYPE_ONE = 0 # 单曲循环
PLAY_TYPE_ALL = 1 # 全部循环
PLAY_TYPE_ONE = 0 # 单曲循环
PLAY_TYPE_ALL = 1 # 全部循环
class ThreadedHTTPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass
class HTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
logger = logging.getLogger("xiaomusic")
def log_message(self, format, *args):
self.logger.debug(f"{self.address_string()} - {format}", *args)
def log_error(self, format, *args):
self.logger.error(f"{self.address_string()} - {format}", *args)
def copyfile(self, source, outputfile):
try:
super().copyfile(source, outputfile)
except (socket.error, ConnectionResetError, BrokenPipeError):
# ignore this or TODO find out why the error later
pass
class XiaoMusic:
def __init__(self, config: Config):
@@ -79,14 +56,22 @@ class XiaoMusic:
self.hostname = config.hostname
self.port = config.port
self.proxy = config.proxy
self.search_prefix = config.search_prefix
self.ffmpeg_location = config.ffmpeg_location
# 下载对象
self.download_proc = None
# 单曲循环,全部循环
self.play_type = PLAY_TYPE_ONE
self.play_type = PLAY_TYPE_ALL
self.cur_music = ""
self._next_timer = None
self._timeout = 0
self._volume = 50
self._all_music = {}
self._play_list = []
# 关机定时器
self._stop_timer = None
# setup logger
self.log = logging.getLogger("xiaomusic")
@@ -94,6 +79,11 @@ class XiaoMusic:
self.log.addHandler(RichHandler())
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 with ClientSession() as session:
session._cookie_jar = self.cookie_jar
@@ -115,7 +105,6 @@ class XiaoMusic:
await self._init_data_hardware()
session.cookie_jar.update_cookies(self.get_cookie())
self.cookie_jar = session.cookie_jar
self.start_http_server()
async def login_miboy(self, session):
account = MiAccount(
@@ -225,8 +214,22 @@ class XiaoMusic:
self.last_record = last_record
self.new_record_event.set()
# 手动发消息
def set_last_record(self, query):
self.last_record = {
"query": query,
}
self.new_record_event.set()
async def do_tts(self, value, wait_for_finish=False):
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:
try:
await self.mina_service.text_to_speech(self.device_id, value)
@@ -243,23 +246,28 @@ class XiaoMusic:
await asyncio.sleep(elapse)
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):
while True:
if not await self.get_if_xiaoai_is_playing():
break
await asyncio.sleep(1)
def start_http_server(self):
# create the server
handler = functools.partial(HTTPRequestHandler, directory=self.music_path)
httpd = ThreadedHTTPServer(("", self.port), handler)
# start the server in a new thread
server_thread = threading.Thread(target=httpd.serve_forever)
server_thread.daemon = True
server_thread.start()
self.log.info(f"Serving on {self.hostname}:{self.port}")
async def get_if_xiaoai_is_playing(self):
playing_info = await self.mina_service.player_get_status(self.device_id)
# WTF xiaomi api
@@ -286,64 +294,121 @@ class XiaoMusic:
def is_downloading(self):
if not self.download_proc:
return False
if self.download_proc.returncode != None \
and self.download_proc.returncode < 0:
if self.download_proc.returncode != None and self.download_proc.returncode < 0:
return False
return True
# 下载歌曲
async def download(self, name):
if self.download_proc:
self.download_proc.kill()
try:
self.download_proc.kill()
except ProcessLookupError:
pass
self.download_proc = await asyncio.create_subprocess_exec(
"yt-dlp", f"ytsearch:{name}",
"-x", "--audio-format", "mp3",
"--paths", self.music_path,
"-o", f"{name}.mp3",
"--proxy", f"{self.proxy}",
"--ffmpeg-location", "./ffmpeg/bin")
sbp_args = (
"yt-dlp",
f"{self.search_prefix}{name}",
"-x",
"--audio-format",
"mp3",
"--paths",
self.music_path,
"-o",
f"{name}.mp3",
"--ffmpeg-location",
f"{self.ffmpeg_location}",
"--no-playlist",
)
if self.proxy:
sbp_args += ("--proxy", f"{self.proxy}")
self.download_proc = await asyncio.create_subprocess_exec(*sbp_args)
await self.do_tts(f"正在下载歌曲{name}")
def get_filename(self, name):
filename = os.path.join(self.music_path, f"{name}.mp3")
return filename
# 本地是否存在歌曲
def local_exist(self, name):
filename = self.get_filename(name)
self.log.debug("local_exist. filename:%s", filename)
return os.path.exists(filename)
def get_filename(self, name):
if name not in self._all_music:
return ""
filename = self._all_music[name]
self.log.debug("try get_filename. filename:%s", filename)
if os.path.exists(filename):
return filename
return ""
# 获取歌曲播放地址
def get_file_url(self, name):
encoded_name = urllib.parse.quote(os.path.basename(name))
return f"http://{self.hostname}:{self.port}/{encoded_name}.mp3"
filename = self.get_filename(name)
self.log.debug("get_file_url. name:%s, filename:%s", name, filename)
encoded_name = urllib.parse.quote(filename)
return f"http://{self.hostname}:{self.port}/{encoded_name}"
# 随机获取一首音乐
def random_music(self):
files = os.listdir(self.music_path)
# 过滤 mp3 文件
mp3_files = [file for file in files if file.endswith(".mp3")]
if len(mp3_files) == 0:
# 递归获取目录下所有歌曲,生成随机播放列表
def gen_all_music_list(self):
self._all_music = {}
for root, dirs, filenames in os.walk(self.music_path):
for filename in filenames:
self.log.debug("gen_all_music_list. filename:%s", filename)
# 过滤隐藏文件
if filename.startswith("."):
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
# 歌曲名字相同会覆盖
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"没有随机到歌曲")
return ""
# 随机选择一个文件
mp3_file = random.choice(mp3_files)
name = mp3_file[:-4]
self.log.info(f"随机到歌曲{name}")
return name
index = 0
try:
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
# 获取mp3文件播放时长
def get_mp3_duration(self, name):
filename = self.get_filename(name)
audio = mutagen.mp3.MP3(filename)
return audio.info.length
# 获取文件播放时长
def get_file_duration(self, filename):
# 获取音频文件对象
audio = mutagen.File(filename)
# 获取播放时长
duration = audio.info.length
return duration
# 设置下一首歌曲的播放定时器
def set_next_music_timeout(self):
sec = int(self.get_mp3_duration(self.cur_music))
self.log.info(f"歌曲{self.cur_music}的时长{sec}")
filename = self.get_filename(self.cur_music)
sec = int(self.get_file_duration(filename))
self.log.info(f"歌曲 {self.cur_music} : {filename} 的时长 {sec}")
if self._next_timer:
self._next_timer.cancel()
self.log.info(f"定时器已取消")
@@ -351,7 +416,10 @@ class XiaoMusic:
async def _do_next():
await asyncio.sleep(self._timeout)
await self.play_next()
try:
await self.play_next()
except Exception as e:
self.log.warning(f"执行出错 {str(e)}\n{traceback.format_exc()}")
self._next_timer = asyncio.ensure_future(_do_next())
self.log.info(f"{sec}秒后将会播放下一首")
@@ -360,9 +428,13 @@ class XiaoMusic:
async with ClientSession() as session:
self.session = session
await self.init_all_data(session)
StartHTTPServer(self.port, self.music_path, self)
task = asyncio.create_task(self.poll_latest_ask())
assert task is not None # to keep the reference to task, do not remove this
self.log.info(f"Running xiaomusic now, 用`{'/'.join(KEY_WORD_DICT.keys())}`开头来控制")
self.log.info(
f"Running xiaomusic now, 用`{'/'.join(KEY_WORD_DICT.keys())}`开头来控制"
)
while True:
self.polling_event.set()
await self.new_record_event.wait()
@@ -373,42 +445,60 @@ class XiaoMusic:
self.log.debug("收到消息:%s", query)
# 匹配命令
match = re.match(rf"^({'|'.join(KEY_WORD_DICT.keys())})", query)
if not match:
opvalue, oparg = self.match_cmd(query)
if not opvalue:
await asyncio.sleep(1)
continue
if self.config.mute_xiaoai:
await self.stop_if_xiaoai_is_playing()
else:
# waiting for xiaoai speaker done
await asyncio.sleep(8)
opkey = match.groups()[0]
opvalue = KEY_WORD_DICT[opkey]
oparg = query[len(opkey):]
self.log.info("收到指令:%s %s", opkey, oparg)
try:
func = getattr(self, opvalue)
await func(name = oparg)
await func(arg1=oparg)
except Exception as e:
self.log.warning(f"执行出错 {str(e)}\n{traceback.format_exc()}")
# 匹配命令
def match_cmd(self, query):
for opkey in KEY_MATCH_ORDER:
patternarg = rf"(.*){opkey}(.*)"
# 匹配参数
matcharg = re.match(patternarg, query)
if not matcharg:
# self.log.debug(patternarg)
continue
argpre = matcharg.groups()[0]
argafter = matcharg.groups()[1]
self.log.debug(
"matcharg. opkey:%s, argpre:%s, argafter:%s",
opkey,
argpre,
argafter,
)
oparg = argafter
opvalue = KEY_WORD_DICT[opkey]
if opkey in KEY_WORD_ARG_BEFORE_DICT:
oparg = argpre
self.log.info("匹配到指令. opkey:%s opvalue:%s oparg:%s", opkey, opvalue, oparg)
return (opvalue, oparg)
return (None, None)
# 播放歌曲
async def play(self, **kwargs):
name = kwargs["name"]
name = kwargs["arg1"]
if name == "":
await self.play_next()
return
await self.do_tts(f"即将播放{name}")
if not self.local_exist(name):
filename = self.get_filename(name)
if len(filename) <= 0:
await self.download(name)
self.log.info("正在下载中 %s", name)
await self.download_proc.wait()
# 把文件插入到播放列表里
self.add_download_music(name)
self.cur_music = name
self.log.info("cur_music %s", self.cur_music)
url = self.get_file_url(name)
self.log.info("播放 %s", url)
await self.stop_if_xiaoai_is_playing()
@@ -421,12 +511,13 @@ class XiaoMusic:
async def play_next(self, **kwargs):
self.log.info("下一首")
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 == "":
name = self.random_music()
name = self.get_next_music()
if name == "":
await self.do_tts(f"本地没有歌曲")
return
await self.play(name=name)
await self.play(arg1=name)
# 单曲循环
async def set_play_type_one(self, **kwargs):
@@ -438,8 +529,41 @@ class XiaoMusic:
self.play_type = PLAY_TYPE_ALL
await self.do_tts(f"已经设置为全部循环")
# 随机播放
async def random_play(self, **kwargs):
self.play_type = PLAY_TYPE_ALL
await self.do_tts(f"已经设置为全部循环并随机播放")
# 重新生成随机播放列表
self.gen_all_music_list()
await self.play_next()
async def stop(self, **kwargs):
if self._next_timer:
self._next_timer.cancel()
self.log.info(f"定时器已取消")
await self.stop_if_xiaoai_is_playing()
async def stop_after_minute(self, **kwargs):
if self._stop_timer:
self._stop_timer.cancel()
self.log.info(f"关机定时器已取消")
minute = int(kwargs["arg1"])
async def _do_stop():
await asyncio.sleep(minute * 60)
try:
await self.stop()
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}分钟后将关机")
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