mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-06 14:52:50 +08:00
Compare commits
181 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5ab8e398a | ||
|
|
8907e41818 | ||
|
|
af25300917 | ||
|
|
f18b2f49bf | ||
|
|
db1e4e6fc4 | ||
|
|
dc49f63a37 | ||
|
|
6837841872 | ||
|
|
637347ae0c | ||
|
|
ff968c4db4 | ||
|
|
ca547e0d81 | ||
|
|
f0931c447b | ||
|
|
d098b5eb60 | ||
|
|
09111e849d | ||
|
|
49a76dee60 | ||
|
|
637672473e | ||
|
|
e4e1d13b69 | ||
|
|
7736f8c5b4 | ||
|
|
29db69b52f | ||
|
|
37fe51771b | ||
|
|
77ece713dc | ||
|
|
4436cc3a15 | ||
|
|
c875350112 | ||
|
|
d6df2f6bfe | ||
|
|
03e3312218 | ||
|
|
5d7451c3f2 | ||
|
|
551dfa0c7f | ||
|
|
3cc35e8f97 | ||
|
|
01c68ba64e | ||
|
|
61d167d347 | ||
|
|
9393e9f1ca | ||
|
|
c08ef030e9 | ||
|
|
bad13f01f4 | ||
|
|
049e1a2c38 | ||
|
|
a9fb829563 | ||
|
|
e66f731301 | ||
|
|
538ac1d485 | ||
|
|
88fbc503e7 | ||
|
|
1dc3ccbc16 | ||
|
|
df007d8e1b | ||
|
|
0876551795 | ||
|
|
51acb3ac8e | ||
|
|
786af1c79e | ||
|
|
7fba78e44b | ||
|
|
9434cf3216 | ||
|
|
f71ab25407 | ||
|
|
a634813c21 | ||
|
|
17279aaae0 | ||
|
|
4a234e8829 | ||
|
|
805b3c41c8 | ||
|
|
7a154fd847 | ||
|
|
3cdc836e9e | ||
|
|
d232627796 | ||
|
|
579820e606 | ||
|
|
a24a5166f9 | ||
|
|
ad67894244 | ||
|
|
725d4c4ab3 | ||
|
|
6a0310fe05 | ||
|
|
463fd9dd38 | ||
|
|
34fe19abd1 | ||
|
|
3365f082f7 | ||
|
|
13361c57b8 | ||
|
|
2a22b00d53 | ||
|
|
925b52d979 | ||
|
|
468efb63fb | ||
|
|
38aae7eca3 | ||
|
|
44df1134a8 | ||
|
|
243c1673db | ||
|
|
82eab4810c | ||
|
|
e0a59b5729 | ||
|
|
ad3bad85db | ||
|
|
743d85de32 | ||
|
|
8bd32f878f | ||
|
|
eccb52c197 | ||
|
|
603d60d8b8 | ||
|
|
3ef04f4159 | ||
|
|
7888ee7938 | ||
|
|
b2a3cda7b5 | ||
|
|
80c6d29079 | ||
|
|
0b020deaef | ||
|
|
74c8bea756 | ||
|
|
af10d6261f | ||
|
|
a178278576 | ||
|
|
474fea8434 | ||
|
|
d271f7b0f7 | ||
|
|
7e2af515ed | ||
|
|
2d403ff18c | ||
|
|
f08244a990 | ||
|
|
4869e5cf80 | ||
|
|
b887504f9f | ||
|
|
ad43a4f732 | ||
|
|
8699938b61 | ||
|
|
40bd099153 | ||
|
|
750923d5ca | ||
|
|
6d99b30e2d | ||
|
|
a155f16560 | ||
|
|
d4aa045487 | ||
|
|
8080dd9822 | ||
|
|
2eab8d8113 | ||
|
|
b51e56718a | ||
|
|
088d448e10 | ||
|
|
4a89b4bce5 | ||
|
|
b351b4bcd4 | ||
|
|
b2edaf48e4 | ||
|
|
33e02cee82 | ||
|
|
91a8c9eb50 | ||
|
|
50da8a0554 | ||
|
|
42b5978d89 | ||
|
|
bf29fc67b4 | ||
|
|
dbc68d6b56 | ||
|
|
5dabf66e7c | ||
|
|
d6e4478eb6 | ||
|
|
23ef4719ba | ||
|
|
d799a85ab9 | ||
|
|
4ad6bcc636 | ||
|
|
d2473ec7e8 | ||
|
|
28797edc7c | ||
|
|
be1a643071 | ||
|
|
ee6b9778ac | ||
|
|
881c34bcb5 | ||
|
|
c22fc99235 | ||
|
|
0874efe58b | ||
|
|
f01665c998 | ||
|
|
ac23080f6a | ||
|
|
15ee6c4dd1 | ||
|
|
aeaa8f8925 | ||
|
|
59d7e056c4 | ||
|
|
e79afa46b3 | ||
|
|
9714f3d064 | ||
|
|
2c35c6cfd6 | ||
|
|
88f0ce7e51 | ||
|
|
e484164fad | ||
|
|
aa6bce75cd | ||
|
|
512efb595a | ||
|
|
e5dea8e693 | ||
|
|
a704f8003c | ||
|
|
349a25ad58 | ||
|
|
746f46edb3 | ||
|
|
4a29c7a124 | ||
|
|
0e1e412ee9 | ||
|
|
2e84f7c830 | ||
|
|
61a0d68b6a | ||
|
|
ae90029d8e | ||
|
|
ccc83a518c | ||
|
|
7884a5769f | ||
|
|
a663bb330e | ||
|
|
346f0af543 | ||
|
|
49ec1bb7c0 | ||
|
|
fc0cc75dea | ||
|
|
6fc2be5d31 | ||
|
|
db680bf1ba | ||
|
|
1c2b97c0d2 | ||
|
|
59cfbb06a4 | ||
|
|
9291676543 | ||
|
|
0d2ba60728 | ||
|
|
cd1461df6d | ||
|
|
37abfd9ce2 | ||
|
|
c6de3dfd00 | ||
|
|
ae297c780a | ||
|
|
e07a06c8e4 | ||
|
|
1c91f39417 | ||
|
|
13d26be0a2 | ||
|
|
c2740533a8 | ||
|
|
abbc2f25bb | ||
|
|
04b9738a77 | ||
|
|
f5932a301e | ||
|
|
f11e194e6a | ||
|
|
259e47d4d3 | ||
|
|
96c3e00902 | ||
|
|
066414a380 | ||
|
|
b6c7bbb2b7 | ||
|
|
cdce558984 | ||
|
|
a48bb89763 | ||
|
|
e10a8137f4 | ||
|
|
76aeb20268 | ||
|
|
de36ff7d24 | ||
|
|
4b5d5b3a0a | ||
|
|
59f150ebbd | ||
|
|
4e2d39abac | ||
|
|
a35cde5d4a | ||
|
|
bbdf41f334 | ||
|
|
529aedede0 |
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
github: [hanxi]
|
||||
custom: ['https://afdian.net/a/imhanxi']
|
||||
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
@@ -25,6 +25,6 @@ jobs:
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -61,6 +61,6 @@ jobs:
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}, ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:latest, ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:stable
|
||||
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -164,3 +164,4 @@ cython_debug/
|
||||
ffmpeg
|
||||
music
|
||||
test.sh
|
||||
conf
|
||||
|
||||
@@ -6,7 +6,6 @@ COPY install_dependencies.sh .
|
||||
RUN bash install_dependencies.sh
|
||||
|
||||
FROM python:3.10-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/.venv /app/.venv
|
||||
COPY --from=builder /app/ffmpeg /app/ffmpeg
|
||||
|
||||
187
README.md
187
README.md
@@ -1,8 +1,75 @@
|
||||
# xiaomusic
|
||||
[](https://github.com/hanxi/xiaomusic)
|
||||
[](https://hub.docker.com/r/hanxi/xiaomusic)
|
||||
[](https://hub.docker.com/r/hanxi/xiaomusic)
|
||||
[](https://pypi.org/project/xiaomusic/)
|
||||
[](https://pypi.org/project/xiaomusic/)
|
||||
[](https://pypi.org/project/xiaomusic/)
|
||||
[](https://github.com/hanxi/xiaomusic/releases)
|
||||
|
||||
使用小爱/红米音箱播放音乐,音乐使用 yt-dlp 下载。
|
||||
|
||||
## 运行
|
||||
|
||||
使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。
|
||||
|
||||
<https://github.com/hanxi/xiaomusic>
|
||||
|
||||
## 最简配置运行
|
||||
|
||||
已经支持在 web 页面配置其他参数,docker compose 配置如下:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
xiaomusic:
|
||||
image: hanxi/xiaomusic
|
||||
container_name: xiaomusic
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8090:8090
|
||||
volumes:
|
||||
- ./music:/app/music
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_VERBOSE: 'true'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
```
|
||||
|
||||
对应的 docker 启动命令如下:
|
||||
|
||||
```yaml
|
||||
docker run -e MI_USER='小米账号' \
|
||||
-e MI_PASS='小米密码' \
|
||||
-e XIAOMUSIC_VERBOSE='true' \
|
||||
-e XIAOMUSIC_HOSTNAME='docker 主机 ip' \
|
||||
-p 8090:8090 \
|
||||
-v ./music:/app/music \
|
||||
hanxi/xiaomusic
|
||||
```
|
||||
|
||||
启动成功后,在 web 页面可以配置 MI_DID, MI_HARDWARE, XIAOMUSIC_SEARCH, XIAOMUSIC_PROXY 参数。
|
||||
|
||||
如果需要修改 8090 端口为其他端口,比如 5678,需要这样配,3个数字都需要是 5678
|
||||
```yaml
|
||||
services:
|
||||
xiaomusic:
|
||||
image: hanxi/xiaomusic
|
||||
container_name: xiaomusic
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 5678:5678
|
||||
volumes:
|
||||
- ./music:/app/music
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_VERBOSE: 'true'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
XIAOMUSIC_PORT: 5678
|
||||
```
|
||||
|
||||
其中 XIAOMUSIC_VERBOSE 设置为 'true' 时表示开启 debug 日志,遇到问题可以去 web 设置页面底部【下载日志文件】按钮,然后搜索一下日志文件内容确保里面没有账号密码信息后(有就删除这些敏感信息),然后在提 issues 反馈问题时把下载的日志文件带上。
|
||||
|
||||
## 开发环境运行
|
||||
|
||||
- 使用 install_dependencies.sh 下载依赖
|
||||
- 使用 pdm 安装环境
|
||||
@@ -28,26 +95,60 @@ pdm run xiaomusic.py
|
||||
- 下一首
|
||||
- 单曲循环
|
||||
- 全部循环
|
||||
- 随机播放
|
||||
- 关机
|
||||
- 停止播放
|
||||
- 刷新列表
|
||||
- 播放列表+列表名 比如:播放列表其他
|
||||
|
||||
> 隐藏玩法: 对小爱同学说播放歌曲小猪佩奇的故事,会播放小猪佩奇的故事。
|
||||
|
||||
## 已测试设备
|
||||
## 已测试支持的设备
|
||||
|
||||
```txt
|
||||
"L07A": ("5-1", "5-5"), # Redmi小爱音箱Play(l7a)
|
||||
- L06A
|
||||
- L07A
|
||||
- S12
|
||||
- S12A
|
||||
- LX5A
|
||||
- LX05
|
||||
- L16A
|
||||
- L17A
|
||||
- LX06
|
||||
- LX01
|
||||
- L05B
|
||||
- L05C
|
||||
````
|
||||
|
||||
型号与产品名称对照可以在这里查询 <https://home.miot-spec.com/s/xiaomi.wifispeaker>
|
||||
|
||||
> 如果你的设备支持播放,请反馈给我添加到支持列表里,谢谢。
|
||||
|
||||
## 支持音乐格式
|
||||
|
||||
- mp3
|
||||
- flac
|
||||
- wav
|
||||
- ape
|
||||
- ogg
|
||||
|
||||
> 本地音乐会搜索 mp3 和 flac 格式的文件,下载的歌曲是 mp3 格式的。
|
||||
> 本地音乐会搜索目录下上面格式的文件,下载的歌曲是 mp3 格式的。
|
||||
> 已知 L05B L05C 不支持 flac 格式。
|
||||
|
||||
## 在 Docker 里使用
|
||||
|
||||
```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 -e XIAOMUSIC_SEARCH='bilisearch:' -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 用于配置代理,默认为空;
|
||||
@@ -67,7 +168,6 @@ direct connection
|
||||
|
||||
见 <https://github.com/hanxi/xiaomusic/issues/2> 和 <https://github.com/hanxi/xiaomusic/issues/11>
|
||||
|
||||
|
||||
### 本地编译Docker Image
|
||||
|
||||
```shell
|
||||
@@ -124,6 +224,26 @@ services:
|
||||
XIAOMUSIC_HOSTNAME: '192.168.2.5'
|
||||
```
|
||||
|
||||
如果想让 setting.json 文件不存储到 music 目录,可以这样配,下面的示例会把 setting.json 文件放到容器的 /app/conf 目录且映射到本地的 ./conf 目录:
|
||||
|
||||
```yaml
|
||||
services:
|
||||
xiaomusic:
|
||||
image: hanxi/xiaomusic
|
||||
container_name: xiaomusic
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- 8090:8090
|
||||
volumes:
|
||||
- ./music:/app/music
|
||||
- ./conf:/app/conf
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
XIAOMUSIC_CONF_PATH: '/app/conf'
|
||||
```
|
||||
|
||||
|
||||
## 简易的控制面板
|
||||
|
||||
@@ -131,7 +251,53 @@ services:
|
||||
|
||||
- ip 是 XIAOMUSIC_HOSTNAME 设置的
|
||||
- 8090 是默认端口
|
||||
- 支持功能
|
||||
- 显示正在播放的歌曲
|
||||
- 模糊搜索本地歌曲
|
||||
- 播放列表
|
||||
- 删除歌曲
|
||||
- 设置页面
|
||||
- 配置网络歌单
|
||||
- 日志文件下载
|
||||
|
||||
采用新的设置页面之后,必须在启动前配置的环境变量只剩下:
|
||||
- MI_USER
|
||||
- MI_PASS
|
||||
- XIAOMUSIC_HOSTNAME
|
||||
|
||||
其他的这些可以在网页里配置:
|
||||
- MI_DID
|
||||
- MI_HARDWARE
|
||||
- XIAOMUSIC_SEARCH
|
||||
- XIAOMUSIC_PROXY
|
||||
|
||||
## 网络歌单功能
|
||||
|
||||
可以配置一个 json 格式的歌单,支持电台和歌曲,也可以直接用别人分享的链接,同时配备了 m3u 文件格式转换工具,可以很方便的把 m3u 电台文件转换成网络歌单格式的 json 文件,具体用法见 <https://github.com/hanxi/xiaomusic/issues/78>
|
||||
|
||||
> 欢迎有想法的朋友们制作更多的歌单转换工具。
|
||||
|
||||
## 更多其他可选配置
|
||||
|
||||
- XIAOMUSIC_ACTIVE_CMD 环境变量,用于唤醒口令,配置成'play,random_play',在非播放状态下,只有这两个指令(播放歌曲和随机播放)可以触发,触发后,xiaomusic进入playing状态,其他指令则可以正常触发。具体见 <https://github.com/hanxi/xiaomusic/pull/43>
|
||||
- XIAOMUSIC_EXCLUDE_DIRS 配置歌曲目录里需要忽略的目录
|
||||
- XIAOMUSIC_MUSIC_PATH_DEPTH 配置歌曲目录搜索深度,具体见 <https://github.com/hanxi/xiaomusic/issues/76>
|
||||
- XIAOMUSIC_DISABLE_HTTPAUTH 配置成 false 表示开启密码访问web控制台,具体见 <https://github.com/hanxi/xiaomusic/issues/47>
|
||||
- XIAOMUSIC_HTTPAUTH_USERNAME 配置 web 控制台用户
|
||||
- XIAOMUSIC_HTTPAUTH_PASSWORD 配置 web 控制台密码
|
||||
- XIAOMUSIC_CONF_PATH 用来存放配置文件的目录,记得把目录映射到主机,默认情况会把配置存放在music目录,具体见 <https://github.com/hanxi/xiaomusic/issues/74>
|
||||
- XIAOMUSIC_DISABLE_DOWNLOAD 设为 true 时关闭下载功能,见 <https://github.com/hanxi/xiaomusic/issues/82>
|
||||
- XIAOMUSIC_USE_MUSIC_API 设为 true 时使用 player_play_music 接口播放音乐,用于兼容不能播放的型号
|
||||
- XIAOMUSIC_KEYWORDS_PLAY 用来播放歌曲的口令前缀,默认是 "播放歌曲,放歌曲" ,可以用英文逗号分割配置多个
|
||||
- XIAOMUSIC_KEYWORDS_STOP 用来关机的口令,默认是 "关机,暂停,停止" ,可以用英文逗号分割配置多个。
|
||||
- XIAOMUSIC_KEYWORDS_PLAYLOCAL 用来播放本地歌曲的口令前缀,本地找不到时不会下载歌曲,默认是 "播放本地歌曲,本地播放歌曲" ,可以用英文逗号分割配置多个。
|
||||
|
||||
## 讨论区
|
||||
|
||||
- [点击链接加入QQ频道【xiaomusic】](https://pd.qq.com/s/e2jybz0ss)
|
||||
- [点击链接加入群聊【xiaomusic】 604526973](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=13St5PLVcTxYlWTAs_iAawazjtdD1l-a&authKey=dJWEpaT2fDBDpdUUOWj%2FLt6NS1ePBfShDfz7a6seNURi05VvVnAGQzXF%2FM%2F5HgIm&noverify=0&group_code=604526973)
|
||||
- <https://github.com/hanxi/xiaomusic/issues>
|
||||
- [微信群二维码](https://github.com/hanxi/xiaomusic/issues/86)
|
||||
|
||||
## 感谢
|
||||
|
||||
@@ -142,7 +308,14 @@ services:
|
||||
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
|
||||
- [NAS部署教程](https://post.m.smzdm.com/p/avpe7n99/)
|
||||
- [群晖部署教程](https://post.m.smzdm.com/p/a7px7dol/)
|
||||
- [QNAS部署教程](https://post.smzdm.com/p/a5xz5x63/)
|
||||
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#hanxi/xiaomusic&Date)
|
||||
|
||||
## 赞赏
|
||||
|
||||
- 爱发电 <https://afdian.net/a/imhanxi>
|
||||
- 点个 Star ⭐
|
||||
- 谢谢 ❤️
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
set -e
|
||||
|
||||
version_file=./pyproject.toml
|
||||
init_file=./xiaomusic/__init__.py
|
||||
# 获取当前版本号
|
||||
current_version=$(grep -oE "version = \"[0-9]+\.[0-9]+\.[0-9]+\"" $version_file | cut -d'"' -f2)
|
||||
echo "当前版本号: "$current_version
|
||||
@@ -24,11 +25,13 @@ new_version="$major.$minor.$patch"
|
||||
|
||||
# 将新版本号写入文件
|
||||
sed -i "s/version.*/version = \"$new_version\"/g" $version_file
|
||||
sed -i "s/__version__.*/__version__ = \"$new_version\"/g" $init_file
|
||||
|
||||
echo "新版本号:$new_version"
|
||||
|
||||
git diff
|
||||
git add $version_file
|
||||
git add $init_file
|
||||
git commit -m "new version v$new_version"
|
||||
git tag v$new_version
|
||||
git push -u origin main --tags
|
||||
|
||||
198
pdm.lock
generated
198
pdm.lock
generated
@@ -2,15 +2,14 @@
|
||||
# It is not intended for manual editing.
|
||||
|
||||
[metadata]
|
||||
groups = ["default"]
|
||||
cross_platform = true
|
||||
static_urls = false
|
||||
lock_version = "4.3"
|
||||
content_hash = "sha256:d21199e11013c9db9343d7868f7f582ff85a6c8ad29b3f5caca7ce7fe669b841"
|
||||
groups = ["default", "lint"]
|
||||
strategy = ["cross_platform"]
|
||||
lock_version = "4.4.1"
|
||||
content_hash = "sha256:813253734c7d7835a76cd87fe8fe0329e02ad067f535aee6a9e11cb106569dd2"
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.9.3"
|
||||
version = "3.9.5"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Async http client/server framework (asyncio)"
|
||||
dependencies = [
|
||||
@@ -22,52 +21,52 @@ dependencies = [
|
||||
"yarl<2.0,>=1.0",
|
||||
]
|
||||
files = [
|
||||
{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"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-win32.whl", hash = "sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb"},
|
||||
{file = "aiohttp-3.9.5-cp310-cp310-win_amd64.whl", hash = "sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-win32.whl", hash = "sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6"},
|
||||
{file = "aiohttp-3.9.5-cp311-cp311-win_amd64.whl", hash = "sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-win32.whl", hash = "sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59"},
|
||||
{file = "aiohttp-3.9.5-cp312-cp312-win_amd64.whl", hash = "sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888"},
|
||||
{file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -342,7 +341,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "flask"
|
||||
version = "3.0.1"
|
||||
version = "3.0.3"
|
||||
requires_python = ">=3.8"
|
||||
summary = "A simple framework for building complex web applications."
|
||||
dependencies = [
|
||||
@@ -353,23 +352,35 @@ dependencies = [
|
||||
"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"},
|
||||
{file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"},
|
||||
{file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flask-httpauth"
|
||||
version = "4.8.0"
|
||||
summary = "HTTP authentication for Flask routes"
|
||||
dependencies = [
|
||||
"flask",
|
||||
]
|
||||
files = [
|
||||
{file = "Flask-HTTPAuth-4.8.0.tar.gz", hash = "sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a"},
|
||||
{file = "Flask_HTTPAuth-4.8.0-py3-none-any.whl", hash = "sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flask"
|
||||
version = "3.0.1"
|
||||
version = "3.0.3"
|
||||
extras = ["async"]
|
||||
requires_python = ">=3.8"
|
||||
summary = "A simple framework for building complex web applications."
|
||||
dependencies = [
|
||||
"asgiref>=3.2",
|
||||
"flask==3.0.1",
|
||||
"flask==3.0.3",
|
||||
]
|
||||
files = [
|
||||
{file = "flask-3.0.1-py3-none-any.whl", hash = "sha256:ca631a507f6dfe6c278ae20112cea3ff54ff2216390bf8880f6b035a5354af13"},
|
||||
{file = "flask-3.0.1.tar.gz", hash = "sha256:6489f51bb3666def6f314e15f19d50a1869a19ae0e8c9a3641ffe66c77d42403"},
|
||||
{file = "flask-3.0.3-py3-none-any.whl", hash = "sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3"},
|
||||
{file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -508,16 +519,17 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "miservice-fork"
|
||||
version = "2.3.2"
|
||||
requires_python = ">=3.7"
|
||||
version = "2.6.0"
|
||||
requires_python = ">=3.8"
|
||||
summary = "XiaoMi Cloud Service fork from https://github.com/Yonsm/MiService"
|
||||
dependencies = [
|
||||
"aiohttp",
|
||||
"mutagen",
|
||||
"rich",
|
||||
]
|
||||
files = [
|
||||
{file = "miservice_fork-2.3.2-py3-none-any.whl", hash = "sha256:f24c40366df99d5db706f09528692bc490390fe7db950aa32f4948bafdc1a03d"},
|
||||
{file = "miservice_fork-2.3.2.tar.gz", hash = "sha256:1c907289cd354c349ead5e5b1f08e22aa23b8fa01114ecc7a2800e463751ba5b"},
|
||||
{file = "miservice_fork-2.6.0-py3-none-any.whl", hash = "sha256:98169a77ea41a7b9392e1b1fab8cb80a4165fed8a9e882d9ada9a16dd1120347"},
|
||||
{file = "miservice_fork-2.6.0.tar.gz", hash = "sha256:a59d337d1f7a92566aa147e96595a8d2f5bf3f7000ae5e7dd9ed451f18d6e2fd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -620,8 +632,8 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "requests"
|
||||
version = "2.31.0"
|
||||
requires_python = ">=3.7"
|
||||
version = "2.32.3"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Python HTTP for Humans."
|
||||
dependencies = [
|
||||
"certifi>=2017.4.17",
|
||||
@@ -630,13 +642,13 @@ dependencies = [
|
||||
"urllib3<3,>=1.21.1",
|
||||
]
|
||||
files = [
|
||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
||||
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rich"
|
||||
version = "13.7.0"
|
||||
version = "13.7.1"
|
||||
requires_python = ">=3.7.0"
|
||||
summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
|
||||
dependencies = [
|
||||
@@ -644,8 +656,34 @@ dependencies = [
|
||||
"pygments<3.0.0,>=2.13.0",
|
||||
]
|
||||
files = [
|
||||
{file = "rich-13.7.0-py3-none-any.whl", hash = "sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235"},
|
||||
{file = "rich-13.7.0.tar.gz", hash = "sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa"},
|
||||
{file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
|
||||
{file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.5.0"
|
||||
requires_python = ">=3.7"
|
||||
summary = "An extremely fast Python linter and code formatter, written in Rust."
|
||||
files = [
|
||||
{file = "ruff-0.5.0-py3-none-linux_armv6l.whl", hash = "sha256:ee770ea8ab38918f34e7560a597cc0a8c9a193aaa01bfbd879ef43cb06bd9c4c"},
|
||||
{file = "ruff-0.5.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:38f3b8327b3cb43474559d435f5fa65dacf723351c159ed0dc567f7ab735d1b6"},
|
||||
{file = "ruff-0.5.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7594f8df5404a5c5c8f64b8311169879f6cf42142da644c7e0ba3c3f14130370"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:adc7012d6ec85032bc4e9065110df205752d64010bed5f958d25dbee9ce35de3"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d505fb93b0fabef974b168d9b27c3960714d2ecda24b6ffa6a87ac432905ea38"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9dc5cfd3558f14513ed0d5b70ce531e28ea81a8a3b1b07f0f48421a3d9e7d80a"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:db3ca35265de239a1176d56a464b51557fce41095c37d6c406e658cf80bbb362"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b1a321c4f68809fddd9b282fab6a8d8db796b270fff44722589a8b946925a2a8"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2c4dfcd8d34b143916994b3876b63d53f56724c03f8c1a33a253b7b1e6bf2a7d"},
|
||||
{file = "ruff-0.5.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81e5facfc9f4a674c6a78c64d38becfbd5e4f739c31fcd9ce44c849f1fad9e4c"},
|
||||
{file = "ruff-0.5.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e589e27971c2a3efff3fadafb16e5aef7ff93250f0134ec4b52052b673cf988d"},
|
||||
{file = "ruff-0.5.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2ffbc3715a52b037bcb0f6ff524a9367f642cdc5817944f6af5479bbb2eb50e"},
|
||||
{file = "ruff-0.5.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cd096e23c6a4f9c819525a437fa0a99d1c67a1b6bb30948d46f33afbc53596cf"},
|
||||
{file = "ruff-0.5.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:46e193b36f2255729ad34a49c9a997d506e58f08555366b2108783b3064a0e1e"},
|
||||
{file = "ruff-0.5.0-py3-none-win32.whl", hash = "sha256:49141d267100f5ceff541b4e06552e98527870eafa1acc9dec9139c9ec5af64c"},
|
||||
{file = "ruff-0.5.0-py3-none-win_amd64.whl", hash = "sha256:e9118f60091047444c1b90952736ee7b1792910cab56e9b9a9ac20af94cd0440"},
|
||||
{file = "ruff-0.5.0-py3-none-win_arm64.whl", hash = "sha256:ed5c4df5c1fb4518abcb57725b576659542bdbe93366f4f329e8f398c4b71178"},
|
||||
{file = "ruff-0.5.0.tar.gz", hash = "sha256:eb641b5873492cf9bd45bc9c5ae5320648218e04386a5f0c264ad6ccce8226a1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -668,6 +706,16 @@ files = [
|
||||
{file = "urllib3-2.0.6.tar.gz", hash = "sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "waitress"
|
||||
version = "3.0.0"
|
||||
requires_python = ">=3.8.0"
|
||||
summary = "Waitress WSGI server"
|
||||
files = [
|
||||
{file = "waitress-3.0.0-py3-none-any.whl", hash = "sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669"},
|
||||
{file = "waitress-3.0.0.tar.gz", hash = "sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "websockets"
|
||||
version = "12.0"
|
||||
@@ -784,20 +832,20 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "yt-dlp"
|
||||
version = "2024.2.2.232707.dev0"
|
||||
version = "2024.6.24.232830.dev0"
|
||||
requires_python = ">=3.8"
|
||||
summary = "A youtube-dl fork with additional features and patches"
|
||||
summary = "A feature-rich command-line audio/video downloader"
|
||||
dependencies = [
|
||||
"brotli; implementation_name == \"cpython\"",
|
||||
"brotlicffi; implementation_name != \"cpython\"",
|
||||
"certifi",
|
||||
"mutagen",
|
||||
"pycryptodomex",
|
||||
"requests<3,>=2.31.0",
|
||||
"requests<3,>=2.32.2",
|
||||
"urllib3<3,>=1.26.17",
|
||||
"websockets>=12.0",
|
||||
]
|
||||
files = [
|
||||
{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"},
|
||||
{file = "yt_dlp-2024.6.24.232830.dev0-py3-none-any.whl", hash = "sha256:efffecef44ce688e9ee3c02226eb1ba4ad64b37744726e9e4df5c2bd04ea93c5"},
|
||||
{file = "yt_dlp-2024.6.24.232830.dev0.tar.gz", hash = "sha256:0e89b46958984954393692a8c41e0f6d76a773be2df381c3d3a4ff24ce89aa32"},
|
||||
]
|
||||
|
||||
@@ -1,18 +1,19 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.1.24"
|
||||
version = "0.1.78"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
]
|
||||
dependencies = [
|
||||
"rich>=13.6.0",
|
||||
"requests>=2.31.0",
|
||||
"aiohttp>=3.8.6",
|
||||
"miservice-fork>=2.2.1",
|
||||
"miservice-fork>=2.5.0",
|
||||
"mutagen>=1.47.0",
|
||||
"yt-dlp>=2024.2.2.232707.dev0",
|
||||
"yt-dlp>=2024.04.09",
|
||||
"flask[async]>=3.0.1",
|
||||
"waitress>=3.0.0",
|
||||
"flask-HTTPAuth>=4.8.0",
|
||||
]
|
||||
requires-python = ">=3.10"
|
||||
readme = "README.md"
|
||||
@@ -21,3 +22,31 @@ license = {text = "MIT"}
|
||||
[build-system]
|
||||
requires = ["pdm-backend"]
|
||||
build-backend = "pdm.backend"
|
||||
|
||||
[tool.pdm]
|
||||
[tool.pdm.dev-dependencies]
|
||||
lint = [
|
||||
"ruff>=0.4.8",
|
||||
]
|
||||
[tool.ruff]
|
||||
lint.select = [
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"E", # pycodestyle - Error
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
"W", # pycodestyle - Warning
|
||||
"UP", # pyupgrade
|
||||
]
|
||||
lint.ignore = [
|
||||
"E501", # line-too-long
|
||||
"W191", # tab-indentation
|
||||
]
|
||||
include = ["**/*.py", "**/*.pyi", "**/pyproject.toml"]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
[tool.pdm.scripts]
|
||||
lint = "ruff check ."
|
||||
fmt = "ruff format ."
|
||||
|
||||
204
requirements.txt
204
requirements.txt
@@ -1,60 +1,60 @@
|
||||
# This file is @generated by PDM.
|
||||
# Please do not edit it manually.
|
||||
|
||||
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
|
||||
aiohttp==3.9.5 \
|
||||
--hash=sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c \
|
||||
--hash=sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf \
|
||||
--hash=sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81 \
|
||||
--hash=sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f \
|
||||
--hash=sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a \
|
||||
--hash=sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771 \
|
||||
--hash=sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb \
|
||||
--hash=sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430 \
|
||||
--hash=sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233 \
|
||||
--hash=sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9 \
|
||||
--hash=sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59 \
|
||||
--hash=sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888 \
|
||||
--hash=sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c \
|
||||
--hash=sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c \
|
||||
--hash=sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424 \
|
||||
--hash=sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2 \
|
||||
--hash=sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb \
|
||||
--hash=sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a \
|
||||
--hash=sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10 \
|
||||
--hash=sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0 \
|
||||
--hash=sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4 \
|
||||
--hash=sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3 \
|
||||
--hash=sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa \
|
||||
--hash=sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a \
|
||||
--hash=sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a \
|
||||
--hash=sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323 \
|
||||
--hash=sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6 \
|
||||
--hash=sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832 \
|
||||
--hash=sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75 \
|
||||
--hash=sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6 \
|
||||
--hash=sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d \
|
||||
--hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \
|
||||
--hash=sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db \
|
||||
--hash=sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da \
|
||||
--hash=sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678 \
|
||||
--hash=sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b \
|
||||
--hash=sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f \
|
||||
--hash=sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58 \
|
||||
--hash=sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342 \
|
||||
--hash=sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558 \
|
||||
--hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551 \
|
||||
--hash=sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595 \
|
||||
--hash=sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee \
|
||||
--hash=sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d \
|
||||
--hash=sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7 \
|
||||
--hash=sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f
|
||||
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 \
|
||||
async-timeout==4.0.3; python_version < "3.11" \
|
||||
--hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
|
||||
--hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
|
||||
attrs==23.1.0 \
|
||||
@@ -63,7 +63,7 @@ attrs==23.1.0 \
|
||||
blinker==1.7.0 \
|
||||
--hash=sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9 \
|
||||
--hash=sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182
|
||||
brotli==1.1.0 \
|
||||
brotli==1.1.0; implementation_name == "cpython" \
|
||||
--hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \
|
||||
--hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \
|
||||
--hash=sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3 \
|
||||
@@ -101,9 +101,71 @@ brotli==1.1.0 \
|
||||
--hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \
|
||||
--hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \
|
||||
--hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e
|
||||
brotlicffi==1.1.0.0; implementation_name != "cpython" \
|
||||
--hash=sha256:19ffc919fa4fc6ace69286e0a23b3789b4219058313cf9b45625016bf7ff996b \
|
||||
--hash=sha256:1a807d760763e398bbf2c6394ae9da5815901aa93ee0a37bca5efe78d4ee3171 \
|
||||
--hash=sha256:1b12b50e07c3911e1efa3a8971543e7648100713d4e0971b13631cce22c587eb \
|
||||
--hash=sha256:246f1d1a90279bb6069de3de8d75a8856e073b8ff0b09dcca18ccc14cec85979 \
|
||||
--hash=sha256:2a7ae37e5d79c5bdfb5b4b99f2715a6035e6c5bf538c3746abc8e26694f92f33 \
|
||||
--hash=sha256:2e4aeb0bd2540cb91b069dbdd54d458da8c4334ceaf2d25df2f4af576d6766ca \
|
||||
--hash=sha256:2f3711be9290f0453de8eed5275d93d286abe26b08ab4a35d7452caa1fef532f \
|
||||
--hash=sha256:37c26ecb14386a44b118ce36e546ce307f4810bc9598a6e6cb4f7fca725ae7e6 \
|
||||
--hash=sha256:391151ec86bb1c683835980f4816272a87eaddc46bb91cbf44f62228b84d8cca \
|
||||
--hash=sha256:3de0cf28a53a3238b252aca9fed1593e9d36c1d116748013339f0949bfc84112 \
|
||||
--hash=sha256:4b7b0033b0d37bb33009fb2fef73310e432e76f688af76c156b3594389d81391 \
|
||||
--hash=sha256:54a07bb2374a1eba8ebb52b6fafffa2afd3c4df85ddd38fcc0511f2bb387c2a8 \
|
||||
--hash=sha256:6be5ec0e88a4925c91f3dea2bb0013b3a2accda6f77238f76a34a1ea532a1cb0 \
|
||||
--hash=sha256:7901a7dc4b88f1c1475de59ae9be59799db1007b7d059817948d8e4f12e24e35 \
|
||||
--hash=sha256:84763dbdef5dd5c24b75597a77e1b30c66604725707565188ba54bab4f114820 \
|
||||
--hash=sha256:8557a8559509b61e65083f8782329188a250102372576093c88930c875a69838 \
|
||||
--hash=sha256:994a4f0681bb6c6c3b0925530a1926b7a189d878e6e5e38fae8efa47c5d9c613 \
|
||||
--hash=sha256:9b6068e0f3769992d6b622a1cd2e7835eae3cf8d9da123d7f51ca9c1e9c333e5 \
|
||||
--hash=sha256:9b7ae6bd1a3f0df532b6d67ff674099a96d22bc0948955cb338488c31bfb8851 \
|
||||
--hash=sha256:9feb210d932ffe7798ee62e6145d3a757eb6233aa9a4e7db78dd3690d7755814 \
|
||||
--hash=sha256:add0de5b9ad9e9aa293c3aa4e9deb2b61e99ad6c1634e01d01d98c03e6a354cc \
|
||||
--hash=sha256:b77827a689905143f87915310b93b273ab17888fd43ef350d4832c4a71083c13 \
|
||||
--hash=sha256:ca72968ae4eaf6470498d5c2887073f7efe3b1e7d7ec8be11a06a79cc810e990 \
|
||||
--hash=sha256:cc4bc5d82bc56ebd8b514fb8350cfac4627d6b0743382e46d033976a5f80fab6 \
|
||||
--hash=sha256:ce01c7316aebc7fce59da734286148b1d1b9455f89cf2c8a4dfce7d41db55c2d \
|
||||
--hash=sha256:d9eb71bb1085d996244439154387266fd23d6ad37161f6f52f1cd41dd95a3808 \
|
||||
--hash=sha256:fa8ca0623b26c94fccc3a1fdd895be1743b838f3917300506d04aa3346fd2a14
|
||||
certifi==2023.7.22 \
|
||||
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
|
||||
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
|
||||
cffi==1.16.0; implementation_name != "cpython" \
|
||||
--hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
|
||||
--hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
|
||||
--hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
|
||||
--hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
|
||||
--hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
|
||||
--hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
|
||||
--hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
|
||||
--hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
|
||||
--hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
|
||||
--hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
|
||||
--hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
|
||||
--hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
|
||||
--hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
|
||||
--hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
|
||||
--hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
|
||||
--hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
|
||||
--hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
|
||||
--hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
|
||||
--hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
|
||||
--hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
|
||||
--hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
|
||||
--hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
|
||||
--hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
|
||||
--hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
|
||||
--hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
|
||||
--hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
|
||||
--hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
|
||||
--hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
|
||||
--hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
|
||||
--hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
|
||||
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
|
||||
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
|
||||
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
|
||||
charset-normalizer==3.3.0 \
|
||||
--hash=sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786 \
|
||||
--hash=sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e \
|
||||
@@ -155,9 +217,15 @@ charset-normalizer==3.3.0 \
|
||||
click==8.1.7 \
|
||||
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
|
||||
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
|
||||
flask==3.0.1 \
|
||||
--hash=sha256:6489f51bb3666def6f314e15f19d50a1869a19ae0e8c9a3641ffe66c77d42403 \
|
||||
--hash=sha256:ca631a507f6dfe6c278ae20112cea3ff54ff2216390bf8880f6b035a5354af13
|
||||
colorama==0.4.6; platform_system == "Windows" \
|
||||
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
||||
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
||||
flask==3.0.3 \
|
||||
--hash=sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3 \
|
||||
--hash=sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842
|
||||
flask-HTTPAuth==4.8.0 \
|
||||
--hash=sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a \
|
||||
--hash=sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0
|
||||
frozenlist==1.4.0 \
|
||||
--hash=sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01 \
|
||||
--hash=sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251 \
|
||||
@@ -237,9 +305,9 @@ MarkupSafe==2.1.4 \
|
||||
mdurl==0.1.2 \
|
||||
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
||||
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
||||
miservice-fork==2.3.2 \
|
||||
--hash=sha256:1c907289cd354c349ead5e5b1f08e22aa23b8fa01114ecc7a2800e463751ba5b \
|
||||
--hash=sha256:f24c40366df99d5db706f09528692bc490390fe7db950aa32f4948bafdc1a03d
|
||||
miservice-fork==2.6.0 \
|
||||
--hash=sha256:98169a77ea41a7b9392e1b1fab8cb80a4165fed8a9e882d9ada9a16dd1120347 \
|
||||
--hash=sha256:a59d337d1f7a92566aa147e96595a8d2f5bf3f7000ae5e7dd9ed451f18d6e2fd
|
||||
multidict==6.0.4 \
|
||||
--hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \
|
||||
--hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \
|
||||
@@ -275,6 +343,9 @@ multidict==6.0.4 \
|
||||
mutagen==1.47.0 \
|
||||
--hash=sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99 \
|
||||
--hash=sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719
|
||||
pycparser==2.21; implementation_name != "cpython" \
|
||||
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
|
||||
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
|
||||
pycryptodomex==3.19.0 \
|
||||
--hash=sha256:09c9401dc06fb3d94cb1ec23b4ea067a25d1f4c6b7b118ff5631d0b5daaab3cc \
|
||||
--hash=sha256:0b2f1982c5bc311f0aab8c293524b861b485d76f7c9ab2c3ac9a25b6f7655975 \
|
||||
@@ -300,18 +371,21 @@ pycryptodomex==3.19.0 \
|
||||
pygments==2.16.1 \
|
||||
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
|
||||
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
|
||||
requests==2.31.0 \
|
||||
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
|
||||
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
|
||||
rich==13.7.0 \
|
||||
--hash=sha256:5cb5123b5cf9ee70584244246816e9114227e0b98ad9176eede6ad54bf5403fa \
|
||||
--hash=sha256:6da14c108c4866ee9520bbffa71f6fe3962e193b7da68720583850cd4548e235
|
||||
typing-extensions==4.9.0 \
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
rich==13.7.1 \
|
||||
--hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \
|
||||
--hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432
|
||||
typing-extensions==4.9.0; python_version < "3.11" \
|
||||
--hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
|
||||
--hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
|
||||
urllib3==2.0.6 \
|
||||
--hash=sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2 \
|
||||
--hash=sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564
|
||||
waitress==3.0.0 \
|
||||
--hash=sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1 \
|
||||
--hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669
|
||||
websockets==12.0 \
|
||||
--hash=sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b \
|
||||
--hash=sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6 \
|
||||
@@ -398,6 +472,6 @@ yarl==1.9.2 \
|
||||
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
|
||||
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
|
||||
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560
|
||||
yt-dlp==2024.2.2.232707.dev0 \
|
||||
--hash=sha256:7ff05434979d89e2a7c344d6771cc60229901fe4182c19a756472bb49a50e3b8 \
|
||||
--hash=sha256:fd8d85f64842038cbdaaf7ee5812d98beed64fdcb4612f6e80b2c721bad13262
|
||||
yt-dlp==2024.6.24.232830.dev0 \
|
||||
--hash=sha256:0e89b46958984954393692a8c41e0f6d76a773be2df381c3d3a4ff24ce89aa32 \
|
||||
--hash=sha256:efffecef44ce688e9ee3c02226eb1ba4ad64b37744726e9e4df5c2bd04ea93c5
|
||||
|
||||
@@ -1 +1 @@
|
||||
pdm export -o requirements.txt
|
||||
pdm export --prod -o requirements.txt
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
__version__ = "0.1.78"
|
||||
|
||||
@@ -27,20 +27,6 @@ def main():
|
||||
dest="cookie",
|
||||
help="xiaomi cookie",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--use_command",
|
||||
dest="use_command",
|
||||
action="store_true",
|
||||
default=None,
|
||||
help="use command to tts",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mute_xiaoai",
|
||||
dest="mute_xiaoai",
|
||||
action="store_true",
|
||||
default=None,
|
||||
help="try to mute xiaoai answer",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
dest="verbose",
|
||||
|
||||
@@ -3,47 +3,24 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Any, Iterable
|
||||
from dataclasses import dataclass
|
||||
|
||||
from xiaomusic.utils import validate_proxy
|
||||
|
||||
LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation?source=dialogu&hardware={hardware}×tamp={timestamp}&limit=2"
|
||||
COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}"
|
||||
|
||||
HARDWARE_COMMAND_DICT = {
|
||||
# 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", "2-1")
|
||||
|
||||
KEY_WORD_DICT = {
|
||||
# 默认口令
|
||||
DEFAULT_KEY_WORD_DICT = {
|
||||
"播放歌曲": "play",
|
||||
"放歌曲": "play",
|
||||
"播放本地歌曲": "playlocal",
|
||||
"关机": "stop",
|
||||
"下一首": "play_next",
|
||||
"单曲循环": "set_play_type_one",
|
||||
"全部循环": "set_play_type_all",
|
||||
"随机播放": "random_play",
|
||||
"关机": "stop",
|
||||
"停止播放": "stop",
|
||||
"分钟后关机": "stop_after_minute",
|
||||
"播放列表": "play_music_list",
|
||||
"刷新列表": "gen_music_list",
|
||||
"set_volume#": "set_volume",
|
||||
"get_volume#": "get_volume",
|
||||
}
|
||||
|
||||
# 命令参数在前面
|
||||
@@ -51,23 +28,19 @@ KEY_WORD_ARG_BEFORE_DICT = {
|
||||
"分钟后关机": True,
|
||||
}
|
||||
|
||||
# 匹配优先级
|
||||
KEY_MATCH_ORDER = [
|
||||
# 口令匹配优先级
|
||||
DEFAULT_KEY_MATCH_ORDER = [
|
||||
"set_volume#",
|
||||
"get_volume#",
|
||||
"分钟后关机",
|
||||
"播放歌曲",
|
||||
"放歌曲",
|
||||
"下一首",
|
||||
"单曲循环",
|
||||
"全部循环",
|
||||
"随机播放",
|
||||
"关机",
|
||||
"停止播放",
|
||||
]
|
||||
|
||||
SUPPORT_MUSIC_TYPE = [
|
||||
".mp3",
|
||||
".flac",
|
||||
"刷新列表",
|
||||
"播放列表",
|
||||
]
|
||||
|
||||
|
||||
@@ -77,11 +50,10 @@ class Config:
|
||||
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 = False
|
||||
verbose: bool = False
|
||||
verbose: bool = os.getenv("XIAOMUSIC_VERBOSE", "").lower() == "true"
|
||||
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
|
||||
conf_path: str = os.getenv("XIAOMUSIC_CONF_PATH", None)
|
||||
hostname: str = os.getenv("XIAOMUSIC_HOSTNAME", "192.168.2.5")
|
||||
port: int = int(os.getenv("XIAOMUSIC_PORT", "8090"))
|
||||
proxy: str | None = os.getenv("XIAOMUSIC_PROXY", None)
|
||||
@@ -89,22 +61,51 @@ class Config:
|
||||
"XIAOMUSIC_SEARCH", "ytsearch:"
|
||||
) # "bilisearch:" or "ytsearch:"
|
||||
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
|
||||
active_cmd: str = os.getenv(
|
||||
"XIAOMUSIC_ACTIVE_CMD", "play,random_play,playlocal,play_music_list,stop"
|
||||
)
|
||||
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir")
|
||||
music_path_depth: int = int(os.getenv("XIAOMUSIC_MUSIC_PATH_DEPTH", "10"))
|
||||
disable_httpauth: bool = (
|
||||
os.getenv("XIAOMUSIC_DISABLE_HTTPAUTH", "true").lower() == "true"
|
||||
)
|
||||
httpauth_username: str = os.getenv("XIAOMUSIC_HTTPAUTH_USERNAME", "admin")
|
||||
httpauth_password: str = os.getenv("XIAOMUSIC_HTTPAUTH_PASSWORD", "admin")
|
||||
music_list_url: str = os.getenv("XIAOMUSIC_MUSIC_LIST_URL", "")
|
||||
music_list_json: str = os.getenv("XIAOMUSIC_MUSIC_LIST_JSON", "")
|
||||
disable_download: bool = (
|
||||
os.getenv("XIAOMUSIC_DISABLE_DOWNLOAD", "false").lower() == "true"
|
||||
)
|
||||
key_word_dict = DEFAULT_KEY_WORD_DICT.copy()
|
||||
key_match_order = DEFAULT_KEY_MATCH_ORDER.copy()
|
||||
use_music_api: bool = (
|
||||
os.getenv("XIAOMUSIC_USE_MUSIC_API", "false").lower() == "true"
|
||||
)
|
||||
log_file: str = os.getenv("XIAOMUSIC_MUSIC_LOG_FILE", "/tmp/xiaomusic.txt")
|
||||
# 模糊搜索匹配的最低相似度阈值
|
||||
fuzzy_match_cutoff: float = float(os.getenv("XIAOMUSIC_FUZZY_MATCH_CUTOFF", "0.6"))
|
||||
# 开启模糊搜索
|
||||
enable_fuzzy_match: bool = (
|
||||
os.getenv("XIAOMUSIC_ENABLE_FUZZY_MATCH", "true").lower() == "true"
|
||||
)
|
||||
|
||||
def append_keyword(self, keys, action):
|
||||
for key in keys.split(","):
|
||||
self.key_word_dict[key] = action
|
||||
if key not in self.key_match_order:
|
||||
self.key_match_order.append(key)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.proxy:
|
||||
validate_proxy(self.proxy)
|
||||
|
||||
@property
|
||||
def tts_command(self) -> str:
|
||||
return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[0]
|
||||
|
||||
@property
|
||||
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]
|
||||
keywords_playlocal = os.getenv(
|
||||
"XIAOMUSIC_KEYWORDS_PLAYLOCAL", "播放本地歌曲,本地播放歌曲"
|
||||
)
|
||||
self.append_keyword(keywords_playlocal, "playlocal")
|
||||
keywords_play = os.getenv("XIAOMUSIC_KEYWORDS_PLAY", "播放歌曲,放歌曲")
|
||||
self.append_keyword(keywords_play, "play")
|
||||
keywords_stop = os.getenv("XIAOMUSIC_KEYWORDS_STOP", "关机,暂停,停止")
|
||||
self.append_keyword(keywords_stop, "stop")
|
||||
|
||||
@classmethod
|
||||
def from_options(cls, options: argparse.Namespace) -> Config:
|
||||
|
||||
10
xiaomusic/const.py
Normal file
10
xiaomusic/const.py
Normal file
@@ -0,0 +1,10 @@
|
||||
SUPPORT_MUSIC_TYPE = [
|
||||
".mp3",
|
||||
".flac",
|
||||
".wav",
|
||||
".ape",
|
||||
".ogg",
|
||||
]
|
||||
|
||||
LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation?source=dialogu&hardware={hardware}×tamp={timestamp}&limit=2"
|
||||
COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}"
|
||||
@@ -1,15 +1,21 @@
|
||||
#!/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,
|
||||
from flask import Flask, request, send_file, send_from_directory
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from waitress import serve
|
||||
|
||||
from xiaomusic import (
|
||||
__version__,
|
||||
)
|
||||
from xiaomusic.utils import (
|
||||
downloadfile,
|
||||
)
|
||||
|
||||
app = Flask(__name__)
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
host = "0.0.0.0"
|
||||
port = 8090
|
||||
static_path = "music"
|
||||
@@ -17,32 +23,67 @@ xiaomusic = None
|
||||
log = None
|
||||
|
||||
|
||||
@auth.verify_password
|
||||
def verify_password(username, password):
|
||||
if xiaomusic.config.disable_httpauth:
|
||||
return True
|
||||
|
||||
if (
|
||||
xiaomusic.config.httpauth_username == username
|
||||
and xiaomusic.config.httpauth_password == password
|
||||
):
|
||||
return username
|
||||
|
||||
|
||||
@app.route("/allcmds")
|
||||
@auth.login_required
|
||||
def allcmds():
|
||||
return KEY_WORD_DICT
|
||||
return xiaomusic.config.key_word_dict
|
||||
|
||||
|
||||
@app.route("/getversion", methods=["GET"])
|
||||
def getversion():
|
||||
log.debug("getversion %s", __version__)
|
||||
return {
|
||||
"version": __version__,
|
||||
}
|
||||
|
||||
|
||||
@app.route("/getvolume", methods=["GET"])
|
||||
@auth.login_required
|
||||
def getvolume():
|
||||
volume = xiaomusic.get_volume_ret()
|
||||
return {
|
||||
"volume": xiaomusic.get_volume(),
|
||||
"volume": volume,
|
||||
}
|
||||
|
||||
|
||||
@app.route("/searchmusic", methods=["GET"])
|
||||
@auth.login_required
|
||||
def searchmusic():
|
||||
name = request.args.get('name')
|
||||
name = request.args.get("name")
|
||||
return xiaomusic.searchmusic(name)
|
||||
|
||||
|
||||
@app.route("/playingmusic", methods=["GET"])
|
||||
@auth.login_required
|
||||
def playingmusic():
|
||||
return xiaomusic.playingmusic()
|
||||
|
||||
|
||||
@app.route("/isplaying", methods=["GET"])
|
||||
@auth.login_required
|
||||
def isplaying():
|
||||
return xiaomusic.isplaying()
|
||||
|
||||
|
||||
@app.route("/", methods=["GET"])
|
||||
def redirect_to_index():
|
||||
def index():
|
||||
return send_from_directory("static", "index.html")
|
||||
|
||||
|
||||
@app.route("/cmd", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def do_cmd():
|
||||
data = request.get_json()
|
||||
cmd = data.get("cmd")
|
||||
@@ -53,6 +94,89 @@ async def do_cmd():
|
||||
return {"ret": "Unknow cmd"}
|
||||
|
||||
|
||||
@app.route("/getsetting", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def getsetting():
|
||||
config = xiaomusic.getconfig()
|
||||
log.debug(config)
|
||||
|
||||
alldevices = await xiaomusic.call_main_thread_function(xiaomusic.getalldevices)
|
||||
log.info(alldevices)
|
||||
data = {
|
||||
"mi_did": config.mi_did,
|
||||
"mi_did_list": alldevices["did_list"],
|
||||
"mi_hardware": config.hardware,
|
||||
"mi_hardware_list": alldevices["hardware_list"],
|
||||
"xiaomusic_search": config.search_prefix,
|
||||
"xiaomusic_proxy": config.proxy,
|
||||
"xiaomusic_music_list_url": config.music_list_url,
|
||||
"xiaomusic_music_list_json": config.music_list_json,
|
||||
}
|
||||
return data
|
||||
|
||||
|
||||
@app.route("/savesetting", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def savesetting():
|
||||
data = request.get_json()
|
||||
log.info(data)
|
||||
await xiaomusic.saveconfig(data)
|
||||
return "save success"
|
||||
|
||||
|
||||
@app.route("/musiclist", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def musiclist():
|
||||
return xiaomusic.get_music_list()
|
||||
|
||||
|
||||
@app.route("/curplaylist", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def curplaylist():
|
||||
return xiaomusic.get_cur_play_list()
|
||||
|
||||
|
||||
@app.route("/delmusic", methods=["POST"])
|
||||
@auth.login_required
|
||||
def delmusic():
|
||||
data = request.get_json()
|
||||
log.info(data)
|
||||
xiaomusic.del_music(data["name"])
|
||||
return "success"
|
||||
|
||||
|
||||
@app.route("/downloadjson", methods=["POST"])
|
||||
@auth.login_required
|
||||
def downloadjson():
|
||||
data = request.get_json()
|
||||
log.info(data)
|
||||
url = data["url"]
|
||||
try:
|
||||
ret = "OK"
|
||||
content = downloadfile(url)
|
||||
except Exception as e:
|
||||
log.warning(f"downloadjson failed. url:{url} e:{e}")
|
||||
ret = "Download JSON file failed."
|
||||
return {
|
||||
"ret": ret,
|
||||
"content": content,
|
||||
}
|
||||
|
||||
|
||||
@app.route("/downloadlog", methods=["GET"])
|
||||
@auth.login_required
|
||||
def downloadlog():
|
||||
return send_file(xiaomusic.config.log_file, as_attachment=True)
|
||||
|
||||
|
||||
@app.route("/playurl", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def playurl():
|
||||
url = request.args.get("url")
|
||||
log.info(f"play_url:{url}")
|
||||
return await xiaomusic.call_main_thread_function(xiaomusic.play_url, arg1=url)
|
||||
|
||||
|
||||
def static_path_handler(filename):
|
||||
log.debug(filename)
|
||||
log.debug(static_path)
|
||||
@@ -62,7 +186,7 @@ def static_path_handler(filename):
|
||||
|
||||
|
||||
def run_app():
|
||||
app.run(host=host, port=port)
|
||||
serve(app, host=host, port=port)
|
||||
|
||||
|
||||
def StartHTTPServer(_port, _static_path, _xiaomusic):
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
$(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("随机播放");
|
||||
append_op_button_name("刷新列表");
|
||||
append_op_button_name("下一首");
|
||||
append_op_button_name("关机");
|
||||
|
||||
$container.append($("<hr>"));
|
||||
|
||||
@@ -14,11 +14,81 @@ $(function(){
|
||||
append_op_button_name("60分钟后关机");
|
||||
|
||||
// 拉取声音
|
||||
sendcmd("get_volume#");
|
||||
$.get("/getvolume", function(data, status) {
|
||||
console.log(data, status, data["volume"]);
|
||||
$("#volume").val(data.volume);
|
||||
});
|
||||
|
||||
// 拉取版本
|
||||
$.get("/getversion", function(data, status) {
|
||||
console.log(data, status, data["version"]);
|
||||
$("#version").text(`(${data.version})`);
|
||||
});
|
||||
|
||||
// 拉取播放列表
|
||||
function refresh_music_list() {
|
||||
$('#music_list').empty();
|
||||
$.get("/musiclist", function(data, status) {
|
||||
console.log(data, status);
|
||||
$.each(data, function(key, value) {
|
||||
$('#music_list').append($('<option></option>').val(key).text(key));
|
||||
});
|
||||
|
||||
$('#music_list').change(function() {
|
||||
const selectedValue = $(this).val();
|
||||
$('#music_name').empty();
|
||||
const sorted_musics = data[selectedValue].sort(custom_sort_key);
|
||||
$.each(sorted_musics, function(index, item) {
|
||||
$('#music_name').append($('<option></option>').val(item).text(item));
|
||||
});
|
||||
});
|
||||
|
||||
$('#music_list').trigger('change');
|
||||
|
||||
// 获取当前播放列表
|
||||
$.get("curplaylist", function(data, status) {
|
||||
$('#music_list').val(data);
|
||||
$('#music_list').trigger('change');
|
||||
})
|
||||
})
|
||||
}
|
||||
refresh_music_list();
|
||||
|
||||
$("#play_music_list").on("click", () => {
|
||||
var music_list = $("#music_list").val();
|
||||
var music_name = $("#music_name").val();
|
||||
let cmd = "播放列表" + music_list + "|" + music_name;
|
||||
sendcmd(cmd);
|
||||
});
|
||||
|
||||
$("#del_music").on("click", () => {
|
||||
var del_music_name = $("#music_name").val();
|
||||
if (confirm(`确定删除歌曲 ${del_music_name} 吗?`)) {
|
||||
console.log(`删除歌曲 ${del_music_name}`);
|
||||
$.ajax({
|
||||
type: 'POST',
|
||||
url: '/delmusic',
|
||||
data: JSON.stringify({"name": del_music_name}),
|
||||
contentType: "application/json; charset=utf-8",
|
||||
success: () => {
|
||||
alert(`删除 ${del_music_name} 成功`);
|
||||
refresh_music_list();
|
||||
},
|
||||
error: () => {
|
||||
alert(`删除 ${del_music_name} 失败`);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$("#playurl").on("click", () => {
|
||||
var url = $("#music-url").val();
|
||||
$.get(`/playurl?url=${url}`, function(data, status) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
|
||||
function append_op_button_name(name) {
|
||||
append_op_button(name, name);
|
||||
}
|
||||
@@ -40,8 +110,8 @@ $(function(){
|
||||
|
||||
$("#play").on("click", () => {
|
||||
var search_key = $("#music-name").val();
|
||||
var filename=$("#music-filename").val();
|
||||
let cmd = "播放歌曲"+search_key+"|"+filename;
|
||||
var filename = $("#music-filename").val();
|
||||
let cmd = "播放歌曲" + search_key + "|" + filename;
|
||||
sendcmd(cmd);
|
||||
});
|
||||
|
||||
@@ -54,10 +124,12 @@ $(function(){
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/cmd",
|
||||
contentType: "application/json",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({cmd: cmd}),
|
||||
success: () => {
|
||||
// 请求成功时执行的操作
|
||||
if (cmd == "刷新列表") {
|
||||
setTimeout(refresh_music_list, 3000);
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
// 请求失败时执行的操作
|
||||
@@ -99,4 +171,23 @@ $(function(){
|
||||
setInterval(() => {
|
||||
get_playing_music();
|
||||
}, 3000);
|
||||
|
||||
function custom_sort_key(a, b) {
|
||||
// 使用正则表达式提取数字前缀
|
||||
const numericPrefixA = a.match(/^(\d+)/) ? parseInt(a.match(/^(\d+)/)[1], 10) : null;
|
||||
const numericPrefixB = b.match(/^(\d+)/) ? parseInt(b.match(/^(\d+)/)[1], 10) : null;
|
||||
|
||||
// 如果两个键都有数字前缀,则按数字大小排序
|
||||
if (numericPrefixA !== null && numericPrefixB !== null) {
|
||||
return numericPrefixA - numericPrefixB;
|
||||
}
|
||||
|
||||
// 如果一个键有数字前缀而另一个没有,则有数字前缀的键排在前面
|
||||
if (numericPrefixA !== null) return -1;
|
||||
if (numericPrefixB !== null) return 1;
|
||||
|
||||
// 如果两个键都没有数字前缀,则按照常规字符串排序
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
@@ -1,74 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<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: 300px;
|
||||
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>
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱操控面板</h2>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱操控面板<span id="version">(版本未知)</span></h2>
|
||||
<hr>
|
||||
<div id="cmds">
|
||||
</div>
|
||||
<hr>
|
||||
<div style="margin-left: 20px;">
|
||||
<div style="margin: 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>
|
||||
<svg 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>
|
||||
<a href="/static/setting.html">
|
||||
<svg fill="#8e43e7" height="48px" width="48px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="-11.88 -11.88 77.76 77.76" xml:space="preserve" stroke="#8e43e7" transform="rotate(0)matrix(1, 0, 0, 1, 0, 0)" stroke-width="0.00054"><g id="SVGRepo_bgCarrier" stroke-width="0" transform="translate(0,0), scale(1)"><rect x="-11.88" y="-11.88" width="77.76" height="77.76" rx="18.6624" fill="#addcff" strokewidth="0"></rect></g><g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round" stroke="#CCCCCC" stroke-width="1.512"></g><g id="SVGRepo_iconCarrier"> <g> <path d="M51.22,21h-5.052c-0.812,0-1.481-0.447-1.792-1.197s-0.153-1.54,0.42-2.114l3.572-3.571 c0.525-0.525,0.814-1.224,0.814-1.966c0-0.743-0.289-1.441-0.814-1.967l-4.553-4.553c-1.05-1.05-2.881-1.052-3.933,0l-3.571,3.571 c-0.574,0.573-1.366,0.733-2.114,0.421C33.447,9.313,33,8.644,33,7.832V2.78C33,1.247,31.753,0,30.22,0H23.78 C22.247,0,21,1.247,21,2.78v5.052c0,0.812-0.447,1.481-1.197,1.792c-0.748,0.313-1.54,0.152-2.114-0.421l-3.571-3.571 c-1.052-1.052-2.883-1.05-3.933,0l-4.553,4.553c-0.525,0.525-0.814,1.224-0.814,1.967c0,0.742,0.289,1.44,0.814,1.966l3.572,3.571 c0.573,0.574,0.73,1.364,0.42,2.114S8.644,21,7.832,21H2.78C1.247,21,0,22.247,0,23.78v6.439C0,31.753,1.247,33,2.78,33h5.052 c0.812,0,1.481,0.447,1.792,1.197s0.153,1.54-0.42,2.114l-3.572,3.571c-0.525,0.525-0.814,1.224-0.814,1.966 c0,0.743,0.289,1.441,0.814,1.967l4.553,4.553c1.051,1.051,2.881,1.053,3.933,0l3.571-3.572c0.574-0.573,1.363-0.731,2.114-0.42 c0.75,0.311,1.197,0.98,1.197,1.792v5.052c0,1.533,1.247,2.78,2.78,2.78h6.439c1.533,0,2.78-1.247,2.78-2.78v-5.052 c0-0.812,0.447-1.481,1.197-1.792c0.751-0.312,1.54-0.153,2.114,0.42l3.571,3.572c1.052,1.052,2.883,1.05,3.933,0l4.553-4.553 c0.525-0.525,0.814-1.224,0.814-1.967c0-0.742-0.289-1.44-0.814-1.966l-3.572-3.571c-0.573-0.574-0.73-1.364-0.42-2.114 S45.356,33,46.168,33h5.052c1.533,0,2.78-1.247,2.78-2.78V23.78C54,22.247,52.753,21,51.22,21z M52,30.22 C52,30.65,51.65,31,51.22,31h-5.052c-1.624,0-3.019,0.932-3.64,2.432c-0.622,1.5-0.295,3.146,0.854,4.294l3.572,3.571 c0.305,0.305,0.305,0.8,0,1.104l-4.553,4.553c-0.304,0.304-0.799,0.306-1.104,0l-3.571-3.572c-1.149-1.149-2.794-1.474-4.294-0.854 c-1.5,0.621-2.432,2.016-2.432,3.64v5.052C31,51.65,30.65,52,30.22,52H23.78C23.35,52,23,51.65,23,51.22v-5.052 c0-1.624-0.932-3.019-2.432-3.64c-0.503-0.209-1.021-0.311-1.533-0.311c-1.014,0-1.997,0.4-2.761,1.164l-3.571,3.572 c-0.306,0.306-0.801,0.304-1.104,0l-4.553-4.553c-0.305-0.305-0.305-0.8,0-1.104l3.572-3.571c1.148-1.148,1.476-2.794,0.854-4.294 C10.851,31.932,9.456,31,7.832,31H2.78C2.35,31,2,30.65,2,30.22V23.78C2,23.35,2.35,23,2.78,23h5.052 c1.624,0,3.019-0.932,3.64-2.432c0.622-1.5,0.295-3.146-0.854-4.294l-3.572-3.571c-0.305-0.305-0.305-0.8,0-1.104l4.553-4.553 c0.304-0.305,0.799-0.305,1.104,0l3.571,3.571c1.147,1.147,2.792,1.476,4.294,0.854C22.068,10.851,23,9.456,23,7.832V2.78 C23,2.35,23.35,2,23.78,2h6.439C30.65,2,31,2.35,31,2.78v5.052c0,1.624,0.932,3.019,2.432,3.64 c1.502,0.622,3.146,0.294,4.294-0.854l3.571-3.571c0.306-0.305,0.801-0.305,1.104,0l4.553,4.553c0.305,0.305,0.305,0.8,0,1.104 l-3.572,3.571c-1.148,1.148-1.476,2.794-0.854,4.294c0.621,1.5,2.016,2.432,3.64,2.432h5.052C51.65,23,52,23.35,52,23.78V30.22z"></path> <path d="M27,18c-4.963,0-9,4.037-9,9s4.037,9,9,9s9-4.037,9-9S31.963,18,27,18z M27,34c-3.859,0-7-3.141-7-7s3.141-7,7-7 s7,3.141,7,7S30.859,34,27,34z"></path> </g> </g></svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
@@ -81,5 +32,25 @@
|
||||
<div class="container">
|
||||
<div id="playering-music" class="text"></div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<label for="music_list">播放列表:</label>
|
||||
<select id="music_list"></select>
|
||||
<label for="music_name">歌曲:</label>
|
||||
<select id="music_name"></select>
|
||||
</div>
|
||||
<button id="play_music_list">播放列表歌曲</button>
|
||||
<button id="del_music">删除选中歌曲</button>
|
||||
|
||||
<hr>
|
||||
<div>
|
||||
<input id="music-url" type="text" placeholder="链接(http://ngcdn001.cnr.cn/live/zgzs/index.m3u8)"></input>
|
||||
</div>
|
||||
<button id="playurl">播放链接</button>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
64
xiaomusic/static/m3u.html
Normal file
64
xiaomusic/static/m3u.html
Normal file
@@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>M3U to JSON Converter</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
// VConsole 默认会挂载到 `window.VConsole` 上
|
||||
var vConsole = new window.VConsole();
|
||||
</script>
|
||||
-->
|
||||
<script>
|
||||
function handleFileSelect(evt) {
|
||||
var file = evt.target.files[0];
|
||||
if (file) {
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
document.getElementById('m3u-input').value = e.target.result;
|
||||
};
|
||||
reader.readAsText(file);
|
||||
} else {
|
||||
alert('无法加载文件');
|
||||
}
|
||||
}
|
||||
|
||||
function convertToJSON() {
|
||||
var m3uContent = document.getElementById('m3u-input').value;
|
||||
var lines = m3uContent.split('\n');
|
||||
console.log(lines);
|
||||
var musicsArray = [];
|
||||
var currentName = '';
|
||||
lines.forEach(function(line) {
|
||||
line = line.trim();
|
||||
if (line.startsWith('#EXTINF:')) {
|
||||
currentName = line.replace(/.*,/g, '');
|
||||
} else if (line.startsWith('http') && currentName !== '') {
|
||||
musicsArray.push({"name": currentName, "type": "radio", "url": line});
|
||||
currentName = ''; // Reset the name for the next entry
|
||||
}
|
||||
});
|
||||
var output = [{
|
||||
"name": "m3u电台",
|
||||
"musics": musicsArray
|
||||
}];
|
||||
|
||||
document.getElementById('json-output').value = JSON.stringify(output, null, 2);
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>M3U to JSON Converter</h1>
|
||||
<input type="file" id="file-input" accept=".m3u" onchange="handleFileSelect(event)"/><br>
|
||||
<textarea id="m3u-input" rows="10" cols="50" placeholder="粘贴m3u内容或上传文件..."></textarea><br>
|
||||
<button onclick="convertToJSON()">转换</button><br>
|
||||
<textarea id="json-output" rows="10" cols="50" placeholder="转换后的JSON..."></textarea>
|
||||
</body>
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
</html>
|
||||
|
||||
43
xiaomusic/static/setting.html
Normal file
43
xiaomusic/static/setting.html
Normal file
@@ -0,0 +1,43 @@
|
||||
<!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/setting.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱设置面板<span id="version">(版本未知)</span></h2>
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<label for="mi_did">MI_DID:</label>
|
||||
<select id="mi_did"></select>
|
||||
<label for="mi_hardware">MI_HARDWARE(型号):</label>
|
||||
<select id="mi_hardware" disabled></select>
|
||||
<label for="xiaomusic_search">XIAOMUSIC_SEARCH:</label>
|
||||
<select id="xiaomusic_search">
|
||||
<option value="ytsearch:">ytsearch:</option>
|
||||
<option value="bilisearch:">bilisearch:</option>
|
||||
</select>
|
||||
<label for="xiaomusic_proxy">XIAOMUSIC_PROXY(ytsearch需要):</label>
|
||||
<input id="xiaomusic_proxy" type="text" placeholder="http://192.168.2.5:8080"></input>
|
||||
<label for="xiaomusic_music_list_url">歌单地址:</label>
|
||||
<input id="xiaomusic_music_list_url" type="text" value="https://gist.githubusercontent.com/hanxi/dda82d964a28f8110f8fba81c3ff8314/raw/example.json"></input>
|
||||
<label for="xiaomusic_music_list_json">歌单内容:</label>
|
||||
<textarea id="xiaomusic_music_list_json" type="text"></textarea>
|
||||
</div>
|
||||
<hr>
|
||||
<button onclick="location.href='/';">返回首页</button>
|
||||
<button id="get_music_list">获取歌单</button>
|
||||
<button id="save">保存</button>
|
||||
<a class="button" href="/downloadlog" download="xiaomusic.txt">下载日志文件</a>
|
||||
<hr>
|
||||
|
||||
<a href="/static/m3u.html" target="_blank">m3u文件转换工具</a>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
129
xiaomusic/static/setting.js
Normal file
129
xiaomusic/static/setting.js
Normal file
@@ -0,0 +1,129 @@
|
||||
$(function(){
|
||||
// 拉取版本
|
||||
$.get("/getversion", function(data, status) {
|
||||
console.log(data, status, data["version"]);
|
||||
$("#version").text(`(${data.version})`);
|
||||
});
|
||||
|
||||
const updateSelectOptions = (selectId, optionsList, selectedOption) => {
|
||||
const select = $(selectId);
|
||||
select.empty();
|
||||
optionsList.forEach(option => {
|
||||
select.append(new Option(option, option));
|
||||
});
|
||||
select.val(selectedOption);
|
||||
};
|
||||
|
||||
let isChanging = false;
|
||||
// 更新下拉菜单的函数
|
||||
const updateSelect = (selectId, value) => {
|
||||
if (!isChanging) {
|
||||
isChanging = true;
|
||||
$(selectId).val(value);
|
||||
isChanging = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 联动逻辑
|
||||
const linkSelects = (sourceSelect, sourceList, targetSelect, targetList) => {
|
||||
$(sourceSelect).change(function() {
|
||||
if (!isChanging) {
|
||||
const selectedValue = $(this).val();
|
||||
const selectedIndex = sourceList.indexOf(selectedValue);
|
||||
console.log(selectedIndex, selectedValue,sourceList,targetList)
|
||||
if (selectedIndex !== -1) {
|
||||
updateSelect(targetSelect, targetList[selectedIndex]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
// 拉取现有配置
|
||||
$.get("/getsetting", function(data, status) {
|
||||
console.log(data, status);
|
||||
|
||||
updateSelectOptions("#mi_did", data.mi_did_list, data.mi_did);
|
||||
updateSelectOptions("#mi_hardware", data.mi_hardware_list, data.mi_hardware);
|
||||
|
||||
// 初始化联动
|
||||
linkSelects('#mi_did', data.mi_did_list, '#mi_hardware', data.mi_hardware_list);
|
||||
|
||||
if (data.xiaomusic_search != "") {
|
||||
$("#xiaomusic_search").val(data.xiaomusic_search);
|
||||
}
|
||||
|
||||
if (data.xiaomusic_proxy != "") {
|
||||
$("#xiaomusic_proxy").val(data.xiaomusic_proxy);
|
||||
}
|
||||
|
||||
if (data.xiaomusic_music_list_url != "") {
|
||||
$("#xiaomusic_music_list_url").val(data.xiaomusic_music_list_url);
|
||||
}
|
||||
|
||||
if (data.xiaomusic_music_list_json != "") {
|
||||
$("#xiaomusic_music_list_json").val(data.xiaomusic_music_list_json);
|
||||
}
|
||||
});
|
||||
|
||||
$("#save").on("click", () => {
|
||||
var mi_did = $("#mi_did").val();
|
||||
var mi_hardware = $("#mi_hardware").val();
|
||||
var xiaomusic_search = $("#xiaomusic_search").val();
|
||||
var xiaomusic_proxy = $("#xiaomusic_proxy").val();
|
||||
var xiaomusic_music_list_url = $("#xiaomusic_music_list_url").val();
|
||||
var xiaomusic_music_list_json = $("#xiaomusic_music_list_json").val();
|
||||
console.log("mi_did", mi_did);
|
||||
console.log("mi_hardware", mi_hardware);
|
||||
console.log("xiaomusic_search", xiaomusic_search);
|
||||
console.log("xiaomusic_proxy", xiaomusic_proxy);
|
||||
console.log("xiaomusic_music_list_url", xiaomusic_music_list_url);
|
||||
console.log("xiaomusic_music_list_json", xiaomusic_music_list_json);
|
||||
var data = {
|
||||
mi_did: mi_did,
|
||||
mi_hardware: mi_hardware,
|
||||
xiaomusic_search: xiaomusic_search,
|
||||
xiaomusic_proxy: xiaomusic_proxy,
|
||||
xiaomusic_music_list_url: xiaomusic_music_list_url,
|
||||
xiaomusic_music_list_json: xiaomusic_music_list_json,
|
||||
};
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/savesetting",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data),
|
||||
success: (msg) => {
|
||||
alert(msg);
|
||||
},
|
||||
error: (msg) => {
|
||||
alert(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$("#get_music_list").on("click", () => {
|
||||
var xiaomusic_music_list_url = $("#xiaomusic_music_list_url").val();
|
||||
console.log("xiaomusic_music_list_url", xiaomusic_music_list_url);
|
||||
var data = {
|
||||
url: xiaomusic_music_list_url,
|
||||
};
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/downloadjson",
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify(data),
|
||||
success: (res) => {
|
||||
if (res.ret == "OK") {
|
||||
$("#xiaomusic_music_list_json").val(res.content);
|
||||
} else {
|
||||
console.log(res);
|
||||
alert(res.ret);
|
||||
}
|
||||
},
|
||||
error: (res) => {
|
||||
console.log(res);
|
||||
alert(res);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
79
xiaomusic/static/style.css
Normal file
79
xiaomusic/static/style.css
Normal file
@@ -0,0 +1,79 @@
|
||||
.button {
|
||||
line-height: 50px;
|
||||
font-size: 14px;
|
||||
}
|
||||
button, .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, .button:active {
|
||||
font-weight:bold;
|
||||
background-color: #007CBA;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
label {
|
||||
margin-left: 10px;
|
||||
width: 300px;
|
||||
}
|
||||
input,select {
|
||||
margin: 10px;
|
||||
width: 300px;
|
||||
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;
|
||||
}
|
||||
|
||||
.rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-left: 20px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
footer {
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
textarea{
|
||||
margin: 10px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
}
|
||||
@@ -1,16 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import socket
|
||||
from http.cookies import SimpleCookie
|
||||
from typing import AsyncIterator
|
||||
from urllib.parse import urlparse
|
||||
import difflib
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import string
|
||||
import tempfile
|
||||
from collections.abc import AsyncIterator
|
||||
from http.cookies import SimpleCookie
|
||||
from urllib.parse import urlparse
|
||||
|
||||
import aiohttp
|
||||
import mutagen
|
||||
import requests
|
||||
from requests.utils import cookiejar_from_dict
|
||||
|
||||
from xiaomusic.const import SUPPORT_MUSIC_TYPE
|
||||
|
||||
|
||||
### HELP FUNCTION ###
|
||||
def parse_cookie_string(cookie_string):
|
||||
@@ -62,6 +69,174 @@ def validate_proxy(proxy_str: str) -> bool:
|
||||
|
||||
return True
|
||||
|
||||
|
||||
# 模糊搜索
|
||||
def fuzzyfinder(user_input, collection):
|
||||
return difflib.get_close_matches(user_input, collection, 10, cutoff=0.1)
|
||||
return difflib.get_close_matches(user_input, collection, n=10, cutoff=0.1)
|
||||
|
||||
|
||||
def find_best_match(user_input, collection, cutoff=0.6):
|
||||
matches = difflib.get_close_matches(user_input, collection, n=1, cutoff=cutoff)
|
||||
return matches[0] if matches else None
|
||||
|
||||
|
||||
# 歌曲排序
|
||||
def custom_sort_key(s):
|
||||
# 使用正则表达式分别提取字符串的数字前缀和数字后缀
|
||||
prefix_match = re.match(r"^(\d+)", s)
|
||||
suffix_match = re.search(r"(\d+)$", s)
|
||||
|
||||
numeric_prefix = int(prefix_match.group(0)) if prefix_match else None
|
||||
numeric_suffix = int(suffix_match.group(0)) if suffix_match else None
|
||||
|
||||
if numeric_prefix is not None:
|
||||
# 如果前缀是数字,先按前缀数字排序,再按整个字符串排序
|
||||
return (0, numeric_prefix, s)
|
||||
elif numeric_suffix is not None:
|
||||
# 如果后缀是数字,先按前缀字符排序,再按后缀数字排序
|
||||
return (1, s[: suffix_match.start()], numeric_suffix)
|
||||
else:
|
||||
# 如果前缀和后缀都不是数字,按字典序排序
|
||||
return (2, s)
|
||||
|
||||
|
||||
# fork from https://gist.github.com/dougthor42/001355248518bc64d2f8
|
||||
def walk_to_depth(root, depth=None, *args, **kwargs):
|
||||
"""
|
||||
Wrapper around os.walk that stops after going down `depth` folders.
|
||||
I had my own version, but it wasn't as efficient as
|
||||
http://stackoverflow.com/a/234329/1354930, so I modified to be more
|
||||
similar to nosklo's answer.
|
||||
However, nosklo's answer doesn't work if topdown=False, so I kept my
|
||||
version.
|
||||
"""
|
||||
# Let people use this as a standard `os.walk` function.
|
||||
if depth is None:
|
||||
return os.walk(root, *args, **kwargs)
|
||||
|
||||
# remove any trailing separators so that our counts are correct.
|
||||
root = root.rstrip(os.path.sep)
|
||||
|
||||
def main_func(root, depth, *args, **kwargs):
|
||||
"""Faster because it skips traversing dirs that are too deep."""
|
||||
root_depth = root.count(os.path.sep)
|
||||
for dirpath, dirnames, filenames in os.walk(root, *args, **kwargs):
|
||||
yield (dirpath, dirnames, filenames)
|
||||
|
||||
# calculate how far down we are.
|
||||
current_folder_depth = dirpath.count(os.path.sep)
|
||||
if current_folder_depth >= root_depth + depth:
|
||||
del dirnames[:]
|
||||
|
||||
def fallback_func(root, depth, *args, **kwargs):
|
||||
"""Slower, but works when topdown is False"""
|
||||
root_depth = root.count(os.path.sep)
|
||||
for dirpath, dirnames, filenames in os.walk(root, *args, **kwargs):
|
||||
current_folder_depth = dirpath.count(os.path.sep)
|
||||
if current_folder_depth <= root_depth + depth:
|
||||
yield (dirpath, dirnames, filenames)
|
||||
|
||||
# there's gotta be a better way do do this...
|
||||
try:
|
||||
if args[0] is False:
|
||||
yield from fallback_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
else:
|
||||
yield from main_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if kwargs["topdown"] is False:
|
||||
yield from fallback_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
else:
|
||||
yield from main_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
except KeyError:
|
||||
yield from main_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
|
||||
|
||||
def downloadfile(url):
|
||||
# 清理和验证URL
|
||||
# 解析URL
|
||||
parsed_url = urlparse(url)
|
||||
|
||||
# 基础验证:仅允许HTTP和HTTPS协议
|
||||
if parsed_url.scheme not in ("http", "https"):
|
||||
raise Warning(
|
||||
f"Invalid URL scheme: {parsed_url.scheme}. Only HTTP and HTTPS are allowed."
|
||||
)
|
||||
|
||||
# 构建目标URL
|
||||
cleaned_url = parsed_url.geturl()
|
||||
|
||||
# 发起请求
|
||||
response = requests.get(cleaned_url, timeout=5) # 增加超时以避免长时间挂起
|
||||
response.raise_for_status() # 如果响应不是200,引发HTTPError异常
|
||||
return response.text
|
||||
|
||||
|
||||
async def _get_web_music_duration(session, url, start=0, end=500):
|
||||
duration = 0
|
||||
headers = {"Range": f"bytes={start}-{end}"}
|
||||
async with session.get(url, headers=headers) as response:
|
||||
array_buffer = await response.read()
|
||||
with tempfile.NamedTemporaryFile(delete=False) as tmp:
|
||||
tmp.write(array_buffer)
|
||||
name = tmp.name
|
||||
|
||||
try:
|
||||
m = mutagen.File(name)
|
||||
duration = m.info.length
|
||||
except Exception:
|
||||
pass
|
||||
os.remove(name)
|
||||
return duration
|
||||
|
||||
|
||||
async def get_web_music_duration(url, start=0, end=500):
|
||||
duration = 0
|
||||
try:
|
||||
parsed_url = urlparse(url)
|
||||
file_path = parsed_url.path
|
||||
_, extension = os.path.splitext(file_path)
|
||||
if extension.lower() not in SUPPORT_MUSIC_TYPE:
|
||||
cleaned_url = parsed_url.geturl()
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
cleaned_url,
|
||||
allow_redirects=True,
|
||||
headers={
|
||||
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36"
|
||||
},
|
||||
) as response:
|
||||
url = str(response.url)
|
||||
# 设置总超时时间为3秒
|
||||
timeout = aiohttp.ClientTimeout(total=3)
|
||||
async with aiohttp.ClientSession(timeout=timeout) as session:
|
||||
duration = await _get_web_music_duration(session, url, start=0, end=500)
|
||||
if duration <= 0:
|
||||
duration = await _get_web_music_duration(
|
||||
session, url, start=0, end=1000
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
return duration, url
|
||||
|
||||
|
||||
# 获取文件播放时长
|
||||
def get_local_music_duration(filename):
|
||||
duration = 0
|
||||
try:
|
||||
m = mutagen.File(filename)
|
||||
duration = m.info.length
|
||||
except Exception:
|
||||
pass
|
||||
return duration
|
||||
|
||||
|
||||
def get_random(length):
|
||||
return "".join(random.sample(string.ascii_letters + string.digits, length))
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user