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

Compare commits

...

135 Commits

Author SHA1 Message Date
涵曦
c552a34ec1 bump: version 0.3.55 → 0.3.56 2024-12-07 17:31:00 +08:00
涵曦
e4144aa568 build: update static version 2024-12-07 17:30:59 +08:00
涵曦
fe54ad29e2 fix: 播放失败设置重试次数10次,解决设备失联后无限重试的问题 2024-12-07 15:54:19 +08:00
涵曦
48a8bf3325 feat: tag 信息支持写入到歌曲文件 see #266 2024-12-06 22:55:14 +08:00
涵曦
2c5b7b7f26 Update README.md 2024-12-06 00:22:27 +08:00
涵曦
46168315d0 feat: 开启gzip压缩 2024-12-05 21:18:51 +08:00
涵曦
b385bfab54 fix: 修复最近新增歌单问题 2024-12-04 16:46:19 +08:00
徒言
4e2e3e1f74 fix: 小程序码移动端布局兼容 (#293) 2024-12-04 12:21:49 +08:00
涵曦
0db3e4cada bump: version 0.3.54 → 0.3.55 2024-12-04 10:22:27 +08:00
涵曦
fa21d02e1d build: update static version 2024-12-04 10:22:26 +08:00
涵曦
be48fe9f54 fix: 修复播放接口报错问题 2024-12-04 10:17:06 +08:00
徒言
042a91336e chore: 引导页新增小程序码 (#290) 2024-12-04 09:54:38 +08:00
涵曦
790a4cd808 bump: version 0.3.53 → 0.3.54 2024-12-04 01:41:29 +08:00
涵曦
70d029f4d1 build: update static version 2024-12-04 01:41:28 +08:00
52fisher
0472ad3188 fix: 安卓低版本webview对audio的src为空值的报错 (#289) 2024-12-04 01:30:07 +08:00
涵曦
733c44d12f feat: 新增最近新增歌单 close #273 2024-12-03 21:44:48 +08:00
涵曦
8c92afd09b fix: 修复M01语音播放问题,X08C X08E X8F 型号默认采用型号兼容模式 see #30 2024-12-03 21:25:51 +08:00
涵曦
742929b9d5 Update README.md 2024-12-03 21:18:26 +08:00
涵曦
4766e08ff4 Update README.md 2024-12-03 21:17:11 +08:00
涵曦
99c4296c7a bump: version 0.3.52 → 0.3.53 2024-12-03 12:15:09 +08:00
涵曦
0ae24f4810 build: update static version 2024-12-03 12:15:08 +08:00
涵曦
77cca0d18c fix: 解决播放接口修改后播放失败的问题 2024-12-03 12:14:57 +08:00
涵曦
ddc24595df bump: version 0.3.51 → 0.3.52 2024-12-03 12:02:39 +08:00
涵曦
ce1bfb164c build: update static version 2024-12-03 12:02:39 +08:00
涵曦
78dbba6c1f fix: 修复播放接口参数错误的问题 2024-12-03 12:02:14 +08:00
涵曦
7eb0ab1e46 bump: version 0.3.50 → 0.3.51 2024-12-03 09:06:51 +08:00
涵曦
0a2e3cc579 build: update static version 2024-12-03 09:06:50 +08:00
涵曦
75ec336285 fix: 修复空配置启动失败问题 close #284 2024-12-03 09:02:15 +08:00
涵曦
a19d53f000 bump: version 0.3.49 → 0.3.50 2024-12-03 07:11:40 +08:00
涵曦
cdb6190e7a build: update static version 2024-12-03 07:11:40 +08:00
涵曦
1aa9b58561 style: 更新 gitignore 2024-12-02 23:17:54 +08:00
涵曦
6a990f48d0 fix: 更新 yt-dlp ,解决 B 站下载问题 close #279 2024-12-02 23:17:12 +08:00
涵曦
82e92a0380 Update README.md 2024-12-02 21:43:56 +08:00
涵曦
ecce5c8848 feat: 修改日志文件的默认值 2024-12-02 21:38:31 +08:00
涵曦
87fb34e5c9 feat: 新增修改tag缓存信息的接口 close #266 2024-12-02 12:27:09 +08:00
涵曦
df3c4b7fa9 feat: 新增专用的播放歌曲和播放歌单接口,解决默认口令提示词被修改了导致后台失效的问题 2024-12-02 11:40:26 +08:00
涵曦
cb2af0ee9f feat: 统计设备型号 2024-12-02 11:08:19 +08:00
涵曦
8f9bba0ca3 refactor: 调整设置页面 2024-12-01 22:47:56 +08:00
涵曦
b86e8d3196 Update README.md 2024-12-01 22:41:47 +08:00
52fisher
65067346f3 feat: 页面与设置中的HOST不一致时弹窗提醒 (#281) 2024-12-01 22:23:50 +08:00
52fisher
865b412fb7 fix: 网页播放audio获取到错误url无法播放时提醒用户 (#280) 2024-12-01 12:33:05 +08:00
涵曦
441fffd59e Update README.md 2024-11-29 10:02:51 +08:00
52fisher
2ee7b956cf feat: 未发现小爱设备时给予提示 (#278)
fix: input标签自闭合
2024-11-29 07:23:57 +08:00
涵曦
126bfa43a2 feat: 优化设置页面提示 2024-11-28 23:29:06 +08:00
涵曦
3a4d702070 bump: version 0.3.48 → 0.3.49 2024-11-28 20:30:36 +08:00
涵曦
2c7a09b9d4 build: update static version 2024-11-28 20:30:36 +08:00
涵曦
74837baaef feat: 临时文件目录支持配置 #99 2024-11-28 18:55:18 +08:00
涵曦
def63b2407 feat: 新增单曲播放和顺序播放功能 close #277 2024-11-28 18:07:40 +08:00
Formatter [BOT]
93d2047c7a Auto-format code 🧹🌟🤖 2024-11-27 10:31:40 +00:00
dludream
9a1b9d1949 fix: 修复中文数字转换函数对'十、十一'等数字的处理 (#275) 2024-11-27 18:31:12 +08:00
涵曦
88fa4318dc Update setting.html 2024-11-27 14:29:59 +08:00
涵曦
0bc4bc8b13 feat: 设置播放类型支持配置语音提示词,定时任务支持设置播放类型 2024-11-26 23:18:25 +08:00
涵曦
ca2ddcd89c bump: version 0.3.47 → 0.3.48 2024-11-20 00:31:57 +08:00
涵曦
78acc35a62 build: update static version 2024-11-20 00:31:56 +08:00
涵曦
323a832a9e feat: 支持替换默认口令,而不是追加 close #259 2024-11-20 00:24:11 +08:00
涵曦
0c99f4d537 feat: 新增自定义个歌单接口 #242 2024-11-20 00:09:54 +08:00
涵曦
b2737f745d fix: 锁定 PWA 应用旋转方向 2024-11-14 22:55:41 +08:00
涵曦
464a1e1bd1 bump: version 0.3.46 → 0.3.47 2024-11-14 08:15:40 +08:00
涵曦
7bd613f74c build: update static version 2024-11-14 08:15:39 +08:00
涵曦
3fb0a3bae9 fix: 修复 PWA 应用有密码时报错的问题 2024-11-14 00:51:53 +08:00
涵曦
b4f0e7b349 feat: 支持 PWA 应用安装 2024-11-14 00:26:19 +08:00
Formatter [BOT]
7c1ce81b5e Auto-format code 🧹🌟🤖 2024-11-13 15:28:49 +00:00
涵曦
052027fb50 feat: 新增模糊匹配测试用例 2024-11-13 23:28:10 +08:00
涵曦
b4d8434507 fix: 修复播放顺序没有按数字排序的问题 close #249 2024-11-12 09:14:20 +08:00
涵曦
ec6018eabf bump: version 0.3.45 → 0.3.46 2024-11-08 23:22:21 +08:00
涵曦
bdeb2b5647 build: update static version 2024-11-08 23:22:21 +08:00
涵曦
657e046379 fix: 添加依赖库 requests 2024-11-08 23:11:20 +08:00
涵曦
bd6dd43737 refactor: 依赖库已经支持分段获取静态文件,重构代码 2024-11-08 21:19:38 +08:00
涵曦
5766919e69 feat: 升级依赖库 2024-11-08 15:54:17 +08:00
涵曦
0fe5f74d12 bump: version 0.3.44 → 0.3.45 2024-11-08 00:43:14 +08:00
涵曦
a2d6d1c357 build: update static version 2024-11-08 00:43:13 +08:00
涵曦
5c61ef4b26 fix: 修复定时任务报错问题 2024-11-07 22:43:27 +08:00
涵曦
e57a02a192 feat: 定时任务支持设置音量 2024-11-07 22:35:17 +08:00
涵曦
5587411e37 feat: 播放歌单口令支持配置 2024-11-07 22:30:05 +08:00
涵曦
95f756fb28 bump: version 0.3.43 → 0.3.44 2024-11-01 10:14:31 +08:00
涵曦
25ed90efa3 build: update static version 2024-11-01 10:14:29 +08:00
涵曦
147bbcdd4c build: 编译优化 2024-11-01 09:53:21 +08:00
涵曦
8dd9cfe0ac feat: 日志时间里加上日期 2024-11-01 09:27:56 +08:00
涵曦
089bafd693 fix: 修复搜索失败的问题 2024-11-01 09:22:55 +08:00
涵曦
13b72bff97 Update build-base-image.yml 2024-10-31 09:29:35 +08:00
涵曦
3e959a08f0 bump: version 0.3.42 → 0.3.43 2024-10-30 21:39:08 +08:00
涵曦
3d1517854c build: update static version 2024-10-30 21:39:08 +08:00
涵曦
e65c2ca3c9 build: 镜像编译优化 2024-10-30 19:51:10 +08:00
涵曦
6d7ff48913 build: 修改编译脚本 2024-10-30 18:50:26 +08:00
涵曦
7291826b56 Update build-base-image.yml 2024-10-30 16:08:22 +08:00
涵曦
fa06a7ad17 Update build-base-image.yml 2024-10-30 14:27:44 +08:00
涵曦
614cff3f05 Update release.yml 2024-10-30 13:14:54 +08:00
涵曦
a8d924e31f Update build-base-image.yml 2024-10-30 13:14:23 +08:00
涵曦
a9a6ead73f Update release.yml 2024-10-30 12:58:18 +08:00
涵曦
bd41735df2 Update build-base-image.yml 2024-10-30 12:57:01 +08:00
涵曦
655f0f9ab7 Update ci.yml 2024-10-30 12:56:03 +08:00
涵曦
a003b6d0bf Update build-base-image.yml 2024-10-30 12:53:45 +08:00
涵曦
16f224b8e5 Update build-base-image.yml 2024-10-30 12:53:00 +08:00
涵曦
d4ca2c886f Update install_dependencies.sh 2024-10-30 12:48:27 +08:00
涵曦
48b9e0a837 Update ci.yml 2024-10-30 12:34:15 +08:00
涵曦
38df7aa6b9 Update ci.yml 2024-10-30 12:32:56 +08:00
涵曦
29756c29a7 Update ci.yml 2024-10-30 11:29:06 +08:00
涵曦
89287164ad Update build-base-image.yml 2024-10-30 11:11:33 +08:00
涵曦
81fb330db9 Update ci.yml 2024-10-30 11:11:10 +08:00
涵曦
365954ecb0 Update ci.yml 2024-10-30 11:09:32 +08:00
涵曦
d7fd7c43dc Update ci.yml 2024-10-30 11:07:55 +08:00
涵曦
e48c6456fc Update ci.yml 2024-10-30 10:45:41 +08:00
涵曦
193e1885e0 Update ci.yml 2024-10-30 10:41:04 +08:00
涵曦
9acd5820ef Update ci.yml 2024-10-30 10:39:20 +08:00
涵曦
119283693a Update ci.yml 2024-10-30 10:31:14 +08:00
涵曦
dc9eb96a27 Update ci.yml 2024-10-30 10:23:26 +08:00
涵曦
c022b5a0b1 Update ci.yml 2024-10-30 10:16:46 +08:00
涵曦
bcbbfc5f52 Update ci.yml 2024-10-30 10:05:32 +08:00
涵曦
3da07ce816 Update ci.yml 2024-10-30 09:54:19 +08:00
涵曦
8629c16fe4 build: 编译镜像 2024-10-30 09:50:22 +08:00
涵曦
ac6fbd1b82 Update Dockerfile.base 2024-10-30 09:25:29 +08:00
涵曦
6995afed16 Update ci.yml 2024-10-30 09:19:41 +08:00
涵曦
b49e250488 build: 修改镜像 2024-10-30 09:03:14 +08:00
涵曦
5032747f1e build: 修改镜像 2024-10-30 08:51:59 +08:00
涵曦
f749edcf16 build: 新增编译基础镜像 2024-10-30 08:42:32 +08:00
52fisher
14598aedee feat: 播放列表可以删除当前歌曲(!危险操作,请在设置中心开启相关功能) (#250) 2024-10-30 06:38:23 +08:00
涵曦
8845148cce fix: 修复谷歌统计导致的卡顿问题 2024-10-30 00:13:41 +08:00
涵曦
1513a59726 fix: 解决挂载网盘卡死的问题 2024-10-28 02:56:23 +08:00
涵曦
497c1f34ef test: 修改测试用例 2024-10-27 09:30:29 +08:00
52fisher
77920dffac feature: Update Theme (#248)
* pure:修复群内反馈的部分分辨率按钮错位问题
xmusicplayer: 新增收藏、取消收藏功能

* fix: 安卓某些浏览器duration一直为0的问题
2024-10-26 15:55:12 +08:00
涵曦
c452136537 feat: 插件自定义口令支持获取语音输入内容 #105 2024-10-24 19:35:09 +08:00
涵曦
aa2992b5d7 bump: version 0.3.41 → 0.3.42 2024-10-24 11:00:00 +08:00
涵曦
7fcd3eeae5 build: update static version 2024-10-24 10:59:59 +08:00
涵曦
30194272d9 Update ci.yml 2024-10-23 19:01:53 +08:00
涵曦
1b71301b06 Update Dockerfile 2024-10-23 18:26:14 +08:00
涵曦
13bbff8d67 Update ci.yml 2024-10-23 17:22:47 +08:00
涵曦
ae3507b811 Update ci.yml 2024-10-23 16:53:37 +08:00
涵曦
bdfb0a4127 ci: update ci 2024-10-23 15:31:04 +08:00
涵曦
3d0a38cbb8 build: 尝试修复 arm 平台的容器下不能启动的问题 2024-10-23 14:08:29 +08:00
涵曦
f469f63d97 fix: 尝试修复缺少 libtiff.so.6 文件的问题 #244 2024-10-23 06:22:00 +08:00
涵曦
6544bb2ff1 fix: 修复默认主题播放歌曲输入框空的情况 2024-10-21 22:59:38 +08:00
涵曦
668237401e fix: 尝试修复停止后自动播放的问题 2024-10-21 22:53:37 +08:00
涵曦
139ebf37c4 Update README.md 2024-10-21 19:40:33 +08:00
涵曦
7146d61fcb Update README.md 2024-10-18 01:14:41 +08:00
涵曦
6033c1a6fc Update README.md 2024-10-18 01:14:02 +08:00
157 changed files with 1969 additions and 784 deletions

45
.github/workflows/build-base-image.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Build Docker Base Image
on:
push:
paths:
- 'Dockerfile.builder'
- 'Dockerfile.runtime'
- 'install_dependencies.sh'
- '.github/workflows/build-base-image.yml'
workflow_dispatch:
jobs:
build-image:
runs-on: ubuntu-latest
if: github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push runtime
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile.runtime
platforms: linux/amd64, linux/arm64, linux/arm/v7
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:runtime
- name: Build and push builder
uses: docker/build-push-action@v4
with:
context: .
file: ./Dockerfile.builder
platforms: linux/amd64, linux/arm64, linux/arm/v7
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:builder

View File

@@ -1,37 +1,88 @@
name: ci
on:
push:
branches:
- "*"
workflow_dispatch:
env:
TEST_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}
jobs:
build-image:
build-test-publish:
runs-on: ubuntu-latest
# run unless event type is pull_request
if: github.event_name != 'pull_request'
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
uses: docker/setup-buildx-action@v3
- name: Login to Docker Hub
uses: docker/login-action@v2
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
- name: Build Docker image (linux/amd64)
uses: docker/build-push-action@v6
with:
platforms: linux/amd64
context: .
push: false
load: true
tags: ${{ env.TEST_TAG }}-linux-amd64
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
- name: Build Docker image (linux/arm64)
uses: docker/build-push-action@v6
with:
platforms: linux/arm64
context: .
push: false
load: true
tags: ${{ env.TEST_TAG }}-linux-arm64
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
- name: Build Docker image (linux/arm/v7)
uses: docker/build-push-action@v6
with:
platforms: linux/arm/v7
context: .
push: false
load: true
tags: ${{ env.TEST_TAG }}-linux-arm-v7
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new
# We test all the images on amd64 host here. This uses QEMU to emulate
# the other platforms.
- run: docker run --rm ${TEST_TAG}-linux-amd64 -h
- run: docker run --rm ${TEST_TAG}-linux-arm64 -h
- run: docker run --rm ${TEST_TAG}-linux-arm-v7 -h
# This will only push the previously built images.
- name: Publish to Docker Hub
uses: docker/build-push-action@v6
with:
platforms: linux/amd64,linux/arm64,linux/arm/v7
context: .
push: true
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}
tags: ${{ env.TEST_TAG }}
cache-from: type=local,src=/tmp/.buildx-cache-new
cache-to: type=local,dest=/tmp/.buildx-cache-new
- name: Docker Hub Description
uses: peter-evans/dockerhub-description@v4
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
repository: hanxi/xiaomusic
- name: Move cache to limit growth
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache

View File

@@ -38,7 +38,6 @@ jobs:
build-image:
runs-on: ubuntu-latest
#needs: release-pypi
# run unless event type is pull_request
if: github.event_name != 'pull_request'
steps:
@@ -56,6 +55,6 @@ jobs:
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
platforms: linux/amd64, linux/arm64, 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
View File

@@ -169,3 +169,4 @@ setting.json
.DS_Store
cache
tmp/
xiaomusic.log.txt

View File

@@ -1,3 +1,163 @@
## v0.3.56 (2024-12-07)
### Feat
- tag 信息支持写入到歌曲文件 see #266
- 开启gzip压缩
### Fix
- 播放失败设置重试次数10次解决设备失联后无限重试的问题
- 修复最近新增歌单问题
- 小程序码移动端布局兼容 (#293)
## v0.3.55 (2024-12-04)
### Fix
- 修复播放接口报错问题
## v0.3.54 (2024-12-04)
### Feat
- 新增最近新增歌单 close #273
### Fix
- 安卓低版本webview对audio的src为空值的报错 (#289)
- 修复M01语音播放问题X08C X08E X8F 型号默认采用型号兼容模式 see #30
## v0.3.53 (2024-12-03)
### Fix
- 解决播放接口修改后播放失败的问题
## v0.3.52 (2024-12-03)
### Fix
- 修复播放接口参数错误的问题
## v0.3.51 (2024-12-03)
### Fix
- 修复空配置启动失败问题 close #284
## v0.3.50 (2024-12-03)
### Feat
- 修改日志文件的默认值
- 新增修改tag缓存信息的接口 close #266
- 新增专用的播放歌曲和播放歌单接口,解决默认口令提示词被修改了导致后台失效的问题
- 统计设备型号
- 页面与设置中的HOST不一致时弹窗提醒 (#281)
- 未发现小爱设备时给予提示 (#278)
- 优化设置页面提示
### Fix
- 更新 yt-dlp ,解决 B 站下载问题 close #279
- 网页播放audio获取到错误url无法播放时提醒用户 (#280)
- input标签自闭合
### Refactor
- 调整设置页面
## v0.3.49 (2024-11-28)
### Feat
- 临时文件目录支持配置 #99
- 新增单曲播放和顺序播放功能 close #277
- 设置播放类型支持配置语音提示词,定时任务支持设置播放类型
### Fix
- 修复中文数字转换函数对'十、十一'等数字的处理 (#275)
## v0.3.48 (2024-11-20)
### Feat
- 支持替换默认口令,而不是追加 close #259
- 新增自定义个歌单接口 #242
### Fix
- 锁定 PWA 应用旋转方向
## v0.3.47 (2024-11-14)
### Feat
- 支持 PWA 应用安装
- 新增模糊匹配测试用例
### Fix
- 修复 PWA 应用有密码时报错的问题
- 修复播放顺序没有按数字排序的问题 close #249
## v0.3.46 (2024-11-08)
### Feat
- 升级依赖库
### Fix
- 添加依赖库 requests
### Refactor
- 依赖库已经支持分段获取静态文件,重构代码
## v0.3.45 (2024-11-08)
### Feat
- 定时任务支持设置音量
- 播放歌单口令支持配置
### Fix
- 修复定时任务报错问题
## v0.3.44 (2024-11-01)
### Feat
- 日志时间里加上日期
### Fix
- 修复搜索失败的问题
## v0.3.43 (2024-10-30)
### Feat
- 播放列表可以删除当前歌曲(!危险操作,请在设置中心开启相关功能) (#250)
- 插件自定义口令支持获取语音输入内容 #105
### Fix
- 修复谷歌统计导致的卡顿问题
- 解决挂载网盘卡死的问题
## v0.3.42 (2024-10-24)
### Fix
- 尝试修复缺少 libtiff.so.6 文件的问题 #244
- 修复默认主题播放歌曲输入框空的情况
- 尝试修复停止后自动播放的问题
## v0.3.41 (2024-10-17)
### Feat

View File

@@ -1,4 +1,4 @@
FROM python:3.10 AS builder
FROM hanxi/xiaomusic:builder AS builder
ENV DEBIAN_FRONTEND=noninteractive
RUN pip install -U pdm
ENV PDM_CHECK_UPDATE=false
@@ -8,16 +8,13 @@ COPY xiaomusic/ ./xiaomusic/
COPY plugins/ ./plugins/
COPY xiaomusic.py .
RUN pdm install --prod --no-editable
COPY install_dependencies.sh .
RUN bash install_dependencies.sh
FROM python:3.10-slim
FROM hanxi/xiaomusic:runtime
WORKDIR /app
COPY --from=builder /app/.venv /app/.venv
COPY --from=builder /app/ffmpeg /app/ffmpeg
COPY xiaomusic/ ./xiaomusic/
COPY plugins/ ./plugins/
COPY xiaomusic.py .
COPY --from=builder /app/xiaomusic/ ./xiaomusic/
COPY --from=builder /app/plugins/ ./plugins/
COPY --from=builder /app/xiaomusic.py .
ENV XIAOMUSIC_HOSTNAME=192.168.2.5
ENV XIAOMUSIC_PORT=8090
VOLUME /app/conf

11
Dockerfile.builder Normal file
View File

@@ -0,0 +1,11 @@
FROM python:3.10
ENV DEBIAN_FRONTEND=noninteractive
RUN pip install -U pdm
ENV PDM_CHECK_UPDATE=false
WORKDIR /app
COPY pyproject.toml README.md .
COPY xiaomusic/ ./xiaomusic/
COPY plugins/ ./plugins/
COPY xiaomusic.py .
RUN pdm install --prod --no-editable

14
Dockerfile.runtime Normal file
View File

@@ -0,0 +1,14 @@
FROM python:3.10-slim
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y \
wget \
xz-utils \
libtiff6 \
libopenjp2-7 \
libxcb1 \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /app
COPY install_dependencies.sh .
RUN bash install_dependencies.sh

View File

@@ -6,7 +6,8 @@
[![PyPI - Downloads](https://img.shields.io/pypi/dm/xiaomusic)](https://pypi.org/project/xiaomusic/)
[![Python Version from PEP 621 TOML](https://img.shields.io/python/required-version-toml?tomlFilePath=https%3A%2F%2Fraw.githubusercontent.com%2Fhanxi%2Fxiaomusic%2Fmain%2Fpyproject.toml)](https://pypi.org/project/xiaomusic/)
[![GitHub Release](https://img.shields.io/github/v/release/hanxi/xiaomusic)](https://github.com/hanxi/xiaomusic/releases)
[![Visitors](https://api.visitorbadge.io/api/daily?path=hanxi%2Fxiaomusic&label=daily%20visitor&countColor=%232ccce4&style=flat)](https://visitorbadge.io/status?path=hanxi%2Fxiaomusic)
[![Visitors](https://api.visitorbadge.io/api/visitors?path=hanxi%2Fxiaomusic&label=total%20visitor&countColor=%232ccce4&style=flat)](https://visitorbadge.io/status?path=hanxi%2Fxiaomusic)
使用小爱音箱播放音乐,音乐使用 yt-dlp 下载。
@@ -24,6 +25,12 @@
docker run -p 8090:8090 -v /xiaomusic/music:/app/music -v /xiaomusic/conf:/app/conf hanxi/xiaomusic
```
🔥 国内:
```bash
docker run -p 8090:8090 -v /xiaomusic/music:/app/music -v /xiaomusic/conf:/app/conf m.daocloud.io/docker.io/hanxi/xiaomusic
```
对应的 docker compose 配置如下:
```yaml
@@ -39,6 +46,21 @@ services:
- /xiaomusic/conf:/app/conf
```
🔥 国内:
```yaml
services:
xiaomusic:
image: m.daocloud.io/docker.io/hanxi/xiaomusic
container_name: xiaomusic
restart: unless-stopped
ports:
- 8090:8090
volumes:
- /xiaomusic/music:/app/music
- /xiaomusic/conf:/app/conf
```
其中 conf 目录为配置文件存放目录music 目录为音乐存放目录,建议分开配置为不同的目录。
> [!NOTE]
@@ -51,6 +73,29 @@ docker 和 docker compose 二选一即可,启动成功后,在 web 页面可
### 🔥 修改默认8090端口映射
#### 方法1 不修改监听端口 8090
【监听端口】保持为默认的 8090 不变,把【外网访问端口】改为 5678 。
```yaml
services:
xiaomusic:
image: hanxi/xiaomusic
container_name: xiaomusic
restart: unless-stopped
ports:
- 5678:8090
volumes:
- /xiaomusic/music:/app/music
- /xiaomusic/conf:/app/conf
environment:
XIAOMUSIC_PUBLIC_PORT: 5678
```
XIAOMUSIC_PUBLIC_PORT 对应后台设置里的【外网访问端口】,修改后可以不用重启。
#### 方法2 修改监听端口 8090 为 5678
如果需要修改 8090 端口为其他端口,比如 5678需要这样配3个数字都需要是 5678 。见 <https://github.com/hanxi/xiaomusic/issues/19>
```yaml
@@ -73,7 +118,7 @@ services:
遇到问题可以去 web 设置页面底部点击【下载日志文件】按钮,然后搜索一下日志文件内容确保里面没有账号密码信息后(有就删除这些敏感信息),然后在提 issues 反馈问题时把下载的日志文件带上。
> [!IMPORTANT]
> XIAOMUSIC_PORT 也可以在后台配置,对应的是监听端口。
> XIAOMUSIC_PORT 也可以在后台配置,对应的是监听端口,修改后记得重启
### 🤐 支持语音口令
@@ -150,8 +195,7 @@ pdm run xiaomusic.py
提交前请执行
```
pdm fmt
pdm lint --fix
pdm lintfmt
```
用于检查代码和格式化代码。
@@ -162,6 +206,14 @@ pdm lint --fix
docker build -t xiaomusic .
```
### 技术栈
- 后端代码使用 Python 语言编写。
- HTTP 服务使用的是 FastAPI 框架,~~早期版本使用的是 Flask~~。
- 使用了 Docker ,在 NAS 上安装更方便。
- 默认的前端主题使用了 jQuery 。
## 已测试支持的设备
| 型号 | 名称 |
@@ -180,7 +232,8 @@ docker build -t xiaomusic .
| L05C | [小米小爱音箱Play 增强版](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.l05c) |
| L09A | [小米音箱Art](https://home.mi.com/webapp/content/baike/product/index.html?model=xiaomi.wifispeaker.l09a) |
| LX04 X10A X08A | 已经支持的触屏版 |
| M01/XMYX01JY | 小米小爱音箱HD (获取对话记录的接口比较特殊) |
| X08C X08E X8F | 需要设置【型号兼容模式】选项为 true |
| M01/XMYX01JY | 小米小爱音箱HD 需要设置【特殊型号获取对话记录】选项为 true 才能语音播放|
型号与产品名称对照可以在这里查询 <https://home.miot-spec.com/s/xiaomi.wifispeaker>
@@ -279,6 +332,7 @@ docker build -t xiaomusic .
- [微信小程序: XIAO晓音](https://github.com/F-loat/xiaoplayer)
- [pure 主题 xiaomusicUI](https://github.com/52fisher/xiaomusicUI)
- [移动端的播放器主题](https://github.com/52fisher/XMusicPlayer)
- [一个第三方的主题](https://github.com/DarrenWen/xiaomusicui)
- 所有帮忙调试和测试的朋友
- 所有反馈问题和建议的朋友

View File

@@ -16,6 +16,7 @@ install_from_github() {
mkdir -p ffmpeg/bin
mv $pkg/bin/ffmpeg ffmpeg/bin/
mv $pkg/bin/ffprobe ffmpeg/bin/
rm -rf $pkg $pkg.tar.xz
}
install_from_ffmpeg() {
@@ -26,6 +27,7 @@ install_from_ffmpeg() {
mkdir -p ffmpeg/bin
mv $pkg/*/ffmpeg ffmpeg/bin/
mv $pkg/*/ffprobe ffmpeg/bin/
rm -rf $pkg $pkg.tar.xz
}
# 基于架构执行不同的操作

594
pdm.lock generated
View File

@@ -5,7 +5,7 @@
groups = ["default", "dev", "lint"]
strategy = ["inherit_metadata"]
lock_version = "4.5.0"
content_hash = "sha256:c7b4db9b4f139c1e6f1f2bd499d57c8f2246688fc5a39d675627d23920dc4403"
content_hash = "sha256:d22d4b03450cd369683d3ddf827359cd96541ee09e29bfa1fa666d72aa7d3ab0"
[[metadata.targets]]
requires_python = "==3.10.12"
@@ -39,23 +39,24 @@ files = [
[[package]]
name = "aiohttp"
version = "3.10.0"
requires_python = ">=3.8"
version = "3.11.9"
requires_python = ">=3.9"
summary = "Async http client/server framework (asyncio)"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"aiohappyeyeballs>=2.3.0",
"aiosignal>=1.1.2",
"async-timeout<5.0,>=4.0; python_version < \"3.11\"",
"async-timeout<6.0,>=4.0; python_version < \"3.11\"",
"attrs>=17.3.0",
"frozenlist>=1.1.1",
"multidict<7.0,>=4.5",
"yarl<2.0,>=1.0",
"propcache>=0.2.0",
"yarl<2.0,>=1.17.0",
]
files = [
{file = "aiohttp-3.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06ef0135d7ab7fb0284342fbbf8e8ddf73b7fee8ecc55f5c3a3d0a6b765e6d8b"},
{file = "aiohttp-3.10.0.tar.gz", hash = "sha256:e8dd7da2609303e3574c95b0ec9f1fd49647ef29b94701a2862cceae76382e1d"},
{file = "aiohttp-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39625703540feb50b6b7f938b3856d1f4886d2e585d88274e62b1bd273fae09b"},
{file = "aiohttp-3.11.9.tar.gz", hash = "sha256:a9266644064779840feec0e34f10a89b3ff1d2d6b751fe90017abcad1864fa7c"},
]
[[package]]
@@ -108,20 +109,18 @@ files = [
[[package]]
name = "apscheduler"
version = "3.10.4"
requires_python = ">=3.6"
version = "3.11.0"
requires_python = ">=3.8"
summary = "In-process task scheduler with Cron-like capabilities"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"importlib-metadata>=3.6.0; python_version < \"3.8\"",
"pytz",
"six>=1.4.0",
"tzlocal!=3.*,>=2.0",
"backports-zoneinfo; python_version < \"3.9\"",
"tzlocal>=3.0",
]
files = [
{file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"},
{file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"},
{file = "APScheduler-3.11.0-py3-none-any.whl", hash = "sha256:fc134ca32e50f5eadcc4938e3a4545ab19131435e851abb40b34d63d5141c6da"},
{file = "apscheduler-3.11.0.tar.gz", hash = "sha256:4c622d250b0955a65d5d0eb91c33e6d43fd879834bf541e0a18661ae60460133"},
]
[[package]]
@@ -173,55 +172,20 @@ summary = "Python bindings for the Brotli compression library"
groups = ["default"]
marker = "implementation_name == \"cpython\" and python_full_version == \"3.10.12\""
files = [
{file = "Brotli-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752"},
{file = "Brotli-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9"},
{file = "Brotli-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3"},
{file = "Brotli-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d"},
{file = "Brotli-1.1.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e"},
{file = "Brotli-1.1.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da"},
{file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80"},
{file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d"},
{file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0"},
{file = "Brotli-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e"},
{file = "Brotli-1.1.0-cp310-cp310-win32.whl", hash = "sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2"},
{file = "Brotli-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128"},
{file = "Brotli-1.1.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc"},
{file = "Brotli-1.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6"},
{file = "Brotli-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd"},
{file = "Brotli-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf"},
{file = "Brotli-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61"},
{file = "Brotli-1.1.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327"},
{file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd"},
{file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9"},
{file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265"},
{file = "Brotli-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8"},
{file = "Brotli-1.1.0-cp311-cp311-win32.whl", hash = "sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50"},
{file = "Brotli-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1"},
{file = "Brotli-1.1.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409"},
{file = "Brotli-1.1.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2"},
{file = "Brotli-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451"},
{file = "Brotli-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91"},
{file = "Brotli-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408"},
{file = "Brotli-1.1.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0"},
{file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc"},
{file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180"},
{file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248"},
{file = "Brotli-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966"},
{file = "Brotli-1.1.0-cp312-cp312-win32.whl", hash = "sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0"},
{file = "Brotli-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951"},
{file = "Brotli-1.1.0.tar.gz", hash = "sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724"},
]
[[package]]
name = "certifi"
version = "2024.7.4"
version = "2024.8.30"
requires_python = ">=3.6"
summary = "Python package for providing Mozilla's CA Bundle."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
{file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"},
{file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"},
]
[[package]]
@@ -311,13 +275,13 @@ files = [
[[package]]
name = "commitizen"
version = "3.28.0"
requires_python = ">=3.8"
version = "4.0.0"
requires_python = ">=3.9"
summary = "Python commitizen client tool"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"argcomplete<3.5,>=1.12.1",
"argcomplete<3.6,>=1.12.1",
"charset-normalizer<4,>=2.1.0",
"colorama<0.5.0,>=0.4.1",
"decli<0.7.0,>=0.6.0",
@@ -328,11 +292,11 @@ dependencies = [
"questionary<3.0,>=2.0",
"termcolor<3,>=1.1",
"tomlkit<1.0.0,>=0.5.3",
"typing-extensions<5.0.0,>=4.0.1; python_version < \"3.8\"",
"typing-extensions<5.0.0,>=4.0.1; python_version < \"3.11\"",
]
files = [
{file = "commitizen-3.28.0-py3-none-any.whl", hash = "sha256:372dba10bb082be0e571cfa9ac0946f4333c3f4b2e242fbe32ae2f2afea143e4"},
{file = "commitizen-3.28.0.tar.gz", hash = "sha256:de3a90b3246233260649e423963cd702d56a3b499ea02886a6412ebfb76f9462"},
{file = "commitizen-4.0.0-py3-none-any.whl", hash = "sha256:52873ee589a64cf77fc55570dbd3f987c6ffcd33132d179eb625c4d06ae935f7"},
{file = "commitizen-4.0.0.tar.gz", hash = "sha256:16aff27e01b43015eab1c74eabbca3e284b4988dd1b146a0963282db241dc2c0"},
]
[[package]]
@@ -347,34 +311,6 @@ files = [
{file = "decli-0.6.2.tar.gz", hash = "sha256:36f71eb55fd0093895efb4f416ec32b7f6e00147dda448e3365cf73ceab42d6f"},
]
[[package]]
name = "dnspython"
version = "2.6.1"
requires_python = ">=3.8"
summary = "DNS toolkit"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"},
{file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"},
]
[[package]]
name = "email-validator"
version = "2.2.0"
requires_python = ">=3.8"
summary = "A robust email address syntax and deliverability validation library."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"dnspython>=2.0.0",
"idna>=2.0.0",
]
files = [
{file = "email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631"},
{file = "email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7"},
]
[[package]]
name = "exceptiongroup"
version = "1.2.2"
@@ -389,40 +325,19 @@ files = [
[[package]]
name = "fastapi"
version = "0.111.1"
version = "0.115.5"
requires_python = ">=3.8"
summary = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"email-validator>=2.0.0",
"fastapi-cli>=0.0.2",
"httpx>=0.23.0",
"jinja2>=2.11.2",
"pydantic!=1.8,!=1.8.1,!=2.0.0,!=2.0.1,!=2.1.0,<3.0.0,>=1.7.4",
"python-multipart>=0.0.7",
"starlette<0.38.0,>=0.37.2",
"starlette<0.42.0,>=0.40.0",
"typing-extensions>=4.8.0",
"uvicorn[standard]>=0.12.0",
]
files = [
{file = "fastapi-0.111.1-py3-none-any.whl", hash = "sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf"},
{file = "fastapi-0.111.1.tar.gz", hash = "sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413"},
]
[[package]]
name = "fastapi-cli"
version = "0.0.4"
requires_python = ">=3.8"
summary = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"typer>=0.12.3",
]
files = [
{file = "fastapi_cli-0.0.4-py3-none-any.whl", hash = "sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809"},
{file = "fastapi_cli-0.0.4.tar.gz", hash = "sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32"},
{file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"},
{file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"},
]
[[package]]
@@ -509,73 +424,6 @@ files = [
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
]
[[package]]
name = "httpcore"
version = "1.0.5"
requires_python = ">=3.8"
summary = "A minimal low-level HTTP client."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"certifi",
"h11<0.15,>=0.13",
]
files = [
{file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"},
{file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"},
]
[[package]]
name = "httptools"
version = "0.6.1"
requires_python = ">=3.8.0"
summary = "A collection of framework independent HTTP protocol utils."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"},
{file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"},
{file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"},
{file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"},
{file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"},
{file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"},
{file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"},
{file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"},
{file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"},
{file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"},
{file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"},
{file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"},
{file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"},
{file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"},
{file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"},
{file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"},
{file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"},
{file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"},
{file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"},
{file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"},
{file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"},
{file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"},
]
[[package]]
name = "httpx"
version = "0.27.0"
requires_python = ">=3.8"
summary = "The next generation HTTP client."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"anyio",
"certifi",
"httpcore==1.*",
"idna",
"sniffio",
]
files = [
{file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"},
{file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"},
]
[[package]]
name = "idna"
version = "3.7"
@@ -593,7 +441,7 @@ name = "jinja2"
version = "3.1.4"
requires_python = ">=3.7"
summary = "A very fast and expressive template engine."
groups = ["default", "dev"]
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"MarkupSafe>=2.0",
@@ -623,7 +471,7 @@ name = "markupsafe"
version = "2.1.5"
requires_python = ">=3.7"
summary = "Safely add untrusted strings to HTML/XML markup."
groups = ["default", "dev"]
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
@@ -673,7 +521,7 @@ files = [
[[package]]
name = "miservice-fork"
version = "2.7.0"
version = "2.7.1"
requires_python = ">=3.8"
summary = "XiaoMi Cloud Service fork from https://github.com/Yonsm/MiService"
groups = ["default"]
@@ -684,8 +532,8 @@ dependencies = [
"rich",
]
files = [
{file = "miservice_fork-2.7.0-py3-none-any.whl", hash = "sha256:8e2c91ebe1fc4b3c63b01cbf1818e5d5833d024fd3a8311970d649ad2d49d6e6"},
{file = "miservice_fork-2.7.0.tar.gz", hash = "sha256:8e87ef6d89adceaf3f7a98242cdae1c9135498d77f2c743ec3871d2e42bcbab8"},
{file = "miservice_fork-2.7.1-py3-none-any.whl", hash = "sha256:0f908de6db2c77bb1a27b217cf3ab99835b408804cda5f7d16329e8e60948d13"},
{file = "miservice_fork-2.7.1.tar.gz", hash = "sha256:a10c82e353dcc69183e50ce00a50cb602d9dc5992d83989b4a259d4830b48ea1"},
]
[[package]]
@@ -782,15 +630,15 @@ files = [
[[package]]
name = "pillow"
version = "10.4.0"
requires_python = ">=3.8"
version = "11.0.0"
requires_python = ">=3.9"
summary = "Python Imaging Library (Fork)"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "pillow-10.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4d49b85c4348ea0b31ea63bc75a9f3857869174e2bf17e7aba02945cd218e6f"},
{file = "pillow-10.4.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:a985e028fc183bf12a77a8bbf36318db4238a3ded7fa9df1b9a133f1cb79f8fc"},
{file = "pillow-10.4.0.tar.gz", hash = "sha256:166c1cd4d24309b30d61f79f4a9114b7b2313d7450912277855ff5dfd7cd4a06"},
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88a58d8ac0cc0e7f3a014509f0455248a76629ca9b604eca7dc5927cc593c5e9"},
{file = "pillow-11.0.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:1a61b54f87ab5786b8479f81c4b11f4d61702830354520837f8cc791ebba0f5f"},
{file = "pillow-11.0.0.tar.gz", hash = "sha256:72bacbaf24ac003fea9bff9837d1eedb6088758d41e100c1552930151f677739"},
]
[[package]]
@@ -808,29 +656,29 @@ files = [
{file = "prompt_toolkit-3.0.36.tar.gz", hash = "sha256:3e163f254bef5a03b146397d7c1963bd3e2812f0964bb9a24e6ec761fd28db63"},
]
[[package]]
name = "propcache"
version = "0.2.0"
requires_python = ">=3.8"
summary = "Accelerated property cache"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "propcache-0.2.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3dfafb44f7bb35c0c06eda6b2ab4bfd58f02729e7c4045e179f9a861b07c9850"},
{file = "propcache-0.2.0-py3-none-any.whl", hash = "sha256:2ccc28197af5313706511fab3a8b66dcd6da067a1331372c82ea1cb74285e036"},
{file = "propcache-0.2.0.tar.gz", hash = "sha256:df81779732feb9d01e5d513fad0122efb3d53bbc75f61b2a4f29a020bc985e70"},
]
[[package]]
name = "pycryptodomex"
version = "3.20.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "3.21.0"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7"
summary = "Cryptographic library for Python"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c"},
{file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3"},
{file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623"},
{file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4"},
{file = "pycryptodomex-3.20.0-cp35-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5"},
{file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed"},
{file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_i686.whl", hash = "sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7"},
{file = "pycryptodomex-3.20.0-cp35-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43"},
{file = "pycryptodomex-3.20.0-cp35-abi3-win32.whl", hash = "sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e"},
{file = "pycryptodomex-3.20.0-cp35-abi3-win_amd64.whl", hash = "sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc"},
{file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b"},
{file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea"},
{file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781"},
{file = "pycryptodomex-3.20.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499"},
{file = "pycryptodomex-3.20.0.tar.gz", hash = "sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e"},
{file = "pycryptodomex-3.21.0-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9aa0cf13a1a1128b3e964dc667e5fe5c6235f7d7cfb0277213f0e2a783837cc2"},
{file = "pycryptodomex-3.21.0.tar.gz", hash = "sha256:222d0bd05381dd25c32dd6065c071ebf084212ab79bab4599ba9e6a3e0009e6c"},
]
[[package]]
@@ -933,39 +781,16 @@ files = [
{file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
]
[[package]]
name = "python-dotenv"
version = "1.0.1"
requires_python = ">=3.8"
summary = "Read key-value pairs from a .env file and set them as environment variables"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
]
[[package]]
name = "python-multipart"
version = "0.0.12"
version = "0.0.19"
requires_python = ">=3.8"
summary = "A streaming multipart parser for Python"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "python_multipart-0.0.12-py3-none-any.whl", hash = "sha256:43dcf96cf65888a9cd3423544dd0d75ac10f7aa0c3c28a175bbcd00c9ce1aebf"},
{file = "python_multipart-0.0.12.tar.gz", hash = "sha256:045e1f98d719c1ce085ed7f7e1ef9d8ccc8c02ba02b5566d5f7521410ced58cb"},
]
[[package]]
name = "pytz"
version = "2024.2"
summary = "World timezone definitions, modern and historical"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
{file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
{file = "python_multipart-0.0.19-py3-none-any.whl", hash = "sha256:f8d5b0b9c618575bf9df01c684ded1d94a338839bdd8223838afacfb4bb2082d"},
{file = "python_multipart-0.0.19.tar.gz", hash = "sha256:905502ef39050557b7a6af411f454bc19526529ca46ae6831508438890ce12cc"},
]
[[package]]
@@ -973,7 +798,7 @@ name = "pyyaml"
version = "6.0.1"
requires_python = ">=3.6"
summary = "YAML parser and emitter for Python"
groups = ["default", "dev"]
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
@@ -1054,38 +879,14 @@ files = [
[[package]]
name = "ruff"
version = "0.5.5"
version = "0.8.1"
requires_python = ">=3.7"
summary = "An extremely fast Python linter and code formatter, written in Rust."
groups = ["lint"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091"},
{file = "ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a"},
]
[[package]]
name = "shellingham"
version = "1.5.4"
requires_python = ">=3.7"
summary = "Tool to Detect Surrounding Shell"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
]
[[package]]
name = "six"
version = "1.16.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
summary = "Python 2 and 3 compatibility utilities"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
{file = "ruff-0.8.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b22346f845fec132aa39cd29acb94451d030c10874408dbf776af3aaeb53284c"},
{file = "ruff-0.8.1.tar.gz", hash = "sha256:3583db9a6450364ed5ca3f3b4225958b24f78178908d5c4bc0f46251ccca898f"},
]
[[package]]
@@ -1102,7 +903,7 @@ files = [
[[package]]
name = "starlette"
version = "0.37.2"
version = "0.41.3"
requires_python = ">=3.8"
summary = "The little ASGI library that shines."
groups = ["default"]
@@ -1112,8 +913,8 @@ dependencies = [
"typing-extensions>=3.10.0; python_version < \"3.10\"",
]
files = [
{file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"},
{file = "starlette-0.37.2.tar.gz", hash = "sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823"},
{file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"},
{file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"},
]
[[package]]
@@ -1140,30 +941,12 @@ files = [
{file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"},
]
[[package]]
name = "typer"
version = "0.12.3"
requires_python = ">=3.7"
summary = "Typer, build great CLIs. Easy to code. Based on Python type hints."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"click>=8.0.0",
"rich>=10.11.0",
"shellingham>=1.3.0",
"typing-extensions>=3.7.4.3",
]
files = [
{file = "typer-0.12.3-py3-none-any.whl", hash = "sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914"},
{file = "typer-0.12.3.tar.gz", hash = "sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482"},
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
requires_python = ">=3.8"
summary = "Backported and Experimental Type Hints for Python 3.8+"
groups = ["default"]
groups = ["default", "dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
@@ -1188,19 +971,19 @@ files = [
[[package]]
name = "urllib3"
version = "2.2.2"
version = "2.2.3"
requires_python = ">=3.8"
summary = "HTTP library with thread-safe connection pooling, file post, and more."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
{file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
]
[[package]]
name = "uvicorn"
version = "0.30.4"
version = "0.32.1"
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
groups = ["default"]
@@ -1211,116 +994,8 @@ dependencies = [
"typing-extensions>=4.0; python_version < \"3.11\"",
]
files = [
{file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"},
{file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"},
]
[[package]]
name = "uvicorn"
version = "0.30.4"
extras = ["standard"]
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"colorama>=0.4; sys_platform == \"win32\"",
"httptools>=0.5.0",
"python-dotenv>=0.13",
"pyyaml>=5.1",
"uvicorn==0.30.4",
"uvloop!=0.15.0,!=0.15.1,>=0.14.0; (sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\"",
"watchfiles>=0.13",
"websockets>=10.4",
]
files = [
{file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"},
{file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"},
]
[[package]]
name = "uvloop"
version = "0.19.0"
requires_python = ">=3.8.0"
summary = "Fast implementation of asyncio event loop on top of libuv"
groups = ["default"]
marker = "(sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\" and python_full_version == \"3.10.12\""
files = [
{file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"},
{file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"},
{file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"},
{file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"},
{file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"},
{file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"},
{file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"},
{file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"},
{file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"},
{file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"},
{file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"},
{file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"},
{file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"},
{file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"},
{file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"},
{file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"},
{file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"},
{file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"},
{file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"},
]
[[package]]
name = "watchfiles"
version = "0.22.0"
requires_python = ">=3.8"
summary = "Simple, modern and high performance file watching and code reload in python."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"anyio>=3.0.0",
]
files = [
{file = "watchfiles-0.22.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538"},
{file = "watchfiles-0.22.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e"},
{file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1"},
{file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a"},
{file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd"},
{file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb"},
{file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171"},
{file = "watchfiles-0.22.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71"},
{file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39"},
{file = "watchfiles-0.22.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848"},
{file = "watchfiles-0.22.0-cp310-none-win32.whl", hash = "sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797"},
{file = "watchfiles-0.22.0-cp310-none-win_amd64.whl", hash = "sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb"},
{file = "watchfiles-0.22.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96"},
{file = "watchfiles-0.22.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696"},
{file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249"},
{file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550"},
{file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c"},
{file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da"},
{file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1"},
{file = "watchfiles-0.22.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f"},
{file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d"},
{file = "watchfiles-0.22.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c"},
{file = "watchfiles-0.22.0-cp311-none-win32.whl", hash = "sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67"},
{file = "watchfiles-0.22.0-cp311-none-win_amd64.whl", hash = "sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1"},
{file = "watchfiles-0.22.0-cp311-none-win_arm64.whl", hash = "sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84"},
{file = "watchfiles-0.22.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a"},
{file = "watchfiles-0.22.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be"},
{file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2"},
{file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c"},
{file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232"},
{file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1"},
{file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6"},
{file = "watchfiles-0.22.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27"},
{file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b"},
{file = "watchfiles-0.22.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35"},
{file = "watchfiles-0.22.0-cp312-none-win32.whl", hash = "sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e"},
{file = "watchfiles-0.22.0-cp312-none-win_amd64.whl", hash = "sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e"},
{file = "watchfiles-0.22.0-cp312-none-win_arm64.whl", hash = "sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea"},
{file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68"},
{file = "watchfiles-0.22.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c"},
{file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab"},
{file = "watchfiles-0.22.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2"},
{file = "watchfiles-0.22.0.tar.gz", hash = "sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb"},
{file = "uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e"},
{file = "uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175"},
]
[[package]]
@@ -1339,120 +1014,52 @@ files = [
[[package]]
name = "websockets"
version = "12.0"
requires_python = ">=3.8"
version = "14.1"
requires_python = ">=3.9"
summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"},
{file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"},
{file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"},
{file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"},
{file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"},
{file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"},
{file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"},
{file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"},
{file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"},
{file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"},
{file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"},
{file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"},
{file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"},
{file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"},
{file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"},
{file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"},
{file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"},
{file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"},
{file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"},
{file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"},
{file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"},
{file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"},
{file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"},
{file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"},
{file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"},
{file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"},
{file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"},
{file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"},
{file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"},
{file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"},
{file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"},
{file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"},
{file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"},
{file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"},
{file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"},
{file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"},
{file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"},
{file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"},
{file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"},
{file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"},
{file = "websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199"},
{file = "websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e"},
{file = "websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8"},
]
[[package]]
name = "yarl"
version = "1.9.4"
requires_python = ">=3.7"
version = "1.17.1"
requires_python = ">=3.9"
summary = "Yet another URL library"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"idna>=2.0",
"multidict>=4.0",
"typing-extensions>=3.7.4; python_version < \"3.8\"",
"propcache>=0.2.0",
]
files = [
{file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"},
{file = "yarl-1.9.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2"},
{file = "yarl-1.9.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66"},
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234"},
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392"},
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551"},
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455"},
{file = "yarl-1.9.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c"},
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53"},
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385"},
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863"},
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b"},
{file = "yarl-1.9.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541"},
{file = "yarl-1.9.4-cp310-cp310-win32.whl", hash = "sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d"},
{file = "yarl-1.9.4-cp310-cp310-win_amd64.whl", hash = "sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b"},
{file = "yarl-1.9.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099"},
{file = "yarl-1.9.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c"},
{file = "yarl-1.9.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0"},
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525"},
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8"},
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9"},
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42"},
{file = "yarl-1.9.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe"},
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce"},
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9"},
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572"},
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958"},
{file = "yarl-1.9.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98"},
{file = "yarl-1.9.4-cp311-cp311-win32.whl", hash = "sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31"},
{file = "yarl-1.9.4-cp311-cp311-win_amd64.whl", hash = "sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1"},
{file = "yarl-1.9.4-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81"},
{file = "yarl-1.9.4-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142"},
{file = "yarl-1.9.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074"},
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129"},
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2"},
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78"},
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4"},
{file = "yarl-1.9.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0"},
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51"},
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff"},
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7"},
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc"},
{file = "yarl-1.9.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10"},
{file = "yarl-1.9.4-cp312-cp312-win32.whl", hash = "sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7"},
{file = "yarl-1.9.4-cp312-cp312-win_amd64.whl", hash = "sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984"},
{file = "yarl-1.9.4-py3-none-any.whl", hash = "sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad"},
{file = "yarl-1.9.4.tar.gz", hash = "sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf"},
{file = "yarl-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e844be8d536afa129366d9af76ed7cb8dfefec99f5f1c9e4f8ae542279a6dc3"},
{file = "yarl-1.17.1-py3-none-any.whl", hash = "sha256:f1790a4b1e8e8e028c391175433b9c8122c39b46e1663228158e61e6f915bf06"},
{file = "yarl-1.17.1.tar.gz", hash = "sha256:067a63fcfda82da6b198fa73079b1ca40b7c9b7994995b6ee38acda728b64d47"},
]
[[package]]
name = "yt-dlp"
version = "2024.8.1"
requires_python = ">=3.8"
version = "2024.12.1.232904.dev0"
requires_python = ">=3.9"
summary = "A feature-rich command-line audio/video downloader"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "yt_dlp-2024.12.1.232904.dev0-py3-none-any.whl", hash = "sha256:67c1fa0986662f2f26ba70789c79c6d04fda45eb530944872f4a47ef4f94047e"},
{file = "yt_dlp-2024.12.1.232904.dev0.tar.gz", hash = "sha256:4fcce6637e70bad7c63220e4dd69a3a6b8969cbc17c93bfe569940dd173c0548"},
]
[[package]]
name = "yt-dlp"
version = "2024.12.1.232904.dev0"
extras = ["default"]
requires_python = ">=3.9"
summary = "A feature-rich command-line audio/video downloader"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
@@ -1464,9 +1071,10 @@ dependencies = [
"pycryptodomex",
"requests<3,>=2.32.2",
"urllib3<3,>=1.26.17",
"websockets>=12.0",
"websockets>=13.0",
"yt-dlp==2024.12.1.232904.dev0",
]
files = [
{file = "yt_dlp-2024.8.1-py3-none-any.whl", hash = "sha256:d0d927038e30a05f6eab26ff6189628456ea21bb159a3d9dc2e855eef2810eac"},
{file = "yt_dlp-2024.8.1.tar.gz", hash = "sha256:4318aa523694611562f01419c8d526b662a72df34ef8ba454016b34c8366c158"},
{file = "yt_dlp-2024.12.1.232904.dev0-py3-none-any.whl", hash = "sha256:67c1fa0986662f2f26ba70789c79c6d04fda45eb530944872f4a47ef4f94047e"},
{file = "yt_dlp-2024.12.1.232904.dev0.tar.gz", hash = "sha256:4fcce6637e70bad7c63220e4dd69a3a6b8969cbc17c93bfe569940dd173c0548"},
]

View File

@@ -3,3 +3,7 @@ async def code1(arg1):
log.info(f"code1:{arg1}")
did = xiaomusic._cur_did
await xiaomusic.do_tts(did, "你好,我是自定义的测试口令")
last_record = xiaomusic.last_record
query = last_record.get("query", "").strip()
await xiaomusic.do_tts(did, f"你说的是: {query}")

View File

@@ -1,6 +1,6 @@
[project]
name = "xiaomusic"
version = "0.3.41"
version = "0.3.56"
description = "Play Music with xiaomi AI speaker"
authors = [
{name = "涵曦", email = "im.hanxi@gmail.com"},
@@ -9,9 +9,9 @@ dependencies = [
"aiohttp>=3.8.6",
"miservice-fork>=2.7.0",
"mutagen>=1.47.0",
"yt-dlp>=2024.07.01",
"yt-dlp[default]>=2024.12.1.232904.dev0",
"uvicorn>=0.30.1",
"fastapi>=0.111.0",
"fastapi>=0.115.4",
"starlette>=0.37.2",
"aiofiles>=24.1.0",
"ga4mp>=2.0.4",
@@ -19,8 +19,9 @@ dependencies = [
"opencc-python-reimplemented==0.1.7",
"pillow>=10.4.0",
"python-multipart>=0.0.12",
"requests>=2.32.3",
]
requires-python = ">=3.10,<3.12"
requires-python = ">=3.10,<=3.12"
readme = "README.md"
license = {text = "MIT"}

33
test/test_difflib.py Normal file
View File

@@ -0,0 +1,33 @@
import difflib
from xiaomusic.utils import (
find_best_match,
keyword_detection,
)
if __name__ == "__main__":
user_input = "八年的爱"
s1 = "冰冰超人 - 八年的爱新版"
s2 = "冰冰超人 - 八年的爱"
r1 = difflib.SequenceMatcher(None, s1, user_input).ratio()
r2 = difflib.SequenceMatcher(None, s2, user_input).ratio()
print(s1, r1)
print(s2, r2)
s3 = "其他"
str_list = [s2, s1, s3]
matches, remains = keyword_detection(user_input, str_list, n=10)
print(matches, remains)
extra_search_index = {}
extra_search_index["1"] = s1
extra_search_index["2"] = s2
extra_search_index["3"] = s3
real_names = find_best_match(
user_input,
str_list,
cutoff=0.4,
n=100,
extra_search_index=extra_search_index,
)
print(real_names)

View File

@@ -36,8 +36,7 @@ async def main(directory):
# await test_one_music(file)
pass
await test_one_music("./music/4.mp3")
# await test_one_music("./music/4 In Love - 一千零一个愿.mp3")
await test_one_music("music/4 In Love - 一千零一个愿望.mp3")
# await test_one_music("./music/程响-人间烟火.flac")

View File

@@ -1 +1 @@
__version__ = "0.3.41"
__version__ = "0.3.56"

View File

@@ -11,7 +11,6 @@ class Analytics:
self.gtag = None
self.current_date = None
self.log = log
self.task = None
self.init()
def init(self):
@@ -30,10 +29,8 @@ class Analytics:
async def run_with_cancel(self, func, *args, **kwargs):
try:
if self.task:
self.log.warning(f"analytics run_with_cancel old : {self.task}")
self.task.cancel()
self.task = asyncio.create_task(func(*args, **kwargs))
asyncio.ensure_future(asyncio.to_thread(func, *args, **kwargs))
self.log.info("analytics run_with_cancel success")
except Exception as e:
self.log.warning(f"analytics run_with_cancel failed {e}")
return None
@@ -45,7 +42,7 @@ class Analytics:
self.log.warning(f"analytics send_startup_event failed {e}")
self.init()
async def _send_startup_event(self):
def _send_startup_event(self):
event = self.gtag.create_new_event(name="startup")
event.set_event_param(name="version", value=__version__)
event_list = [event]
@@ -58,7 +55,7 @@ class Analytics:
self.log.warning(f"analytics send_daily_event failed {e}")
self.init()
async def _send_daily_event(self):
def _send_daily_event(self):
current_date = datetime.now().strftime("%Y-%m-%d")
if self.current_date == current_date:
return
@@ -70,17 +67,18 @@ class Analytics:
self.gtag.send(events=event_list)
self.current_date = current_date
async def send_play_event(self, name, sec):
async def send_play_event(self, name, sec, hardware):
try:
await self.run_with_cancel(self._send_play_event, name, sec)
await self.run_with_cancel(self._send_play_event, name, sec, hardware)
except Exception as e:
self.log.warning(f"analytics send_play_event failed {e}")
self.init()
async def _send_play_event(self, name, sec):
def _send_play_event(self, name, sec, hardware):
event = self.gtag.create_new_event(name="play")
event.set_event_param(name="version", value=__version__)
event.set_event_param(name="music", value=name)
event.set_event_param(name="sec", value=sec)
event.set_event_param(name="hardware", value=hardware)
event_list = [event]
self.gtag.send(events=event_list)

View File

@@ -6,22 +6,27 @@ import os
from dataclasses import asdict, dataclass, field
from typing import get_type_hints
from xiaomusic.const import (
PLAY_TYPE_ALL,
PLAY_TYPE_ONE,
PLAY_TYPE_RND,
PLAY_TYPE_SEQ,
PLAY_TYPE_SIN,
)
from xiaomusic.utils import validate_proxy
# 默认口令
def default_key_word_dict():
return {
"播放歌曲": "play",
"播放本地歌曲": "playlocal",
"关机": "stop",
"下一首": "play_next",
"上一首": "play_prev",
"单曲循环": "set_play_type_one",
"全部循环": "set_play_type_all",
"随机播放": "set_random_play",
"随机播放": "set_play_type_rnd",
"单曲播放": "set_play_type_sin",
"顺序播放": "set_play_type_seq",
"分钟后关机": "stop_after_minute",
"播放列表": "play_music_list",
"刷新列表": "gen_music_list",
"加入收藏": "add_to_favorites",
"收藏歌曲": "add_to_favorites",
@@ -47,12 +52,13 @@ KEY_WORD_ARG_BEFORE_DICT = {
def default_key_match_order():
return [
"分钟后关机",
"播放歌曲",
"下一首",
"上一首",
"单曲循环",
"全部循环",
"随机播放",
"单曲播放",
"顺序播放",
"关机",
"刷新列表",
"播放列表第",
@@ -82,9 +88,8 @@ class Config:
miio_tts_command: str = os.getenv("MIIO_TTS_CMD", "")
cookie: str = ""
verbose: bool = os.getenv("XIAOMUSIC_VERBOSE", "").lower() == "true"
music_path: str = os.getenv(
"XIAOMUSIC_MUSIC_PATH", "music"
) # 只能是music目录下的子目录
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
temp_path: str = os.getenv("XIAOMUSIC_TEMP_PATH", "music/tmp")
download_path: str = os.getenv("XIAOMUSIC_DOWNLOAD_PATH", "music/download")
conf_path: str = os.getenv("XIAOMUSIC_CONF_PATH", "conf")
cache_dir: str = os.getenv("XIAOMUSIC_CACHE_DIR", "cache")
@@ -98,7 +103,7 @@ class Config:
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
active_cmd: str = os.getenv(
"XIAOMUSIC_ACTIVE_CMD",
"play,set_random_play,playlocal,play_music_list,play_music_list_index,stop_after_minute,stop",
"play,set_play_type_rnd,playlocal,play_music_list,play_music_list_index,stop_after_minute,stop",
)
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir,tmp")
music_path_depth: int = int(os.getenv("XIAOMUSIC_MUSIC_PATH_DEPTH", "10"))
@@ -122,7 +127,7 @@ class Config:
"XIAOMUSIC_USE_MUSIC_AUDIO_ID", "1582971365183456177"
)
use_music_id: str = os.getenv("XIAOMUSIC_USE_MUSIC_ID", "355454500")
log_file: str = os.getenv("XIAOMUSIC_LOG_FILE", "/tmp/xiaomusic.txt")
log_file: str = os.getenv("XIAOMUSIC_LOG_FILE", "xiaomusic.log.txt")
# 模糊搜索匹配的最低相似度阈值
fuzzy_match_cutoff: float = float(os.getenv("XIAOMUSIC_FUZZY_MATCH_CUTOFF", "0.6"))
# 开启模糊搜索
@@ -137,6 +142,9 @@ class Config:
)
keywords_play: str = os.getenv("XIAOMUSIC_KEYWORDS_PLAY", "播放歌曲,放歌曲")
keywords_stop: str = os.getenv("XIAOMUSIC_KEYWORDS_STOP", "关机,暂停,停止,停止播放")
keywords_playlist: str = os.getenv(
"XIAOMUSIC_KEYWORDS_PLAYLIST", "播放列表,播放歌单"
)
user_key_word_dict: dict[str, str] = field(
default_factory=default_user_key_word_dict
)
@@ -160,9 +168,30 @@ class Config:
enable_yt_dlp_cookies: bool = (
os.getenv("XIAOMUSIC_ENABLE_YT_DLP_COOKIES", "false").lower() == "true"
)
enable_save_tag: bool = (
os.getenv("XIAOMUSIC_ENABLE_SAVE_TAG", "false").lower() == "true"
)
get_ask_by_mina: bool = (
os.getenv("XIAOMUSIC_GET_ASK_BY_MINA", "false").lower() == "true"
)
play_type_one_tts_msg: str = os.getenv(
"XIAOMUSIC_PLAY_TYPE_ONE_TTS_MSG", "已经设置为单曲循环"
)
play_type_all_tts_msg: str = os.getenv(
"XIAOMUSIC_PLAY_TYPE_ALL_TTS_MSG", "已经设置为全部循环"
)
play_type_rnd_tts_msg: str = os.getenv(
"XIAOMUSIC_PLAY_TYPE_RND_TTS_MSG", "已经设置为随机播放"
)
play_type_sin_tts_msg: str = os.getenv(
"XIAOMUSIC_PLAY_TYPE_SIN_TTS_MSG", "已经设置为单曲播放"
)
play_type_seq_tts_msg: str = os.getenv(
"XIAOMUSIC_PLAY_TYPE_SEQ_TTS_MSG", "已经设置为顺序播放"
)
recently_added_playlist_len: int = int(
os.getenv("XIAOMUSIC_RECENTLY_ADDED_PLAYLIST_LEN", "50")
)
def append_keyword(self, keys, action):
for key in keys.split(","):
@@ -183,7 +212,11 @@ class Config:
self.append_keyword(self.keywords_playlocal, "playlocal")
self.append_keyword(self.keywords_play, "play")
self.append_keyword(self.keywords_stop, "stop")
self.append_keyword(self.keywords_playlist, "play_music_list")
self.append_user_keyword()
self.key_match_order = [
x for x in self.key_match_order if x in self.key_word_dict
]
def __post_init__(self) -> None:
if self.proxy:
@@ -278,3 +311,22 @@ class Config:
os.makedirs(self.conf_path)
cookies_path = os.path.join(self.conf_path, "yt-dlp-cookie.txt")
return cookies_path
@property
def temp_dir(self):
if not os.path.exists(self.temp_path):
os.makedirs(self.temp_path)
return self.temp_path
def get_play_type_tts(self, play_type):
if play_type == PLAY_TYPE_ONE:
return self.play_type_one_tts_msg
if play_type == PLAY_TYPE_ALL:
return self.play_type_all_tts_msg
if play_type == PLAY_TYPE_RND:
return self.play_type_rnd_tts_msg
if play_type == PLAY_TYPE_SIN:
return self.play_type_sin_tts_msg
if play_type == PLAY_TYPE_SEQ:
return self.play_type_seq_tts_msg
return ""

View File

@@ -13,14 +13,17 @@ COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={u
PLAY_TYPE_ONE = 0 # 单曲循环
PLAY_TYPE_ALL = 1 # 全部循环
PLAY_TYPE_RND = 2 # 随机播放
PLAY_TYPE_TTS = {
PLAY_TYPE_ONE: "已经设置为单曲循环",
PLAY_TYPE_ALL: "已经设置为全部循环",
PLAY_TYPE_RND: "已经设置为随机播放",
}
PLAY_TYPE_SIN = 3 # 单曲播放
PLAY_TYPE_SEQ = 4 # 顺序播放
# 需要采用 mina 获取对话记录的设备型号
GET_ASK_BY_MINA = {
"M01",
}
# 需要使用 play_musci 接口的设备型号
NEED_USE_PLAY_MUSIC_API = {
"X08C",
"X08E",
"X8F",
}

View File

@@ -45,7 +45,7 @@ class Crontab:
# 添加语音播放任务
def add_job_tts(self, expression, xiaomusic, did, arg1, **kwargs):
async def job():
xiaomusic.do_tts(did, arg1)
await xiaomusic.do_tts(did, arg1)
self.add_job(expression, job)
@@ -56,10 +56,25 @@ class Crontab:
self.add_job(expression, job)
# 设置音量任务
def add_job_set_volume(self, expression, xiaomusic, did, arg1, **kwargs):
async def job():
await xiaomusic.set_volume(did, arg1)
self.add_job(expression, job)
# 设置播放类型任务
def add_job_set_play_type(self, expression, xiaomusic, did, arg1, **kwargs):
async def job():
play_type = int(arg1)
await xiaomusic.set_play_type(did, play_type, False)
self.add_job(expression, job)
def add_job_cron(self, xiaomusic, cron):
expression = cron["expression"] # cron 计划格式
name = cron["name"] # stop, play, play_music_list, tts
did = cron["did"]
did = cron.get("did", "")
arg1 = cron.get("arg1", "")
jobname = f"add_job_{name}"
func = getattr(self, jobname, None)

View File

@@ -1,7 +1,6 @@
import asyncio
import hashlib
import json
import mimetypes
import os
import re
import secrets
@@ -26,11 +25,12 @@ from fastapi import (
from fastapi.middleware.cors import CORSMiddleware
from fastapi.openapi.docs import get_redoc_html, get_swagger_ui_html
from fastapi.openapi.utils import get_openapi
from fastapi.responses import RedirectResponse, StreamingResponse
from fastapi.responses import RedirectResponse
from fastapi.security import HTTPBasic, HTTPBasicCredentials
from fastapi.staticfiles import StaticFiles
from pydantic import BaseModel
from starlette.background import BackgroundTask
from starlette.middleware.gzip import GZipMiddleware
from starlette.responses import FileResponse, Response
from xiaomusic import __version__
@@ -106,6 +106,8 @@ app.add_middleware(
allow_methods=["*"], # 允许使用的请求方法
allow_headers=["*"], # 允许携带的 Headers
)
# 添加 GZip 中间件
app.add_middleware(GZipMiddleware, minimum_size=500)
def reset_http_server():
@@ -304,6 +306,23 @@ async def musicinfos(
return ret
class MusicInfoObj(BaseModel):
musicname: str
title: str = ""
artist: str = ""
album: str = ""
year: str = ""
genre: str = ""
lyrics: str = ""
picture: str = "" # base64
@app.post("/setmusictag")
async def setmusictag(info: MusicInfoObj, Verifcation=Depends(verification)):
ret = xiaomusic.set_music_tag(info.musicname, info)
return {"ret": ret}
@app.get("/curplaylist")
async def curplaylist(did: str = "", Verifcation=Depends(verification)):
if not xiaomusic.did_exist(did):
@@ -326,6 +345,44 @@ class UrlInfo(BaseModel):
url: str
class DidPlayMusic(BaseModel):
did: str
musicname: str = ""
searchkey: str = ""
@app.post("/playmusic")
async def playmusic(data: DidPlayMusic, Verifcation=Depends(verification)):
did = data.did
musicname = data.musicname
searchkey = data.searchkey
if not xiaomusic.did_exist(did):
return {"ret": "Did not exist"}
log.info(f"playmusic {did} musicname:{musicname} searchkey:{searchkey}")
await xiaomusic.do_play(did, musicname, searchkey)
return {"ret": "OK"}
class DidPlayMusicList(BaseModel):
did: str
listname: str = ""
musicname: str = ""
@app.post("/playmusiclist")
async def playmusiclist(data: DidPlayMusicList, Verifcation=Depends(verification)):
did = data.did
listname = data.listname
musicname = data.musicname
if not xiaomusic.did_exist(did):
return {"ret": "Did not exist"}
log.info(f"playmusiclist {did} listname:{listname} musicname:{musicname}")
await xiaomusic.do_play_music_list(did, listname, musicname)
return {"ret": "OK"}
@app.post("/downloadjson")
async def downloadjson(data: UrlInfo, Verifcation=Depends(verification)):
log.info(data)
@@ -469,6 +526,51 @@ async def upload_yt_dlp_cookie(file: UploadFile = File(...)):
}
class PlayListObj(BaseModel):
name: str = "" # 歌单名
# 新增歌单
@app.post("/playlistadd")
async def playlistadd(data: PlayListObj, Verifcation=Depends(verification)):
ret = xiaomusic.play_list_add(data.name)
if ret:
return {"ret": "OK"}
return {"ret": "Add failed, may be already exist."}
# 移除歌单
@app.post("/playlistdel")
async def playlistdel(data: PlayListObj, Verifcation=Depends(verification)):
ret = xiaomusic.play_list_del(data.name)
if ret:
return {"ret": "OK"}
return {"ret": "Del failed, may be not exist."}
class PlayListMusicObj(BaseModel):
name: str = "" # 歌单名
music_list: list[str] # 歌曲名列表
# 歌单新增歌曲
@app.post("/playlistaddmusic")
async def playlistaddmusic(data: PlayListMusicObj, Verifcation=Depends(verification)):
ret = xiaomusic.play_list_add_music(data.name, data.music_list)
if ret:
return {"ret": "OK"}
return {"ret": "Add failed, may be playlist not exist."}
# 歌单移除歌曲
@app.post("/playlistdelmusic")
async def playlistdelmusic(data: PlayListMusicObj, Verifcation=Depends(verification)):
ret = xiaomusic.play_list_del_music(data.name, data.music_list)
if ret:
return {"ret": "OK"}
return {"ret": "Del failed, may be playlist not exist."}
async def file_iterator(file_path, start, end):
async with aiofiles.open(file_path, mode="rb") as file:
await file.seek(start)
@@ -538,7 +640,7 @@ async def music_file(request: Request, file_path: str, key: str = "", code: str
if not os.path.exists(absolute_file_path):
raise HTTPException(status_code=404, detail="File not found")
# 移除MP3 ID3 v2标签和填充,减少播放前延迟
# 移除MP3 ID3 v2标签和填充
if config.remove_id3tag and is_mp3(file_path):
log.info(f"remove_id3tag:{config.remove_id3tag}, is_mp3:True ")
temp_mp3_file = remove_id3_tags(absolute_file_path, config)
@@ -560,34 +662,7 @@ async def music_file(request: Request, file_path: str, key: str = "", code: str
else:
log.warning(f"Failed to convert file to MP3 format: {absolute_file_path}")
file_size = os.path.getsize(absolute_file_path)
range_start, range_end = 0, file_size - 1
range_header = request.headers.get("Range")
log.info(f"music_file range_header {range_header}")
if range_header:
range_match = range_pattern.match(range_header)
if range_match:
range_start = int(range_match.group(1))
if range_match.group(2):
range_end = int(range_match.group(2))
log.info(f"music_file in range {absolute_file_path}")
log.info(f"music_file {range_start} {range_end} {absolute_file_path}")
headers = {
"Content-Range": f"bytes {range_start}-{range_end}/{file_size}",
"Accept-Ranges": "bytes",
}
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type is None:
mime_type = "application/octet-stream"
return StreamingResponse(
file_iterator(absolute_file_path, range_start, range_end),
headers=headers,
status_code=206 if range_header else 200,
media_type=mime_type,
)
return FileResponse(absolute_file_path)
@app.options("/music/{file_path:path}")
@@ -610,10 +685,7 @@ async def get_picture(request: Request, file_path: str, key: str = "", code: str
if not os.path.exists(absolute_file_path):
raise HTTPException(status_code=404, detail="File not found")
mime_type, _ = mimetypes.guess_type(absolute_file_path)
if mime_type is None:
mime_type = "image/jpeg"
return FileResponse(absolute_file_path, media_type=mime_type)
return FileResponse(absolute_file_path)
@app.get("/docs", include_in_schema=False)

View File

@@ -4,17 +4,21 @@ $(function(){
append_op_button_name("加入收藏");
append_op_button_name("取消收藏");
const PLAY_TYPE_ONE = 0; // 单曲循环
const PLAY_TYPE_ALL = 1; // 全部循环
const PLAY_TYPE_RND = 2; // 随机播放
append_op_button("play_type_all", "全部循环", "全部循环");
append_op_button("play_type_one", "单曲循环", "单曲循环");
append_op_button("play_type_rnd", "随机播放", "随机播放");
append_op_button_name("上一首");
append_op_button_name("关机");
append_op_button_name("下一首");
const PLAY_TYPE_ONE = 0; // 单曲循环
const PLAY_TYPE_ALL = 1; // 全部循环
const PLAY_TYPE_RND = 2; // 随机播放
const PLAY_TYPE_SIN = 3; // 单曲播放
const PLAY_TYPE_SEQ = 4; // 顺序播放
append_op_button("play_type_all", "全部循环", "全部循环");
append_op_button("play_type_one", "单曲循环", "单曲循环");
append_op_button("play_type_rnd", "随机播放", "随机播放");
append_op_button("play_type_sin", "单曲播放", "单曲播放");
append_op_button("play_type_seq", "顺序播放", "顺序播放");
append_op_button_name("刷新列表");
$container.append($("<hr>"));
@@ -25,7 +29,7 @@ $(function(){
var offset = 0;
var duration = 0;
let no_warning = localStorage.getItem('no-warning');
// 拉取现有配置
$.get("/getsetting", function(data, status) {
console.log(data, status);
@@ -71,6 +75,12 @@ $(function(){
} else if (cur_device.play_type == PLAY_TYPE_RND) {
$("#play_type_rnd").css('background-color', '#b1a8f3');
$("#play_type_rnd").text('✔️ 随机播放');
} else if (cur_device.play_type == PLAY_TYPE_SIN) {
$("#play_type_sin").css('background-color', '#b1a8f3');
$("#play_type_sin").text('✔️ 单曲播放');
} else if (cur_device.play_type == PLAY_TYPE_SEQ) {
$("#play_type_seq").css('background-color', '#b1a8f3');
$("#play_type_seq").text('✔️ 顺序播放');
}
}
}
@@ -182,11 +192,34 @@ $(function(){
});
}
function do_play_music_list(listname, musicname) {
$.ajax({
type: "POST",
url: "/playmusiclist",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({did: did, listname: listname, musicname: musicname}),
success: () => {
console.log("do_play_music_list succ", listname, musicname);
},
error: () => {
console.log("do_play_music_list failed", listname, musicname);
}
});
}
$("#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);
if (no_warning) {
do_play_music_list(music_list, music_name);
return;
}
$.get(`/musicinfo?name=${music_name}`, function(data, status) {
console.log(data);
if (data.ret == "OK") {
validHost(data.url) && do_play_music_list(music_list, music_name);
}
});
});
$("#web_play").on("click", () => {
@@ -194,7 +227,7 @@ $(function(){
$.get(`/musicinfo?name=${music_name}`, function(data, status) {
console.log(data);
if (data.ret == "OK") {
$('audio').attr('src',data.url);
validHost(data.url) && $('audio').attr('src',data.url);
}
});
});
@@ -249,11 +282,32 @@ $(function(){
$container.append($button);
}
function do_play_music(musicname, searchkey) {
$.ajax({
type: "POST",
url: "/playmusic",
contentType: "application/json; charset=utf-8",
data: JSON.stringify({did: did, musicname: musicname, searchkey: searchkey}),
success: () => {
console.log("do_play_music succ", musicname, searchkey);
},
error: () => {
console.log("do_play_music failed", musicname, searchkey);
}
});
}
$("#play").on("click", () => {
var search_key = $("#music-name").val();
if (search_key == null) {
search_key = "";
}
var filename = $("#music-filename").val();
let cmd = "播放歌曲" + search_key + "|" + filename;
sendcmd(cmd);
if (filename == null || filename == "") {
filename = search_key;
}
do_play_music(filename, search_key);
});
$("#volume").on('change', function () {
@@ -292,7 +346,7 @@ $(function(){
if (cmd == "刷新列表") {
check_status_refresh_music_list(3); // 最多重试3次
}
if (["全部循环", "单曲循环", "随机播放"].includes(cmd)) {
if (["全部循环", "单曲循环", "随机播放", "单曲播放", "顺序播放"].includes(cmd)) {
location.reload();
}
},
@@ -359,7 +413,7 @@ $(function(){
.catch(error => {
console.error('Error fetching data:', error);
});
}, 300));
}, 500));
// 动态显示保存文件名输入框
const musicNameSelect = document.getElementById('music-name');
@@ -419,5 +473,48 @@ $(function(){
var minutes = Math.floor(seconds / 60);
var remainingSeconds =Math.floor(seconds % 60);
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
}
}
$("audio").on("error", (e) => {
//如果audio标签的src为空则不做任何操作兼容安卓端的低版本webview
if ($("audio").attr("src") === "") {
return;
}
console.log('%c网页播放出现错误: ', 'color: #007acc;', e.currentTarget.error.code,e.currentTarget.error.message);
alert(e.currentTarget.error.code==4 ? "无法打开媒体文件XIAOMUSIC_HOSTNAME或端口地址错误请重新设置" : "在线播放失败,请截图反馈: "+e.currentTarget.error.message);
});
function validHost(url) {
//如果 localStorage 中有 no-warning 则直接返回true
if (no_warning) {
return true;
}
const local = location.host;
const host = new URL(url).host;
// 如果当前页面的Host与设置中的XIAOMUSIC_HOSTNAME、PORT一致, 不再提醒
if (local === host) {
localStorage.setItem('no-warning', 'true');
// 设置全局变量
no_warning = true;
return true;
}
// 如果当前页面的Host与设置中的XIAOMUSIC_HOSTNAME、PORT不一致
const validHost = document.getElementById('valid-host');
let validFlag = false;
$('#local-host').text(local);
$('#setting-host').text(host);
validHost.showModal();
//监听validHost的close事件
function _handleClose() {
console.log('%c提醒HOST不一致弹窗,用户已选择: ', 'color: #007acc;', validHost.returnValue);
if (validHost.returnValue == "no-warning") {
localStorage.setItem('no-warning', 'true');
no_warning = true;
validFlag = true;
}
validHost.removeEventListener('close', _handleClose)
}
validHost.addEventListener('close', _handleClose)
return validFlag;
}
});

View File

@@ -6,9 +6,9 @@
<meta name="viewport" content="width=device-width">
<title>Debug For XiaoMusic</title>
<link rel="stylesheet" type="text/css" href="./style.css?version=1729180160">
<link rel="stylesheet" type="text/css" href="./style.css?version=1733563859">
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script src="./jquery-3.7.1.min.js?version=1729180160"></script>
<script src="./jquery-3.7.1.min.js?version=1733563859"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>

View File

@@ -4,8 +4,8 @@
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width">
<title>歌曲下载工具</title>
<link rel="stylesheet" type="text/css" href="./style.css?version=1729180160">
<script src="./jquery-3.7.1.min.js?version=1729180160"></script>
<link rel="stylesheet" type="text/css" href="./style.css?version=1733563859">
<script src="./jquery-3.7.1.min.js?version=1733563859"></script>
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>

View File

@@ -4,9 +4,9 @@
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width">
<title>小爱音箱操控面板</title>
<script src="./jquery-3.7.1.min.js?version=1729180160"></script>
<script src="./app.js?version=1729180160"></script>
<link rel="stylesheet" type="text/css" href="./style.css?version=1729180160">
<script src="./jquery-3.7.1.min.js?version=1733563859"></script>
<script src="./app.js?version=1733563859"></script>
<link rel="stylesheet" type="text/css" href="./style.css?version=1733563859">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
@@ -94,5 +94,17 @@ var vConsole = new window.VConsole();
<footer>
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
</footer>
<dialog id="valid-host">
<form method="dialog">
<p>当前页面的HOST与设置中的HOST不一致请检查是否设置错误</p>
<p>当前HOST: <span id="local-host"></span></p>
<p>设置中的HOST: <span id="setting-host"></span></p>
<div class="btn-list">
<a href="./setting.html" target="_blank">立即修改</a>
<button value="no-warning" type="submit">继续并不再显示</button>
<button value="cancle" type="submit">取消</button>
</div>
</form>
</dialog>
</body>
</html>

View File

@@ -5,7 +5,7 @@
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width">
<title>M3U to JSON Converter</title>
<link rel="stylesheet" type="text/css" href="./style.css?version=1729180160">
<link rel="stylesheet" type="text/css" href="./style.css?version=1733563859">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>

View File

@@ -4,9 +4,9 @@
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width">
<title>小爱音箱操控面板</title>
<script src="./jquery-3.7.1.min.js?version=1729180160"></script>
<script src="./setting.js?version=1729180160"></script>
<link rel="stylesheet" type="text/css" href="./style.css?version=1729180160">
<script src="./jquery-3.7.1.min.js?version=1733563859"></script>
<script src="./setting.js?version=1733563859"></script>
<link rel="stylesheet" type="text/css" href="./style.css?version=1733563859">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
@@ -43,13 +43,13 @@ var vConsole = new window.VConsole();
<div id="setting">
<div class="rows">
<label for="account">*小米账号:</label>
<input id="account" type="text" placeholder="填写小米登录账号"></input>
<input id="account" type="text" placeholder="填写小米登录账号" />
<label for="password">*小米密码:</label>
<input id="password" type="password" placeholder="填写小米登录密码"></input>
<input id="password" type="password" placeholder="填写小米登录密码" />
<label for="hostname">*XIAOMUSIC_HOSTNAME(IP或域名):</label>
<input id="hostname" type="text"></input>
<input id="hostname" type="text" />
</div>
<hr>
<div class="rows">
@@ -59,36 +59,44 @@ var vConsole = new window.VConsole();
<option value="false">false</option>
</select>
<label for="port">监听端口(修改后需要重启):</label>
<input id="port" type="number" value="8090" />
<label for="public_port">外网访问端口(0表示跟监听端口一致):</label>
<input id="public_port" type="number" value="0" />
<label for="group_list">设备分组配置:<a href="https://github.com/hanxi/xiaomusic/issues/65#issuecomment-2215736529" target="_blank">文档</a></label>
<input id="group_list" type="text" placeholder="did1:组名1,did2:组名1,did3:组名2"></input>
<input id="group_list" type="text" placeholder="did1:组名1,did2:组名1,did3:组名2" />
<label for="music_path">音乐目录:</label>
<input id="music_path" type="text" value="music"></input>
<input id="music_path" type="text" value="music" />
<label for="download_path">音乐下载目录(必须是music的子目录):</label>
<input id="download_path" type="text" value='music/download'></input>
<input id="download_path" type="text" value='music/download' />
<label for="conf_path">配置文件目录:</label>
<input id="conf_path" type="text"></input>
<input id="conf_path" type="text" />
<label for="cache_dir">缓存文件目录:</label>
<input id="cache_dir" type="text"></input>
<input id="cache_dir" type="text" />
<label for="temp_path">临时文件目录:</label>
<input id="temp_path" type="text" value="music/tmp" />
<label for="ffmpeg_location">ffmpeg路径:</label>
<input id="ffmpeg_location" type="text" value="./ffmpeg/bin"></input>
<input id="ffmpeg_location" type="text" value="./ffmpeg/bin" />
<label for="log_file">日志路径:</label>
<input id="log_file" type="text" value="/tmp/xiaomusic.txt"></input>
<input id="log_file" type="text" value="xiaomusic.log.txt" />
<label for="active_cmd">允许唤醒的命令:</label>
<input id="active_cmd" type="text" value="play,random_play,playlocal,play_music_list,stop"></input>
<input id="active_cmd" type="text" value="play,random_play,playlocal,play_music_list,stop" />
<label for="exclude_dirs">忽略目录(逗号分割):</label>
<input id="exclude_dirs" type="text" value="@eaDir"></input>
<input id="exclude_dirs" type="text" value="@eaDir,tmp" />
<label for="music_path_depth">目录深度:</label>
<input id="music_path_depth" type="number" value="10"></input>
<input id="music_path_depth" type="number" value="10" />
<label for="search_prefix">XIAOMUSIC_SEARCH(歌曲下载方式):</label>
<select id="search_prefix">
@@ -97,7 +105,7 @@ var vConsole = new window.VConsole();
</select>
<label for="proxy">XIAOMUSIC_PROXY(ytsearch需要):</label>
<input id="proxy" type="text" placeholder="http://192.168.2.5:8080"></input>
<input id="proxy" type="text" placeholder="http://192.168.2.5:8080" />
<label for="remove_id3tag">去除MP3 ID3v2和填充:</label>
<select id="remove_id3tag">
@@ -112,7 +120,7 @@ var vConsole = new window.VConsole();
</select>
<label for="miio_tts_command">MiIO tts 指令(解决部分型号没有提示音的问题):</label>
<input id="miio_tts_command" type="text" placeholder="如5 或者 5-3"></input>
<input id="miio_tts_command" type="text" placeholder="如5 或者 5-3" />
<label for="disable_httpauth">关闭控制台密码验证:</label>
<select id="disable_httpauth">
@@ -120,9 +128,9 @@ var vConsole = new window.VConsole();
<option value="false">false</option>
</select>
<label for="httpauth_username">控制台账户:</label>
<input id="httpauth_username" type="text" value=""></input>
<input id="httpauth_username" type="text" value="" />
<label for="httpauth_password">控制台密码:</label>
<input id="httpauth_password" type="password" value=""></input>
<input id="httpauth_password" type="password" value="" />
<label for="disable_download">关闭下载功能:</label>
<select id="disable_download">
@@ -131,12 +139,12 @@ var vConsole = new window.VConsole();
</select>
<label for="use_music_audio_id">触屏版显示歌曲ID:</label>
<input id="use_music_audio_id" type="text" value="1582971365183456177"></input>
<input id="use_music_audio_id" type="text" value="1582971365183456177" />
<label for="use_music_id">触屏版显示歌曲分段ID:</label>
<input id="use_music_id" type="text" value="355454500"></input>
<input id="use_music_id" type="text" value="355454500" />
<label for="fuzzy_match_cutoff">模糊匹配阈值(0.1~0.9):</label>
<input id="fuzzy_match_cutoff" type="number" value="0.6"></input>
<input id="fuzzy_match_cutoff" type="number" value="0.6" />
<label for="enable_fuzzy_match">开启模糊搜索:</label>
<select id="enable_fuzzy_match">
@@ -156,26 +164,33 @@ var vConsole = new window.VConsole();
<option value="false" selected>false</option>
</select>
<label for="port">监听端口(修改后需要重启):</label>
<input id="port" type="number" value="8090"></input>
<label for="public_port">外网访问端口(0表示跟监听端口一致):</label>
<input id="public_port" type="number" value="0"></input>
<label for="pull_ask_sec">获取对话记录间隔(秒):</label>
<input id="pull_ask_sec" type="number" value="1"></input>
<input id="pull_ask_sec" type="number" value="1" />
<label for="delay_sec">下一首歌延迟播放秒数:</label>
<input id="delay_sec" type="number" value="3"></input>
<input id="delay_sec" type="number" value="3" />
<label for="stop_tts_msg">停止提示音:</label>
<input id="stop_tts_msg" type="text" value="收到,再见"></input>
<input id="stop_tts_msg" type="text" value="收到,再见" />
<label for="play_type_one_tts_msg">单曲循环提示音:</label>
<input id="play_type_one_tts_msg" type="text" value="已经设置为单曲循环" />
<label for="play_type_all_tts_msg">全部循环提示音:</label>
<input id="play_type_all_tts_msg" type="text" value="已经设置为全部循环" />
<label for="play_type_rnd_tts_msg">随机播放提示音:</label>
<input id="play_type_rnd_tts_msg" type="text" value="已经设置为随机播放" />
<label for="play_type_sin_tts_msg">单曲播放提示音:</label>
<input id="play_type_sin_tts_msg" type="text" value="已经设置为单曲播放" />
<label for="play_type_seq_tts_msg">顺序播放提示音:</label>
<input id="play_type_seq_tts_msg" type="text" value="已经设置为顺序播放" />
<label for="keywords_playlocal">播放本地歌曲口令:</label>
<input id="keywords_playlocal" type="text" value="播放本地歌曲,本地播放歌曲"></input>
<input id="keywords_playlocal" type="text" value="播放本地歌曲,本地播放歌曲" />
<label for="keywords_play">播放歌曲口令:</label>
<input id="keywords_play" type="text" value="播放歌曲,放歌曲"></input>
<input id="keywords_play" type="text" value="播放歌曲,放歌曲" />
<label for="keywords_playlist">播放列表口令:</label>
<input id="keywords_playlist" type="text" value="播放列表,播放歌单" />
<label for="keywords_stop">停止口令:</label>
<input id="keywords_stop" type="text" value="关机,暂停,停止,停止播放"></input>
<input id="keywords_stop" type="text" value="关机,暂停,停止,停止播放" />
<label for="enable_yt_dlp_cookies">启用yt-dlp-cookies(需要先上传yt-dlp-cookies.txt文件):</label>
<select id="enable_yt_dlp_cookies">
@@ -183,14 +198,23 @@ var vConsole = new window.VConsole();
<option value="false" selected>false</option>
</select>
<label for="enable_save_tag">启用ID3标签写入文件:</label>
<select id="enable_save_tag">
<option value="true">true</option>
<option value="false" selected>false</option>
</select>
<label for="get_ask_by_mina">特殊型号获取对话记录:</label>
<select id="get_ask_by_mina">
<option value="true">true</option>
<option value="false" selected>false</option>
</select>
<label for="recently_added_playlist_len">最近新增的歌曲数量:</label>
<input id="recently_added_playlist_len" type="number" value="50" />
<label for="music_list_url">歌单地址:</label>
<input id="music_list_url" type="text" value="https://gist.githubusercontent.com/hanxi/dda82d964a28f8110f8fba81c3ff8314/raw/example.json"></input>
<input id="music_list_url" type="text" value="https://gist.githubusercontent.com/hanxi/dda82d964a28f8110f8fba81c3ff8314/raw/example.json" />
<label for="music_list_json">歌单内容:<a href="https://github.com/hanxi/xiaomusic/issues/78" target="_blank">格式文档</a></label>
<textarea id="music_list_json" type="text"></textarea>

View File

@@ -16,13 +16,19 @@ $(function(){
});
};
function updateCheckbox(selector, mi_did, device_list) {
function updateCheckbox(selector, mi_did, device_list,accountPassValid) {
// 清除现有的内容
$(selector).empty();
// 将 mi_did 字符串通过逗号分割转换为数组,以便于判断默认选中项
var selected_dids = mi_did.split(',');
//如果device_list为空则可能是未设置小米账号密码或者已设置密码但是没有过小米验证此处需要提示用户
if (device_list.length == 0) {
const loginTips = accountPassValid ? `<div class="login-tips">未发现可用的小爱设备,请检查账号密码是否输错,并关闭加速代理或在<a href="https://www.mi.com">小米官网</a>登陆过人脸或滑块验证。如仍未解决。请根据<a href="https://github.com/hanxi/xiaomusic/issues/99">FAQ</a>的内容解决问题。</div>` : `<div class="login-tips">未发现可用的小爱设备,请先在下面的输入框中设置小米的<b>账号、密码</b></div>`;
$(selector).append(loginTips);
return;
}
$.each(device_list, function(index, device) {
var did = device.miotDID;
var hardware = device.hardware;
@@ -64,7 +70,8 @@ $(function(){
// 拉取现有配置
$.get("/getsetting?need_device_list=true", function(data, status) {
console.log(data, status);
updateCheckbox("#mi_did", data.mi_did, data.device_list);
const accountPassValid = data.account && data.password;
updateCheckbox("#mi_did", data.mi_did, data.device_list, accountPassValid);
// 初始化显示
for (const key in data) {

View File

@@ -21,7 +21,6 @@ button:active, .button:active {
}
label {
margin-left: 10px;
width: 300px;
}
input,select {
margin-left: 5%;
@@ -100,3 +99,67 @@ footer {
animation: blink 1s infinite;
}
.login-tips {
color: red;
font-size: 12px;
margin-left: 10px;
}
.login-tips a {
color: rgb(9, 105, 218);
text-decoration: underline;
}
#valid-host {
padding: 20px;
border: none;
border-radius: 10px;
background-color: #fff;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.2);
}
#valid-host::backdrop {
background-color: rgba(0, 0, 0, 0.5);
}
#valid-host form input {
width: fit-content;
margin: 0;
height: fit-content;
}
#valid-host p {
word-break: break-all;
}
#valid-host p span {
color: red;
}
#valid-host a, #valid-host a:visited {
color: rgb(9, 105, 218);;
text-decoration: underline;
display: flex;
align-items: center;
}
#valid-host a:hover {
color: rgb(9, 95, 198);
}
#valid-host .btn-list {
display: flex;
justify-content: center;
margin-top: 20px;
}
#valid-host .btn-list button {
width: fit-content;
min-width: 60px;
height: 40px;
border: none;
color: white;
text-align: center;
text-decoration: none;
display: inline-block;
border-radius: 10px;
background-color: #008CBA;
}
#valid-host .btn-list button:hover {
font-weight:bold;
background-color: #007CBA;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 990 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 657 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 891 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 394 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 760 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Some files were not shown because too many files have changed in this diff Show More