mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-06 14:52:50 +08:00
Compare commits
147 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
48d663a764 | ||
|
|
08ab75b390 | ||
|
|
71dfc6d468 | ||
|
|
7877775495 | ||
|
|
7744a75773 | ||
|
|
a28a0267e4 | ||
|
|
417a5c924a | ||
|
|
d4bc1c49ea | ||
|
|
51ef9e08fe | ||
|
|
285203a342 | ||
|
|
af6077693e | ||
|
|
40ac67cce0 | ||
|
|
96d03c5c29 | ||
|
|
82aa453e50 | ||
|
|
1718211619 | ||
|
|
09310675fc | ||
|
|
ca711bbdb8 | ||
|
|
fb44f88df2 | ||
|
|
e5b32b2831 | ||
|
|
19ddbb7ca9 | ||
|
|
3e82d7acdc | ||
|
|
3921c70c86 | ||
|
|
aea9333e57 | ||
|
|
7043ca31cf | ||
|
|
963d86de7c | ||
|
|
d6b0e974b7 | ||
|
|
8a8340a159 | ||
|
|
20d3c9fce9 | ||
|
|
729549a7a9 | ||
|
|
d28614177c | ||
|
|
db53517784 | ||
|
|
186e9c1417 | ||
|
|
7498016d61 | ||
|
|
7114ea2e6e | ||
|
|
e8ca1f8678 | ||
|
|
2275bc2600 | ||
|
|
45a94f4bfe | ||
|
|
5cb2c84715 | ||
|
|
a3bf8d8aaa | ||
|
|
0a88b7be26 | ||
|
|
05da3e8fc4 | ||
|
|
560ea1aeca | ||
|
|
5ef1f2d940 | ||
|
|
e01fcdcecd | ||
|
|
8ff04dd0f6 | ||
|
|
4a7b5ac2b0 | ||
|
|
ac74ef3c15 | ||
|
|
8913057c27 | ||
|
|
a75030a73c | ||
|
|
e2e74f9459 | ||
|
|
09febb66dc | ||
|
|
ad0db8c9a9 | ||
|
|
90b0fecd3b | ||
|
|
a8f88e8bfc | ||
|
|
d8035f0713 | ||
|
|
76c1a8952f | ||
|
|
d8a66ca152 | ||
|
|
dd77176035 | ||
|
|
6d7d90d642 | ||
|
|
514bf9b8b2 | ||
|
|
cd5869ff84 | ||
|
|
ee6f4ee4e4 | ||
|
|
0189a00155 | ||
|
|
e3d60d3f2e | ||
|
|
27fecd788b | ||
|
|
e9b1d94fb3 | ||
|
|
043a9303a5 | ||
|
|
aa698667c9 | ||
|
|
700e17854c | ||
|
|
40258c9fa1 | ||
|
|
eb59bf0db5 | ||
|
|
a9df78af97 | ||
|
|
901506a32d | ||
|
|
0ddbe58fbd | ||
|
|
350d82184f | ||
|
|
5b8054abd9 | ||
|
|
c5c691b653 | ||
|
|
7a44c8587c | ||
|
|
5092ffc91a | ||
|
|
2da12e12d5 | ||
|
|
5aff72dbb6 | ||
|
|
043f452e71 | ||
|
|
5cedf8a907 | ||
|
|
ae77c7232e | ||
|
|
d559413d46 | ||
|
|
8b185d8768 | ||
|
|
202105a11f | ||
|
|
7da80594e3 | ||
|
|
a032a1d50a | ||
|
|
be62d8abc8 | ||
|
|
aaf9f4b6a7 | ||
|
|
bb5d82097e | ||
|
|
d6ba656641 | ||
|
|
742cae0543 | ||
|
|
a4ab1af160 | ||
|
|
86f158532a | ||
|
|
9ea7935cfb | ||
|
|
20c7e14076 | ||
|
|
e10f5b89b6 | ||
|
|
cb0bae5ae7 | ||
|
|
6a583119d0 | ||
|
|
9349070e8b | ||
|
|
01d99dc699 | ||
|
|
f4d9a6c1fd | ||
|
|
1919bc84d9 | ||
|
|
4c1761468f | ||
|
|
c75230a67d | ||
|
|
ee7ffa55cb | ||
|
|
45bbc8af42 | ||
|
|
ab8bf8fa62 | ||
|
|
493cad080e | ||
|
|
eaa159c5cb | ||
|
|
96e3b8c2ff | ||
|
|
794e8dcd06 | ||
|
|
f2675e4340 | ||
|
|
e5059840fb | ||
|
|
f3e57789fa | ||
|
|
c151b826f7 | ||
|
|
1b3ed3b35a | ||
|
|
77a37a9438 | ||
|
|
f22de9f906 | ||
|
|
090e8c3f4c | ||
|
|
aef51fb65d | ||
|
|
a5a3a2dc62 | ||
|
|
ce9adcee7f | ||
|
|
485a42a9a0 | ||
|
|
3754970c84 | ||
|
|
924fbc208b | ||
|
|
c1a2ee4577 | ||
|
|
e84ee5de1e | ||
|
|
0414830539 | ||
|
|
385f23842d | ||
|
|
1deceaa5a5 | ||
|
|
b8f1157e27 | ||
|
|
06558c24b7 | ||
|
|
6bd399b654 | ||
|
|
228d89f1f8 | ||
|
|
e97639302f | ||
|
|
7f4e51be08 | ||
|
|
cdab5fc92d | ||
|
|
6efe498f2a | ||
|
|
0f3f2e47f5 | ||
|
|
3b720b7367 | ||
|
|
9a3e513b6c | ||
|
|
5a8e5dfa82 | ||
|
|
70d9ad93cb | ||
|
|
87b3411f5e |
2
.github/FUNDING.yml
vendored
2
.github/FUNDING.yml
vendored
@@ -1,2 +1,2 @@
|
||||
github: [hanxi]
|
||||
custom: ['https://afdian.net/a/imhanxi']
|
||||
custom: ['https://afdian.com/a/imhanxi']
|
||||
|
||||
11
.github/workflows/ci.yml
vendored
11
.github/workflows/ci.yml
vendored
@@ -2,7 +2,8 @@ name: ci
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches:
|
||||
- "*"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
@@ -25,6 +26,12 @@ jobs:
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v6,linux/arm/v7
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
push: true
|
||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}
|
||||
- name: Docker Hub Description
|
||||
uses: peter-evans/dockerhub-description@v4
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
repository: hanxi/xiaomusic
|
||||
|
||||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
@@ -61,6 +61,6 @@ jobs:
|
||||
uses: docker/build-push-action@v4
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v6,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
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -165,3 +165,5 @@ ffmpeg
|
||||
music
|
||||
test.sh
|
||||
conf
|
||||
setting.json
|
||||
.DS_Store
|
||||
|
||||
8
.pre-commit-config.yaml
Normal file
8
.pre-commit-config.yaml
Normal file
@@ -0,0 +1,8 @@
|
||||
repos:
|
||||
- hooks:
|
||||
- id: commitizen
|
||||
- id: commitizen-branch
|
||||
stages:
|
||||
- push
|
||||
repo: https://github.com/commitizen-tools/commitizen
|
||||
rev: v3.27.0
|
||||
498
CHANGELOG.md
Normal file
498
CHANGELOG.md
Normal file
@@ -0,0 +1,498 @@
|
||||
## v0.3.11 (2024-07-22)
|
||||
|
||||
### Feat
|
||||
|
||||
- Add remove mp3 id3 tag function
|
||||
|
||||
### Fix
|
||||
|
||||
- #130 单曲循环的模式下,播放列表的指令不生效
|
||||
|
||||
### Refactor
|
||||
|
||||
- 优化代码
|
||||
|
||||
## v0.3.10 (2024-07-19)
|
||||
|
||||
### Feat
|
||||
|
||||
- 支持软连接的接口直接用os.walk即可
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复软连接目录不能播放的问题
|
||||
- 修复自定义语音口令设置不生效的问题
|
||||
|
||||
## v0.3.9 (2024-07-17)
|
||||
|
||||
### Feat
|
||||
|
||||
- #119 音乐目录支持软连接
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复日志下载报错问题
|
||||
- 兼容旧的setting.json文件中conf_path为空的情况
|
||||
- 修复设置页面可能打不开的问题
|
||||
|
||||
## v0.3.8 (2024-07-16)
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复播放url接口问题
|
||||
|
||||
## v0.3.7 (2024-07-16)
|
||||
|
||||
### Feat
|
||||
|
||||
- 播放链接按钮对应给个默认的链接用于测试
|
||||
- Uvicorn 的日志信息合并到 xiaomusic 日志里显示
|
||||
|
||||
## v0.3.6 (2024-07-15)
|
||||
|
||||
### Fix
|
||||
|
||||
- #126 修复pip安装时主页打不开的问题
|
||||
|
||||
## v0.3.5 (2024-07-15)
|
||||
|
||||
### Fix
|
||||
|
||||
- #116 播放失败自动切下首歌
|
||||
|
||||
## v0.3.4 (2024-07-15)
|
||||
|
||||
### Fix
|
||||
|
||||
- #125 修复本地英文歌曲匹大小写字母配不到的问题
|
||||
|
||||
## v0.3.3 (2024-07-15)
|
||||
|
||||
### Fix
|
||||
|
||||
- 尝试修复播放卡顿问题 see #124
|
||||
|
||||
## v0.3.2 (2024-07-15)
|
||||
|
||||
### Fix
|
||||
|
||||
- #122 pip安装方式下,static目录找不到报错
|
||||
- 版本更新时更新页面缓存
|
||||
|
||||
## v0.3.1 (2024-07-15)
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复主页选择设备不生效的问题 see #120
|
||||
|
||||
## v0.3.0 (2024-07-14)
|
||||
|
||||
### Feat
|
||||
|
||||
- 建议音乐目录和配置目录分开不同目录
|
||||
- 优化后台网络设置,同时支持ipv4和ipv6
|
||||
- 使用fastapi替换flask,解决多线程问题
|
||||
- #106 网页上显示音箱当前状态(播放中or空闲中)以及当前的播放模式
|
||||
- 优化首页加载慢的问题
|
||||
- 优化设置页面布局,方便配置必须项
|
||||
- 优化配置界面,支持配置分组
|
||||
- 支持多设备分开播放 see #65
|
||||
|
||||
### Fix
|
||||
|
||||
- #114 修复部分 mp3 文件长度识别错误
|
||||
- 删除 armv6 的支持
|
||||
- 修复编译问题
|
||||
- 修复音乐路径设置后找不到音乐的问题
|
||||
- 修复启动报错的问题
|
||||
- 修复CI警告问题
|
||||
|
||||
## v0.2.0 (2024-07-09)
|
||||
|
||||
### Feat
|
||||
|
||||
- 触屏版可以不用设置 XIAOMUSIC_USE_MUSIC_API
|
||||
- 升级依赖库
|
||||
- 唤醒口令配置支持配语音词,简化自定义口令配置 see #105
|
||||
|
||||
## v0.1.101 (2024-07-07)
|
||||
|
||||
### Fix
|
||||
|
||||
- #81 修复播放列表时,当前歌曲不在列表没有更换歌曲的问题
|
||||
- #110 修复配置加载问题
|
||||
|
||||
## v0.1.100 (2024-07-07)
|
||||
|
||||
### Fix
|
||||
|
||||
- 日志代码写错
|
||||
|
||||
## v0.1.99 (2024-07-07)
|
||||
|
||||
### Fix
|
||||
|
||||
- #81 修复播放列表没有继续播放上次播放的歌曲,并把随机播放,全部循环,单曲循环状态落地
|
||||
|
||||
## v0.1.98 (2024-07-07)
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复多设备获取不到对话记录的问题 see #65
|
||||
- #93 修复目录深度设置后导致目录下的歌曲无法加到播放列表里的问题
|
||||
|
||||
## v0.1.97 (2024-07-06)
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复网页控制台设置页面保存报错
|
||||
|
||||
## v0.1.96 (2024-07-06)
|
||||
|
||||
### Feat
|
||||
|
||||
- 使用commitizen管理版本号
|
||||
- 页面版本号链接到CHANGELOG页面
|
||||
- 规范版本管理
|
||||
|
||||
## v0.1.95 (2024-07-06)
|
||||
|
||||
## v0.1.94 (2024-07-06)
|
||||
|
||||
### Feat
|
||||
|
||||
- 优化多设备接口执行效果,尽量做到同时执行
|
||||
|
||||
### Fix
|
||||
|
||||
- 新增参数配置强制打断小爱说话
|
||||
- 修复多设备获取对话记录的问题
|
||||
- 修复windows下路径分隔符被视为转移符导致音箱无法播放音乐的问题
|
||||
- 修复播放链接报错
|
||||
- 修复配置页面默认配置被置空的问题
|
||||
|
||||
## v0.1.93 (2024-07-05)
|
||||
|
||||
### Feat
|
||||
|
||||
- 访问账号密码默认为空
|
||||
- 支持下载的目录与本地音乐目录分开 see #98
|
||||
- 新增m4a文件格式支持
|
||||
- 设置页面支持配置多设备
|
||||
- 默认用空的后台账号和密码
|
||||
- 支持多个设备同时播放 see #65
|
||||
- 新增自定义口令功能 #105
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复设置页面没成功初始化设置问题
|
||||
- 修复镜像缺少文件问题
|
||||
- 尝试解决插件路径问题
|
||||
- 设置页面日志路径写错了
|
||||
- 修复口令导致异常关闭的问题
|
||||
|
||||
## v0.1.92 (2024-07-04)
|
||||
|
||||
### Feat
|
||||
|
||||
- 启动参数新增 --port 配置监听端口
|
||||
- 外网访问端口可独立配置
|
||||
- 优化设置页面,新增更多配置项
|
||||
- 首次保存设置后不需要重启容器
|
||||
|
||||
### Fix
|
||||
|
||||
- 日志文件配置的环境变量写错了
|
||||
|
||||
## v0.1.91 (2024-07-03)
|
||||
|
||||
### Fix
|
||||
|
||||
- 尝试解决触屏版不能播放的问题
|
||||
|
||||
## v0.1.90 (2024-07-02)
|
||||
|
||||
### Feat
|
||||
|
||||
- 优化触屏版播放页面显示歌曲
|
||||
|
||||
## v0.1.89 (2024-07-02)
|
||||
|
||||
### Feat
|
||||
|
||||
- 尝试解决触屏版无法播放的问题
|
||||
|
||||
### Fix
|
||||
|
||||
- 播放歌曲写成固定的了
|
||||
- 播放歌曲时被其他指令打断后没有继续播放
|
||||
|
||||
## v0.1.88 (2024-07-02)
|
||||
|
||||
### Feat
|
||||
|
||||
- 日志里不要输出敏感信息
|
||||
- 优化下载 ffmpeg 脚本,尝试解决 armv7 环境问题
|
||||
- 优化日志输出信息
|
||||
- 尝试解决触屏版无法播放的问题
|
||||
|
||||
### Fix
|
||||
|
||||
- 是否下载中判断错误导致播放无法自动重新开始播放
|
||||
- 升级yt-dlp到2024.07.01
|
||||
- 修复部分型号关机失败的问题
|
||||
|
||||
## v0.1.87 (2024-07-01)
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复XIAOMUSIC_USE_MUSIC_API=true时播放不了的问题
|
||||
|
||||
## v0.1.86 (2024-07-01)
|
||||
|
||||
### Feat
|
||||
|
||||
- 优化 ffmpeg 安装脚本
|
||||
- 新增调试工具用来调试 player_play_music 接口
|
||||
- 升级依赖库 MiService
|
||||
|
||||
### Fix
|
||||
|
||||
- 尝试修复 armv7 的 ffmpeg 问题
|
||||
- 尝试修复关机失败的问题
|
||||
- 修复口令不能播放的问题
|
||||
|
||||
## v0.1.85 (2024-06-30)
|
||||
|
||||
### Feat
|
||||
|
||||
- 版本号链接到github的release页面,方便查看版本更新日志
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复电台删除后没有从电台列表中删除的问题
|
||||
|
||||
## v0.1.84 (2024-06-30)
|
||||
|
||||
### Feat
|
||||
|
||||
- config.json 支持更多配置选项
|
||||
- 新增 XIAOMUSIC_STOP_TTS_MSG 配置关机提示音
|
||||
|
||||
## v0.1.83 (2024-06-30)
|
||||
|
||||
## v0.1.82 (2024-06-30)
|
||||
|
||||
### Feat
|
||||
|
||||
- 优化指令匹配规则
|
||||
|
||||
## v0.1.81 (2024-06-30)
|
||||
|
||||
## v0.1.80 (2024-06-30)
|
||||
|
||||
### Fix
|
||||
|
||||
- #91 修复下载歌曲报错
|
||||
|
||||
## v0.1.79 (2024-06-29)
|
||||
|
||||
## v0.1.77 (2024-06-29)
|
||||
|
||||
### Fix
|
||||
|
||||
- #52 支持配置模糊匹配本地歌曲
|
||||
|
||||
## v0.1.76 (2024-06-28)
|
||||
|
||||
## v0.1.75 (2024-06-28)
|
||||
|
||||
## v0.1.74 (2024-06-28)
|
||||
|
||||
## v0.1.73 (2024-06-28)
|
||||
|
||||
## v0.1.72 (2024-06-28)
|
||||
|
||||
## v0.1.71 (2024-06-28)
|
||||
|
||||
### Fix
|
||||
|
||||
- #83
|
||||
|
||||
## v0.1.70 (2024-06-27)
|
||||
|
||||
## v0.1.69 (2024-06-26)
|
||||
|
||||
## v0.1.67 (2024-06-26)
|
||||
|
||||
## v0.1.66 (2024-06-26)
|
||||
|
||||
## v0.1.65 (2024-06-26)
|
||||
|
||||
## v0.1.64 (2024-06-26)
|
||||
|
||||
## v0.1.62 (2024-06-25)
|
||||
|
||||
## v0.1.61 (2024-06-25)
|
||||
|
||||
## v0.1.60 (2024-06-25)
|
||||
|
||||
## v0.1.58 (2024-06-25)
|
||||
|
||||
### Fix
|
||||
|
||||
- 登陆失败不阻塞启动
|
||||
|
||||
## v0.1.57 (2024-06-24)
|
||||
|
||||
## v0.1.56 (2024-06-24)
|
||||
|
||||
## v0.1.55 (2024-06-23)
|
||||
|
||||
### Fix
|
||||
|
||||
- #47 支持配置基础的BaseAuth登录
|
||||
|
||||
## v0.1.54 (2024-06-23)
|
||||
|
||||
### Fix
|
||||
|
||||
- #76 新增XIAOMUSIC_MUSIC_PATH_DEPTH配置生成播放列表的目录深度,默认10
|
||||
- #74 配置目录可以和下载目录分开配置, 新增XIAOMUSIC_CONF_PATH用来设置配置目录,不配置时使用下载目录
|
||||
|
||||
## v0.1.53 (2024-06-23)
|
||||
|
||||
## v0.1.52 (2024-06-21)
|
||||
|
||||
## v0.1.51 (2024-06-20)
|
||||
|
||||
## v0.1.49 (2024-06-20)
|
||||
|
||||
## v0.1.48 (2024-06-16)
|
||||
|
||||
## v0.1.47 (2024-06-16)
|
||||
|
||||
## v0.1.46 (2024-06-15)
|
||||
|
||||
## v0.1.45 (2024-06-15)
|
||||
|
||||
## v0.1.44 (2024-06-14)
|
||||
|
||||
## v0.1.43 (2024-06-14)
|
||||
|
||||
## v0.1.41 (2024-06-14)
|
||||
|
||||
## v0.1.40 (2024-06-12)
|
||||
|
||||
## v0.1.39 (2024-06-12)
|
||||
|
||||
## v0.1.38 (2024-06-12)
|
||||
|
||||
### Fix
|
||||
|
||||
- #70 下一首歌曲不存在时从播放列表中删除并继续找下一首
|
||||
|
||||
## v0.1.37 (2024-06-04)
|
||||
|
||||
## v0.1.36 (2024-05-30)
|
||||
|
||||
## v0.1.35 (2024-05-30)
|
||||
|
||||
### Fix
|
||||
|
||||
- #67 没配置did时也允许启动 http 服务
|
||||
|
||||
## v0.1.34 (2024-05-19)
|
||||
|
||||
## v0.1.33 (2024-05-19)
|
||||
|
||||
### Fix
|
||||
|
||||
- #50 新增配置页面
|
||||
- #62
|
||||
|
||||
## v0.1.32 (2024-05-17)
|
||||
|
||||
## v0.1.31 (2024-05-16)
|
||||
|
||||
## v0.1.30 (2024-05-16)
|
||||
|
||||
### Fix
|
||||
|
||||
- 控制台显示版本号 #59
|
||||
|
||||
## v0.1.29 (2024-05-16)
|
||||
|
||||
### Fix
|
||||
|
||||
- #57 #55
|
||||
|
||||
## v0.1.28 (2024-05-16)
|
||||
|
||||
## v0.1.27 (2024-05-16)
|
||||
|
||||
## v0.1.26 (2024-05-08)
|
||||
|
||||
## v0.1.25 (2024-05-06)
|
||||
|
||||
## v0.1.24 (2024-04-30)
|
||||
|
||||
## v0.1.23 (2024-04-30)
|
||||
|
||||
## v0.1.22 (2024-04-30)
|
||||
|
||||
## v0.1.21 (2024-04-08)
|
||||
|
||||
## v0.1.20 (2024-04-08)
|
||||
|
||||
## v0.1.19 (2024-04-04)
|
||||
|
||||
## v0.1.18 (2024-02-24)
|
||||
|
||||
## v0.1.16 (2024-02-24)
|
||||
|
||||
## v0.1.15 (2024-02-03)
|
||||
|
||||
## v0.1.14 (2024-02-03)
|
||||
|
||||
## v0.1.13 (2024-02-02)
|
||||
|
||||
## v0.1.12 (2024-01-30)
|
||||
|
||||
### Fix
|
||||
|
||||
- set volume failed
|
||||
|
||||
## v0.1.11 (2024-01-29)
|
||||
|
||||
## v0.1.10 (2024-01-29)
|
||||
|
||||
## v0.1.9 (2024-01-28)
|
||||
|
||||
### Fix
|
||||
|
||||
- arg1 漏修改
|
||||
|
||||
## v0.1.8 (2024-01-28)
|
||||
|
||||
### Fix
|
||||
|
||||
- http server listen host
|
||||
|
||||
## v0.1.7 (2024-01-28)
|
||||
|
||||
## v0.1.6 (2024-01-28)
|
||||
|
||||
## v0.1.5 (2024-01-27)
|
||||
|
||||
## v0.1.4 (2024-01-27)
|
||||
|
||||
### Fix
|
||||
|
||||
- error when play next
|
||||
|
||||
## v0.1.3 (2023-10-15)
|
||||
|
||||
## v0.1.2 (2023-10-15)
|
||||
|
||||
## v0.1.1 (2023-10-14)
|
||||
@@ -2,7 +2,7 @@ FROM python:3.10 AS builder
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
WORKDIR /app
|
||||
COPY requirements.txt .
|
||||
RUN python3 -m venv .venv && .venv/bin/pip install --no-cache-dir -r requirements.txt
|
||||
RUN python3 -m venv .venv && .venv/bin/pip install --upgrade pip && .venv/bin/pip install --no-cache-dir -r requirements.txt
|
||||
COPY install_dependencies.sh .
|
||||
RUN bash install_dependencies.sh
|
||||
|
||||
@@ -11,11 +11,13 @@ 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 .
|
||||
ENV XDG_CONFIG_HOME=/config
|
||||
ENV XIAOMUSIC_HOSTNAME=192.168.2.5
|
||||
ENV XIAOMUSIC_PORT=8090
|
||||
VOLUME /config
|
||||
VOLUME /app/conf
|
||||
VOLUME /app/music
|
||||
EXPOSE 8090
|
||||
ENV PATH=/app/.venv/bin:$PATH
|
||||
ENTRYPOINT [".venv/bin/python3","xiaomusic.py"]
|
||||
|
||||
64
README.md
64
README.md
@@ -29,28 +29,23 @@ services:
|
||||
- 8090:8090
|
||||
volumes:
|
||||
- ./music:/app/music
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_VERBOSE: 'true'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
- ./conf:/app/conf
|
||||
```
|
||||
|
||||
对应的 docker 启动命令如下:
|
||||
|
||||
```yaml
|
||||
docker run -e MI_USER='小米账号' \
|
||||
-e MI_PASS='小米密码' \
|
||||
-e XIAOMUSIC_VERBOSE='true' \
|
||||
-e XIAOMUSIC_HOSTNAME='docker 主机 ip' \
|
||||
-p 8090:8090 \
|
||||
docker run -p 8090:8090 \
|
||||
-v ./music:/app/music \
|
||||
-v ./conf:/app/conf
|
||||
hanxi/xiaomusic
|
||||
```
|
||||
|
||||
启动成功后,在 web 页面可以配置 MI_DID, MI_HARDWARE, XIAOMUSIC_SEARCH, XIAOMUSIC_PROXY 参数。
|
||||
其中 conf 目录为配置文件存放目录,music 目录为音乐存放目录,建议分开配置为不同的目录。
|
||||
|
||||
### ✨ 修改8090端口
|
||||
启动成功后,在 web 页面可以配置其他参数,带有 `*` 号的配置是必须要配置的,其他的用不上时不用修改。初次配置时需要在页面上输入小米账号和密码保存后才能获取到设备列表。
|
||||
|
||||
### ✨✨✨ 修改默认8090端口映射 ✨✨✨
|
||||
|
||||
如果需要修改 8090 端口为其他端口,比如 5678,需要这样配,3个数字都需要是 5678 。见 <https://github.com/hanxi/xiaomusic/issues/19>
|
||||
|
||||
@@ -65,34 +60,33 @@ services:
|
||||
volumes:
|
||||
- ./music:/app/music
|
||||
environment:
|
||||
MI_USER: '小米账号'
|
||||
MI_PASS: '小米密码'
|
||||
XIAOMUSIC_VERBOSE: 'true'
|
||||
XIAOMUSIC_HOSTNAME: 'docker 主机 ip'
|
||||
XIAOMUSIC_PORT: 5678
|
||||
```
|
||||
|
||||
其中 XIAOMUSIC_VERBOSE 设置为 'true' 时表示开启 debug 日志,遇到问题可以去 web 设置页面底部【下载日志文件】按钮,然后搜索一下日志文件内容确保里面没有账号密码信息后(有就删除这些敏感信息),然后在提 issues 反馈问题时把下载的日志文件带上。
|
||||
遇到问题可以去 web 设置页面底部点击【下载日志文件】按钮,然后搜索一下日志文件内容确保里面没有账号密码信息后(有就删除这些敏感信息),然后在提 issues 反馈问题时把下载的日志文件带上。
|
||||
|
||||
> 目前除了 XIAOMUSIC_PORT 只能在启动前配置,其他参数都可以在 web 网页里配置。
|
||||
|
||||
## pip 方式安装运行
|
||||
|
||||
```shell
|
||||
> pip install xiaomusic
|
||||
> pip install -U xiaomusic
|
||||
> xiaomusic --help
|
||||
__ __ _ __ __ _
|
||||
\ \/ / (_) __ _ ___ | \/ | _ _ ___ (_) ___
|
||||
\ / | | / _` | / _ \ | |\/| | | | | | / __| | | / __|
|
||||
/ \ | | | (_| | | (_) | | | | | | |_| | \__ \ | | | (__
|
||||
/_/\_\ |_| \__,_| \___/ |_| |_| \__,_| |___/ |_| \___|
|
||||
XiaoMusic v0.1.81 by: github.com/hanxi
|
||||
XiaoMusic v0.1.92 by: github.com/hanxi
|
||||
|
||||
usage: xiaomusic.py [-h] [--hardware HARDWARE] [--account ACCOUNT]
|
||||
[--password PASSWORD] [--cookie COOKIE] [--verbose]
|
||||
[--config CONFIG] [--ffmpeg_location FFMPEG_LOCATION]
|
||||
usage: xiaomusic [-h] [--port PORT] [--hardware HARDWARE] [--account ACCOUNT]
|
||||
[--password PASSWORD] [--cookie COOKIE] [--verbose]
|
||||
[--config CONFIG] [--ffmpeg_location FFMPEG_LOCATION]
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--hardware HARDWARE 小爱 hardware
|
||||
--port PORT 监听端口
|
||||
--hardware HARDWARE 小爱音箱型号
|
||||
--account ACCOUNT xiaomi account
|
||||
--password PASSWORD xiaomi password
|
||||
--cookie COOKIE xiaomi cookie
|
||||
@@ -105,6 +99,8 @@ options:
|
||||
|
||||
其中 `config.json` 文件可以参考 `config-example.json` 文件配置。见 <https://github.com/hanxi/xiaomusic/issues/94>
|
||||
|
||||
不修改默认端口 8090 的情况下,只需要执行 `xiaomusic` 即可启动。
|
||||
|
||||
## 开发环境运行
|
||||
|
||||
- 使用 install_dependencies.sh 下载依赖
|
||||
@@ -124,6 +120,8 @@ export XIAOMUSIC_SEARCH='bilisearch:'
|
||||
pdm run xiaomusic.py
|
||||
````
|
||||
|
||||
如果是开发前端界面,可以通过 <http://localhost:8090/docs> 查看有什么接口。
|
||||
|
||||
### 支持口令
|
||||
|
||||
- **播放歌曲**
|
||||
@@ -145,8 +143,7 @@ pdm run xiaomusic.py
|
||||
| ---- | ---------------------------------------------------------------------------------------------- |
|
||||
| L06A | [小爱音箱](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.l06a) |
|
||||
| L07A | [Redmi小爱音箱 Play](https://home.mi.com/webapp/content/baike/product/index.html?model=xiaomi.wifispeaker.l7a) |
|
||||
| S12 | [小米AI音箱](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.s12) |
|
||||
| S12A | - |
|
||||
| S12/S12A/MDZ-25-DA | [小米AI音箱](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.s12) |
|
||||
| LX5A | [小爱音箱 万能遥控版](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.lx5a) |
|
||||
| LX05 | [小爱音箱Play(2019款)](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.lx05) |
|
||||
| L16A | [Xiaomi Sound](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.l16a) |
|
||||
@@ -155,10 +152,13 @@ pdm run xiaomusic.py
|
||||
| LX01 | [小爱音箱mini](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.lx01) |
|
||||
| L05B | [小爱音箱Play](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.l05b) |
|
||||
| L05C | [小米小爱音箱Play 增强版](https://home.mi.com/baike/index.html#/detail?model=xiaomi.wifispeaker.l05c) |
|
||||
| LX04 X10A X08A | 已经支持的触屏版 |
|
||||
|
||||
型号与产品名称对照可以在这里查询 <https://home.miot-spec.com/s/xiaomi.wifispeaker>
|
||||
|
||||
> 如果你的设备支持播放,请反馈给我添加到支持列表里,谢谢。
|
||||
> 目前应该所有设备类型都已经支持播放,有问题随时反馈。
|
||||
> 其他触屏版不能播放可以设置 XIAOMUSIC_USE_MUSIC_API 为 true 试试。
|
||||
|
||||
## 支持音乐格式
|
||||
|
||||
@@ -167,6 +167,7 @@ pdm run xiaomusic.py
|
||||
- wav
|
||||
- ape
|
||||
- ogg
|
||||
- m4a
|
||||
|
||||
> 本地音乐会搜索目录下上面格式的文件,下载的歌曲是 mp3 格式的。
|
||||
> 已知 L05B L05C 不支持 flac 格式。
|
||||
@@ -321,14 +322,21 @@ services:
|
||||
- XIAOMUSIC_DISABLE_HTTPAUTH 配置成 false 表示开启密码访问web控制台,具体见 <https://github.com/hanxi/xiaomusic/issues/47>
|
||||
- XIAOMUSIC_HTTPAUTH_USERNAME 配置 web 控制台用户
|
||||
- XIAOMUSIC_HTTPAUTH_PASSWORD 配置 web 控制台密码
|
||||
- XIAOMUSIC_CONF_PATH 用来存放配置文件的目录,记得把目录映射到主机,默认情况会把配置存放在music目录,具体见 <https://github.com/hanxi/xiaomusic/issues/74>
|
||||
- XIAOMUSIC_CONF_PATH 用来存放配置文件的目录,记得把目录映射到主机,默认为 `/app/config` ,具体见 <https://github.com/hanxi/xiaomusic/issues/74>
|
||||
- XIAOMUSIC_DISABLE_DOWNLOAD 设为 true 时关闭下载功能,见 <https://github.com/hanxi/xiaomusic/issues/82>
|
||||
- XIAOMUSIC_USE_MUSIC_API 设为 true 时使用 player_play_music 接口播放音乐,用于兼容不能播放的型号,v0.1.86 之后的版本可以不用设置。
|
||||
- XIAOMUSIC_USE_MUSIC_API 设为 true 时使用 player_play_music 接口播放音乐,用于兼容不能播放的型号,如果发现需要设置这个选项的时候请告知我加一下设备型号,方便以后不用设置。 见 <https://github.com/hanxi/xiaomusic/issues/30>
|
||||
- XIAOMUSIC_KEYWORDS_PLAY 用来播放歌曲的口令前缀,默认是 "播放歌曲,放歌曲" ,可以用英文逗号分割配置多个
|
||||
- XIAOMUSIC_KEYWORDS_STOP 用来关机的口令,默认是 "关机,暂停,停止" ,可以用英文逗号分割配置多个。
|
||||
- XIAOMUSIC_KEYWORDS_PLAYLOCAL 用来播放本地歌曲的口令前缀,本地找不到时不会下载歌曲,默认是 "播放本地歌曲,本地播放歌曲" ,可以用英文逗号分割配置多个。
|
||||
- XIAOMUSIC_ENABLE_FUZZY_MATCH 设为 true 时开启模糊匹配(默认),设为 false 时关闭模糊匹配,支持模糊匹配歌名和歌单名。 具体见 <https://github.com/hanxi/xiaomusic/issues/52>
|
||||
- XIAOMUSIC_FUZZY_MATCH_CUTOFF 设置模糊搜索匹配的最低相似度阈值(默认0.6,可以配0到1直接的小数),越小越模糊,越大越精准。具体见 <https://github.com/hanxi/xiaomusic/issues/52>
|
||||
- XIAOMUSIC_PUBLIC_PORT 用于设置外网端口,当使用反向代理时可以设置为外网端口,XIAOMUSIC_HOSTNAME 设为外网IP或者域名即可。
|
||||
- XIAOMUSIC_DOWNLOAD_PATH 变量可以配置下载目录,默认为空,表示使用 music 目录为下载目录。设置这个目录必须是 music 的子目录,否则刷新列表后会找不到歌曲。具体见 <https://github.com/hanxi/xiaomusic/issues/98>
|
||||
|
||||
## 高级篇
|
||||
|
||||
- 自定义口令功能 <https://github.com/hanxi/xiaomusic/issues/105>
|
||||
- [ ] 缺少一篇教程 [如何写自定义插件](https://github.com/hanxi/xiaomusic/issues/105)
|
||||
|
||||
## 讨论区
|
||||
|
||||
@@ -347,6 +355,8 @@ services:
|
||||
- [NAS部署教程](https://post.m.smzdm.com/p/avpe7n99/)
|
||||
- [群晖部署教程](https://post.m.smzdm.com/p/a7px7dol/)
|
||||
- [QNAS部署教程](https://post.smzdm.com/p/a5xz5x63/)
|
||||
- 所有帮忙调试和测试的朋友
|
||||
- 所有反馈问题和建议的朋友
|
||||
|
||||
## Star History
|
||||
|
||||
|
||||
@@ -1,32 +1,81 @@
|
||||
{
|
||||
"hardware": "L07A",
|
||||
"account": "",
|
||||
"password": "",
|
||||
"mi_did": "",
|
||||
"cookie": "",
|
||||
"verbose": false,
|
||||
"music_path": "music",
|
||||
"conf_path": null,
|
||||
"hostname": "192.168.2.5",
|
||||
"port": 8090,
|
||||
"proxy": null,
|
||||
"search_prefix": "ytsearch:",
|
||||
"ffmpeg_location": "./ffmpeg/bin",
|
||||
"active_cmd": "play,random_play,playlocal,play_music_list,stop",
|
||||
"exclude_dirs": "@eaDir",
|
||||
"music_path_depth": 10,
|
||||
"disable_httpauth": true,
|
||||
"httpauth_username": "admin",
|
||||
"httpauth_password": "admin",
|
||||
"music_list_url": "",
|
||||
"music_list_json": "",
|
||||
"disable_download": false,
|
||||
"use_music_api": false,
|
||||
"log_file": "/tmp/xiaomusic.txt",
|
||||
"fuzzy_match_cutoff": 0.6,
|
||||
"enable_fuzzy_match": true,
|
||||
"stop_tts_msg": "收到,再见",
|
||||
"keywords_playlocal": "播放本地歌曲,本地播放歌曲",
|
||||
"keywords_play": "播放歌曲,放歌曲",
|
||||
"keywords_stop": "关机,暂停,停止,停止播放"
|
||||
"account": "",
|
||||
"password": "",
|
||||
"mi_did": "",
|
||||
"cookie": "",
|
||||
"verbose": false,
|
||||
"music_path": "music",
|
||||
"download_path": "",
|
||||
"conf_path": null,
|
||||
"hostname": "192.168.2.5",
|
||||
"port": 8090,
|
||||
"public_port": 0,
|
||||
"proxy": null,
|
||||
"search_prefix": "bilisearch:",
|
||||
"ffmpeg_location": "./ffmpeg/bin",
|
||||
"active_cmd": "play,set_random_play,playlocal,play_music_list,stop",
|
||||
"exclude_dirs": "@eaDir",
|
||||
"music_path_depth": 10,
|
||||
"disable_httpauth": true,
|
||||
"httpauth_username": "",
|
||||
"httpauth_password": "",
|
||||
"music_list_url": "",
|
||||
"music_list_json": "",
|
||||
"disable_download": false,
|
||||
"key_word_dict": {
|
||||
"播放歌曲": "play",
|
||||
"播放本地歌曲": "playlocal",
|
||||
"关机": "stop",
|
||||
"下一首": "play_next",
|
||||
"单曲循环": "set_play_type_one",
|
||||
"全部循环": "set_play_type_all",
|
||||
"随机播放": "set_random_play",
|
||||
"分钟后关机": "stop_after_minute",
|
||||
"播放列表": "play_music_list",
|
||||
"刷新列表": "gen_music_list",
|
||||
"本地播放歌曲": "playlocal",
|
||||
"放歌曲": "play",
|
||||
"暂停": "stop",
|
||||
"停止": "stop",
|
||||
"停止播放": "stop",
|
||||
"测试自定义口令": "exec#code1(\"hello\")",
|
||||
"测试链接": "exec#httpget(\"https://github.com/hanxi/xiaomusic\")"
|
||||
},
|
||||
"key_match_order": [
|
||||
"分钟后关机",
|
||||
"播放歌曲",
|
||||
"下一首",
|
||||
"单曲循环",
|
||||
"全部循环",
|
||||
"随机播放",
|
||||
"关机",
|
||||
"刷新列表",
|
||||
"播放列表",
|
||||
"播放本地歌曲",
|
||||
"本地播放歌曲",
|
||||
"放歌曲",
|
||||
"暂停",
|
||||
"停止",
|
||||
"停止播放",
|
||||
"测试自定义口令",
|
||||
"测试链接"
|
||||
],
|
||||
"use_music_api": false,
|
||||
"use_music_audio_id": "1582971365183456177",
|
||||
"use_music_id": "355454500",
|
||||
"log_file": "/tmp/xiaomusic.txt",
|
||||
"fuzzy_match_cutoff": 0.6,
|
||||
"enable_fuzzy_match": true,
|
||||
"stop_tts_msg": "收到,再见",
|
||||
"enable_config_example": true,
|
||||
"keywords_playlocal": "播放本地歌曲,本地播放歌曲",
|
||||
"keywords_play": "播放歌曲,放歌曲",
|
||||
"keywords_stop": "关机,暂停,停止,停止播放",
|
||||
"user_key_word_dict": {
|
||||
"测试自定义口令": "exec#code1(\"hello\")",
|
||||
"测试链接": "exec#httpget(\"https://github.com/hanxi/xiaomusic\")"
|
||||
},
|
||||
"enable_force_stop": false,
|
||||
"devices": {},
|
||||
"group_list": ""
|
||||
}
|
||||
@@ -9,36 +9,42 @@ arch=$(uname -m)
|
||||
# 输出架构信息
|
||||
echo "当前系统架构是:$arch"
|
||||
|
||||
install_from_build() {
|
||||
install_from_github() {
|
||||
pkg=$1
|
||||
wget https://github.com/yt-dlp/FFmpeg-Builds/releases/download/latest/$pkg.tar.xz
|
||||
tar -xvJf $pkg.tar.xz
|
||||
mv $pkg ffmpeg
|
||||
mkdir -p ffmpeg/bin
|
||||
mv $pkg/bin/ffmpeg ffmpeg/bin/
|
||||
mv $pkg/bin/ffprobe ffmpeg/bin/
|
||||
}
|
||||
|
||||
install_from_apt() {
|
||||
apt-get update
|
||||
apt-get install -y ffmpeg
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
mkdir -p /app/ffmpeg/bin
|
||||
ln -s /usr/bin/ffmpeg /app/ffmpeg/bin/ffmpeg
|
||||
ln -s /usr/bin/ffprobe /app/ffmpeg/bin/ffprobe
|
||||
install_from_ffmpeg() {
|
||||
pkg=$1
|
||||
wget https://johnvansickle.com/ffmpeg/builds/$pkg.tar.xz
|
||||
mkdir -p $pkg
|
||||
tar -xvJf $pkg.tar.xz -C $pkg
|
||||
mkdir -p ffmpeg/bin
|
||||
mv $pkg/*/ffmpeg ffmpeg/bin/
|
||||
mv $pkg/*/ffprobe ffmpeg/bin/
|
||||
}
|
||||
|
||||
# 基于架构执行不同的操作
|
||||
case "$arch" in
|
||||
x86_64)
|
||||
echo "64位 x86 架构"
|
||||
pkg=ffmpeg-master-latest-linux64-gpl
|
||||
install_from_build "$pkg"
|
||||
install_from_github ffmpeg-master-latest-linux64-gpl
|
||||
#install_from_ffmpeg ffmpeg-git-amd64-static
|
||||
;;
|
||||
arm64 | aarch64)
|
||||
echo "64位 ARM 架构"
|
||||
pkg=ffmpeg-master-latest-linuxarm64-gpl
|
||||
install_from_build "$pkg"
|
||||
install_from_github ffmpeg-master-latest-linuxarm64-gpl
|
||||
#install_from_ffmpeg ffmpeg-git-arm64-static
|
||||
;;
|
||||
armv7l)
|
||||
echo "armv7l 架构"
|
||||
install_from_ffmpeg ffmpeg-git-armhf-static
|
||||
;;
|
||||
*)
|
||||
echo "未知架构 $arch"
|
||||
install_from_apt
|
||||
;;
|
||||
esac
|
||||
|
||||
9
newpatch.sh
Executable file
9
newpatch.sh
Executable file
@@ -0,0 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
./update-static-version.py
|
||||
git add xiaomusic/static
|
||||
git commit -m 'build: update static version'
|
||||
|
||||
cz bump --check-consistency --increment patch
|
||||
|
||||
git push -u origin main --tags
|
||||
@@ -1,37 +1,9 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
./update-static-version.py
|
||||
git add xiaomusic/static
|
||||
git commit -m 'build: update static version'
|
||||
|
||||
version_file=./pyproject.toml
|
||||
init_file=./xiaomusic/__init__.py
|
||||
# 获取当前版本号
|
||||
current_version=$(grep -oE "version = \"[0-9]+\.[0-9]+\.[0-9]+\"" $version_file | cut -d'"' -f2)
|
||||
echo "当前版本号: "$current_version
|
||||
cz bump --check-consistency
|
||||
|
||||
# 将版本号分割成三部分
|
||||
major=$(echo $current_version | cut -d'.' -f1)
|
||||
minor=$(echo $current_version | cut -d'.' -f2)
|
||||
patch=$(echo $current_version | cut -d'.' -f3)
|
||||
|
||||
echo "major: $major"
|
||||
echo "minor: $minor"
|
||||
echo "patch: $patch"
|
||||
|
||||
# 将补丁号加1
|
||||
patch=$((patch + 1))
|
||||
|
||||
# 生成新版本号
|
||||
new_version="$major.$minor.$patch"
|
||||
|
||||
# 将新版本号写入文件
|
||||
sed -i "s/version.*/version = \"$new_version\"/g" $version_file
|
||||
sed -i "s/__version__.*/__version__ = \"$new_version\"/g" $init_file
|
||||
|
||||
echo "新版本号:$new_version"
|
||||
|
||||
git diff
|
||||
git add $version_file
|
||||
git add $init_file
|
||||
git commit -m "new version v$new_version"
|
||||
git tag v$new_version
|
||||
git push -u origin main --tags
|
||||
|
||||
0
plugins/__init__.py
Normal file
0
plugins/__init__.py
Normal file
4
plugins/code1.py
Normal file
4
plugins/code1.py
Normal file
@@ -0,0 +1,4 @@
|
||||
async def code1(arg1):
|
||||
global log, xiaomusic
|
||||
log.info(f"code1:{arg1}")
|
||||
await xiaomusic.do_tts("你好,我是自定义的测试口令")
|
||||
10
plugins/httpget.py
Normal file
10
plugins/httpget.py
Normal file
@@ -0,0 +1,10 @@
|
||||
import requests
|
||||
|
||||
|
||||
def httpget(url):
|
||||
global log
|
||||
|
||||
# 发起请求
|
||||
response = requests.get(url, timeout=5) # 增加超时以避免长时间挂起
|
||||
response.raise_for_status() # 如果响应不是200,引发HTTPError异常
|
||||
log.info(f"httpget url:{url} response:{response.text}")
|
||||
@@ -1,19 +1,18 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.1.87"
|
||||
version = "0.3.11"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
]
|
||||
dependencies = [
|
||||
"requests==2.31.0",
|
||||
"aiohttp>=3.8.6",
|
||||
"miservice-fork>=2.5.0",
|
||||
"miservice-fork>=2.7.0",
|
||||
"mutagen>=1.47.0",
|
||||
"yt-dlp>=2024.04.09",
|
||||
"flask[async]>=3.0.1",
|
||||
"waitress>=3.0.0",
|
||||
"flask-HTTPAuth>=4.8.0",
|
||||
"yt-dlp>=2024.07.01",
|
||||
"uvicorn>=0.30.1",
|
||||
"fastapi>=0.111.0",
|
||||
"starlette>=0.37.2",
|
||||
]
|
||||
requires-python = ">=3.10"
|
||||
readme = "README.md"
|
||||
@@ -34,25 +33,42 @@ build-backend = "pdm.backend"
|
||||
lint = [
|
||||
"ruff>=0.4.8",
|
||||
]
|
||||
dev = [
|
||||
"commitizen>=3.27.0",
|
||||
]
|
||||
[tool.ruff]
|
||||
lint.select = [
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"E", # pycodestyle - Error
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
"W", # pycodestyle - Warning
|
||||
"UP", # pyupgrade
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"E", # pycodestyle - Error
|
||||
"F", # Pyflakes
|
||||
"I", # isort
|
||||
"W", # pycodestyle - Warning
|
||||
"UP", # pyupgrade
|
||||
]
|
||||
lint.ignore = [
|
||||
"E501", # line-too-long
|
||||
"W191", # tab-indentation
|
||||
"E501", # line-too-long
|
||||
"W191", # tab-indentation
|
||||
]
|
||||
include = ["**/*.py", "**/*.pyi", "**/pyproject.toml"]
|
||||
|
||||
[tool.ruff.lint.pydocstyle]
|
||||
convention = "google"
|
||||
|
||||
[tool.ruff.lint.flake8-bugbear]
|
||||
extend-immutable-calls = ["fastapi.Depends", "fastapi.params.Depends", "fastapi.Query", "fastapi.params.Query"]
|
||||
|
||||
[tool.pdm.scripts]
|
||||
lint = "ruff check ."
|
||||
fmt = "ruff format ."
|
||||
|
||||
[tool.commitizen]
|
||||
name = "cz_conventional_commits"
|
||||
tag_format = "v$version"
|
||||
version_scheme = "pep440"
|
||||
version_provider = "pep621"
|
||||
update_changelog_on_bump = true
|
||||
major_version_zero = true
|
||||
version_files = [
|
||||
"xiaomusic/__init__.py",
|
||||
]
|
||||
|
||||
872
requirements.txt
872
requirements.txt
@@ -2,67 +2,23 @@
|
||||
# Please do not edit it manually.
|
||||
|
||||
aiohttp==3.9.5 \
|
||||
--hash=sha256:0a158704edf0abcac8ac371fbb54044f3270bdbc93e254a82b6c82be1ef08f3c \
|
||||
--hash=sha256:18f634d540dd099c262e9f887c8bbacc959847cfe5da7a0e2e1cf3f14dbf2daf \
|
||||
--hash=sha256:2faa61a904b83142747fc6a6d7ad8fccff898c849123030f8e75d5d967fd4a81 \
|
||||
--hash=sha256:320e8618eda64e19d11bdb3bd04ccc0a816c17eaecb7e4945d01deee2a22f95f \
|
||||
--hash=sha256:393c7aba2b55559ef7ab791c94b44f7482a07bf7640d17b341b79081f5e5cd1a \
|
||||
--hash=sha256:4715a9b778f4293b9f8ae7a0a7cef9829f02ff8d6277a39d7f40565c737d3771 \
|
||||
--hash=sha256:471f0ef53ccedec9995287f02caf0c068732f026455f07db3f01a46e49d76bbb \
|
||||
--hash=sha256:4d3ebb9e1316ec74277d19c5f482f98cc65a73ccd5430540d6d11682cd857430 \
|
||||
--hash=sha256:4ff550491f5492ab5ed3533e76b8567f4b37bd2995e780a1f46bca2024223233 \
|
||||
--hash=sha256:55b39c8684a46e56ef8c8d24faf02de4a2b2ac60d26cee93bc595651ff545de9 \
|
||||
--hash=sha256:5a7ee16aab26e76add4afc45e8f8206c95d1d75540f1039b84a03c3b3800dd59 \
|
||||
--hash=sha256:5ca51eadbd67045396bc92a4345d1790b7301c14d1848feaac1d6a6c9289e888 \
|
||||
--hash=sha256:5d6b3f1fabe465e819aed2c421a6743d8debbde79b6a8600739300630a01bf2c \
|
||||
--hash=sha256:60cdbd56f4cad9f69c35eaac0fbbdf1f77b0ff9456cebd4902f3dd1cf096464c \
|
||||
--hash=sha256:639d0042b7670222f33b0028de6b4e2fad6451462ce7df2af8aee37dcac55424 \
|
||||
--hash=sha256:66331d00fb28dc90aa606d9a54304af76b335ae204d1836f65797d6fe27f1ca2 \
|
||||
--hash=sha256:67c3119f5ddc7261d47163ed86d760ddf0e625cd6246b4ed852e82159617b5fb \
|
||||
--hash=sha256:6ae79c1bc12c34082d92bf9422764f799aee4746fd7a392db46b7fd357d4a17a \
|
||||
--hash=sha256:702e2c7c187c1a498a4e2b03155d52658fdd6fda882d3d7fbb891a5cf108bb10 \
|
||||
--hash=sha256:714d4e5231fed4ba2762ed489b4aec07b2b9953cf4ee31e9871caac895a839c0 \
|
||||
--hash=sha256:82a6a97d9771cb48ae16979c3a3a9a18b600a8505b1115cfe354dfb2054468b4 \
|
||||
--hash=sha256:84dabd95154f43a2ea80deffec9cb44d2e301e38a0c9d331cc4aa0166fe28ae3 \
|
||||
--hash=sha256:8676e8fd73141ded15ea586de0b7cda1542960a7b9ad89b2b06428e97125d4fa \
|
||||
--hash=sha256:88e311d98cc0bf45b62fc46c66753a83445f5ab20038bcc1b8a1cc05666f428a \
|
||||
--hash=sha256:8c64a6dc3fe5db7b1b4d2b5cb84c4f677768bdc340611eca673afb7cf416ef5a \
|
||||
--hash=sha256:93e22add827447d2e26d67c9ac0161756007f152fdc5210277d00a85f6c92323 \
|
||||
--hash=sha256:a81b1143d42b66ffc40a441379387076243ef7b51019204fd3ec36b9f69e77d6 \
|
||||
--hash=sha256:ad7f2919d7dac062f24d6f5fe95d401597fbb015a25771f85e692d043c9d7832 \
|
||||
--hash=sha256:afc52b8d969eff14e069a710057d15ab9ac17cd4b6753042c407dcea0e40bf75 \
|
||||
--hash=sha256:b3df71da99c98534be076196791adca8819761f0bf6e08e07fd7da25127150d6 \
|
||||
--hash=sha256:c088c4d70d21f8ca5c0b8b5403fe84a7bc8e024161febdd4ef04575ef35d474d \
|
||||
--hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \
|
||||
--hash=sha256:c413016880e03e69d166efb5a1a95d40f83d5a3a648d16486592c49ffb76d0db \
|
||||
--hash=sha256:c671dc117c2c21a1ca10c116cfcd6e3e44da7fcde37bf83b2be485ab377b25da \
|
||||
--hash=sha256:c7a4b7a6cf5b6eb11e109a9755fd4fda7d57395f8c575e166d363b9fc3ec4678 \
|
||||
--hash=sha256:c8a02fbeca6f63cb1f0475c799679057fc9268b77075ab7cf3f1c600e81dd46b \
|
||||
--hash=sha256:d153f652a687a8e95ad367a86a61e8d53d528b0530ef382ec5aaf533140ed00f \
|
||||
--hash=sha256:da00da442a0e31f1c69d26d224e1efd3a1ca5bcbf210978a2ca7426dfcae9f58 \
|
||||
--hash=sha256:e0ae53e33ee7476dd3d1132f932eeb39bf6125083820049d06edcdca4381f342 \
|
||||
--hash=sha256:e7a6a8354f1b62e15d48e04350f13e726fa08b62c3d7b8401c0a1314f02e3558 \
|
||||
--hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551 \
|
||||
--hash=sha256:f22eb3a6c1080d862befa0a89c380b4dafce29dc6cd56083f630073d102eb595 \
|
||||
--hash=sha256:f26383adb94da5e7fb388d441bf09c61e5e35f455a3217bfd790c6b6bc64b2ee \
|
||||
--hash=sha256:f64fd07515dad67f24b6ea4a66ae2876c01031de91c93075b8093f07c0a2d93d \
|
||||
--hash=sha256:fcde4c397f673fdec23e6b05ebf8d4751314fa7c24f93334bf1f1364c1c69ac7 \
|
||||
--hash=sha256:ff84aeb864e0fac81f676be9f4685f0527b660f1efdc40dcede3c251ef1e867f
|
||||
--hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551
|
||||
aiosignal==1.3.1 \
|
||||
--hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \
|
||||
--hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17
|
||||
asgiref==3.7.2 \
|
||||
--hash=sha256:89b2ef2247e3b562a16eef663bc0e2e703ec6468e2fa8a5cd61cd449786d4f6e \
|
||||
--hash=sha256:9e0ce3aa93a819ba5b45120216b23878cf6e8525eb3848653452b4192b92afed
|
||||
annotated-types==0.7.0 \
|
||||
--hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
|
||||
--hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
|
||||
anyio==4.4.0 \
|
||||
--hash=sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94 \
|
||||
--hash=sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7
|
||||
async-timeout==4.0.3; python_version < "3.11" \
|
||||
--hash=sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f \
|
||||
--hash=sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028
|
||||
attrs==23.1.0 \
|
||||
--hash=sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04 \
|
||||
--hash=sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015
|
||||
blinker==1.7.0 \
|
||||
--hash=sha256:c3f865d4d54db7abc53758a01601cf343fe55b84c1de4e3fa910e420b438d5b9 \
|
||||
--hash=sha256:e6820ff6fa4e4d1d8e2747c2283749c3f547e4fee112b98555cdcdae32996182
|
||||
attrs==23.2.0 \
|
||||
--hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \
|
||||
--hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
|
||||
brotli==1.1.0; implementation_name == "cpython" \
|
||||
--hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \
|
||||
--hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \
|
||||
@@ -101,309 +57,471 @@ brotli==1.1.0; implementation_name == "cpython" \
|
||||
--hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \
|
||||
--hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \
|
||||
--hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e
|
||||
brotlicffi==1.1.0.0; implementation_name != "cpython" \
|
||||
--hash=sha256:19ffc919fa4fc6ace69286e0a23b3789b4219058313cf9b45625016bf7ff996b \
|
||||
--hash=sha256:1a807d760763e398bbf2c6394ae9da5815901aa93ee0a37bca5efe78d4ee3171 \
|
||||
--hash=sha256:1b12b50e07c3911e1efa3a8971543e7648100713d4e0971b13631cce22c587eb \
|
||||
--hash=sha256:246f1d1a90279bb6069de3de8d75a8856e073b8ff0b09dcca18ccc14cec85979 \
|
||||
--hash=sha256:2a7ae37e5d79c5bdfb5b4b99f2715a6035e6c5bf538c3746abc8e26694f92f33 \
|
||||
--hash=sha256:2e4aeb0bd2540cb91b069dbdd54d458da8c4334ceaf2d25df2f4af576d6766ca \
|
||||
--hash=sha256:2f3711be9290f0453de8eed5275d93d286abe26b08ab4a35d7452caa1fef532f \
|
||||
--hash=sha256:37c26ecb14386a44b118ce36e546ce307f4810bc9598a6e6cb4f7fca725ae7e6 \
|
||||
--hash=sha256:391151ec86bb1c683835980f4816272a87eaddc46bb91cbf44f62228b84d8cca \
|
||||
--hash=sha256:3de0cf28a53a3238b252aca9fed1593e9d36c1d116748013339f0949bfc84112 \
|
||||
--hash=sha256:4b7b0033b0d37bb33009fb2fef73310e432e76f688af76c156b3594389d81391 \
|
||||
--hash=sha256:54a07bb2374a1eba8ebb52b6fafffa2afd3c4df85ddd38fcc0511f2bb387c2a8 \
|
||||
--hash=sha256:6be5ec0e88a4925c91f3dea2bb0013b3a2accda6f77238f76a34a1ea532a1cb0 \
|
||||
--hash=sha256:7901a7dc4b88f1c1475de59ae9be59799db1007b7d059817948d8e4f12e24e35 \
|
||||
--hash=sha256:84763dbdef5dd5c24b75597a77e1b30c66604725707565188ba54bab4f114820 \
|
||||
--hash=sha256:8557a8559509b61e65083f8782329188a250102372576093c88930c875a69838 \
|
||||
--hash=sha256:994a4f0681bb6c6c3b0925530a1926b7a189d878e6e5e38fae8efa47c5d9c613 \
|
||||
--hash=sha256:9b6068e0f3769992d6b622a1cd2e7835eae3cf8d9da123d7f51ca9c1e9c333e5 \
|
||||
--hash=sha256:9b7ae6bd1a3f0df532b6d67ff674099a96d22bc0948955cb338488c31bfb8851 \
|
||||
--hash=sha256:9feb210d932ffe7798ee62e6145d3a757eb6233aa9a4e7db78dd3690d7755814 \
|
||||
--hash=sha256:add0de5b9ad9e9aa293c3aa4e9deb2b61e99ad6c1634e01d01d98c03e6a354cc \
|
||||
--hash=sha256:b77827a689905143f87915310b93b273ab17888fd43ef350d4832c4a71083c13 \
|
||||
--hash=sha256:ca72968ae4eaf6470498d5c2887073f7efe3b1e7d7ec8be11a06a79cc810e990 \
|
||||
--hash=sha256:cc4bc5d82bc56ebd8b514fb8350cfac4627d6b0743382e46d033976a5f80fab6 \
|
||||
--hash=sha256:ce01c7316aebc7fce59da734286148b1d1b9455f89cf2c8a4dfce7d41db55c2d \
|
||||
--hash=sha256:d9eb71bb1085d996244439154387266fd23d6ad37161f6f52f1cd41dd95a3808 \
|
||||
--hash=sha256:fa8ca0623b26c94fccc3a1fdd895be1743b838f3917300506d04aa3346fd2a14
|
||||
certifi==2023.7.22 \
|
||||
--hash=sha256:539cc1d13202e33ca466e88b2807e29f4c13049d6d87031a3c110744495cb082 \
|
||||
--hash=sha256:92d6037539857d8206b8f6ae472e8b77db8058fec5937a1ef3f54304089edbb9
|
||||
cffi==1.16.0; implementation_name != "cpython" \
|
||||
--hash=sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417 \
|
||||
--hash=sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab \
|
||||
--hash=sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520 \
|
||||
--hash=sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743 \
|
||||
--hash=sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684 \
|
||||
--hash=sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56 \
|
||||
--hash=sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d \
|
||||
--hash=sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235 \
|
||||
--hash=sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e \
|
||||
--hash=sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088 \
|
||||
--hash=sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7 \
|
||||
--hash=sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e \
|
||||
--hash=sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673 \
|
||||
--hash=sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2 \
|
||||
--hash=sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a \
|
||||
--hash=sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896 \
|
||||
--hash=sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e \
|
||||
--hash=sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9 \
|
||||
--hash=sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b \
|
||||
--hash=sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6 \
|
||||
--hash=sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404 \
|
||||
--hash=sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0 \
|
||||
--hash=sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc \
|
||||
--hash=sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936 \
|
||||
--hash=sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba \
|
||||
--hash=sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb \
|
||||
--hash=sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614 \
|
||||
--hash=sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1 \
|
||||
--hash=sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d \
|
||||
--hash=sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969 \
|
||||
--hash=sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627 \
|
||||
--hash=sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956 \
|
||||
--hash=sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357
|
||||
charset-normalizer==3.3.0 \
|
||||
--hash=sha256:02af06682e3590ab952599fbadac535ede5d60d78848e555aa58d0c0abbde786 \
|
||||
--hash=sha256:03680bb39035fbcffe828eae9c3f8afc0428c91d38e7d61aa992ef7a59fb120e \
|
||||
--hash=sha256:0570d21da019941634a531444364f2482e8db0b3425fcd5ac0c36565a64142c8 \
|
||||
--hash=sha256:0d3d5b7db9ed8a2b11a774db2bbea7ba1884430a205dbd54a32d61d7c2a190fa \
|
||||
--hash=sha256:1872d01ac8c618a8da634e232f24793883d6e456a66593135aeafe3784b0848d \
|
||||
--hash=sha256:1b2919306936ac6efb3aed1fbf81039f7087ddadb3160882a57ee2ff74fd2382 \
|
||||
--hash=sha256:232ac332403e37e4a03d209a3f92ed9071f7d3dbda70e2a5e9cff1c4ba9f0678 \
|
||||
--hash=sha256:23e8565ab7ff33218530bc817922fae827420f143479b753104ab801145b1d5b \
|
||||
--hash=sha256:24817cb02cbef7cd499f7c9a2735286b4782bd47a5b3516a0e84c50eab44b98e \
|
||||
--hash=sha256:2502dd2a736c879c0f0d3e2161e74d9907231e25d35794584b1ca5284e43f596 \
|
||||
--hash=sha256:278c296c6f96fa686d74eb449ea1697f3c03dc28b75f873b65b5201806346a69 \
|
||||
--hash=sha256:2935ffc78db9645cb2086c2f8f4cfd23d9b73cc0dc80334bc30aac6f03f68f8c \
|
||||
--hash=sha256:380c4bde80bce25c6e4f77b19386f5ec9db230df9f2f2ac1e5ad7af2caa70459 \
|
||||
--hash=sha256:3b447982ad46348c02cb90d230b75ac34e9886273df3a93eec0539308a6296d7 \
|
||||
--hash=sha256:3debd1150027933210c2fc321527c2299118aa929c2f5a0a80ab6953e3bd1908 \
|
||||
--hash=sha256:4162918ef3098851fcd8a628bf9b6a98d10c380725df9e04caf5ca6dd48c847a \
|
||||
--hash=sha256:4cc152c5dd831641e995764f9f0b6589519f6f5123258ccaca8c6d34572fefa8 \
|
||||
--hash=sha256:557b21a44ceac6c6b9773bc65aa1b4cc3e248a5ad2f5b914b91579a32e22204d \
|
||||
--hash=sha256:5707a746c6083a3a74b46b3a631d78d129edab06195a92a8ece755aac25a3f3d \
|
||||
--hash=sha256:5adf257bd58c1b8632046bbe43ee38c04e1038e9d37de9c57a94d6bd6ce5da34 \
|
||||
--hash=sha256:63563193aec44bce707e0c5ca64ff69fa72ed7cf34ce6e11d5127555756fd2f6 \
|
||||
--hash=sha256:6a685067d05e46641d5d1623d7c7fdf15a357546cbb2f71b0ebde91b175ffc3e \
|
||||
--hash=sha256:7b8b8bf1189b3ba9b8de5c8db4d541b406611a71a955bbbd7385bbc45fcb786c \
|
||||
--hash=sha256:82eb849f085624f6a607538ee7b83a6d8126df6d2f7d3b319cb837b289123078 \
|
||||
--hash=sha256:86d1f65ac145e2c9ed71d8ffb1905e9bba3a91ae29ba55b4c46ae6fc31d7c0d4 \
|
||||
--hash=sha256:86f63face3a527284f7bb8a9d4f78988e3c06823f7bea2bd6f0e0e9298ca0403 \
|
||||
--hash=sha256:8eaf82f0eccd1505cf39a45a6bd0a8cf1c70dcfc30dba338207a969d91b965c0 \
|
||||
--hash=sha256:9cf3126b85822c4e53aa28c7ec9869b924d6fcfb76e77a45c44b83d91afd74f9 \
|
||||
--hash=sha256:9fe359b2e3a7729010060fbca442ca225280c16e923b37db0e955ac2a2b72a05 \
|
||||
--hash=sha256:a3f93dab657839dfa61025056606600a11d0b696d79386f974e459a3fbc568ec \
|
||||
--hash=sha256:a4b71f4d1765639372a3b32d2638197f5cd5221b19531f9245fcc9ee62d38f56 \
|
||||
--hash=sha256:abf0d9f45ea5fb95051c8bfe43cb40cda383772f7e5023a83cc481ca2604d74e \
|
||||
--hash=sha256:b09719a17a2301178fac4470d54b1680b18a5048b481cb8890e1ef820cb80455 \
|
||||
--hash=sha256:b3b2316b25644b23b54a6f6401074cebcecd1244c0b8e80111c9a3f1c8e83d65 \
|
||||
--hash=sha256:b3d9b48ee6e3967b7901c052b670c7dda6deb812c309439adaffdec55c6d7b78 \
|
||||
--hash=sha256:b8f3307af845803fb0b060ab76cf6dd3a13adc15b6b451f54281d25911eb92df \
|
||||
--hash=sha256:c350354efb159b8767a6244c166f66e67506e06c8924ed74669b2c70bc8735b1 \
|
||||
--hash=sha256:c71f16da1ed8949774ef79f4a0260d28b83b3a50c6576f8f4f0288d109777989 \
|
||||
--hash=sha256:d7eff0f27edc5afa9e405f7165f85a6d782d308f3b6b9d96016c010597958e63 \
|
||||
--hash=sha256:db756e48f9c5c607b5e33dd36b1d5872d0422e960145b08ab0ec7fd420e9d649 \
|
||||
--hash=sha256:e46cd37076971c1040fc8c41273a8b3e2c624ce4f2be3f5dfcb7a430c1d3acc2 \
|
||||
--hash=sha256:e5c1502d4ace69a179305abb3f0bb6141cbe4714bc9b31d427329a95acfc8bdd \
|
||||
--hash=sha256:edfe077ab09442d4ef3c52cb1f9dab89bff02f4524afc0acf2d46be17dc479f5 \
|
||||
--hash=sha256:effe5406c9bd748a871dbcaf3ac69167c38d72db8c9baf3ff954c344f31c4cbe \
|
||||
--hash=sha256:f0d1e3732768fecb052d90d62b220af62ead5748ac51ef61e7b32c266cac9293 \
|
||||
--hash=sha256:f5969baeaea61c97efa706b9b107dcba02784b1601c74ac84f2a532ea079403e \
|
||||
--hash=sha256:f8888e31e3a85943743f8fc15e71536bda1c81d5aa36d014a3c0c44481d7db6e
|
||||
certifi==2024.7.4 \
|
||||
--hash=sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b \
|
||||
--hash=sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90
|
||||
charset-normalizer==3.3.2 \
|
||||
--hash=sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027 \
|
||||
--hash=sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8 \
|
||||
--hash=sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09 \
|
||||
--hash=sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574 \
|
||||
--hash=sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e \
|
||||
--hash=sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3 \
|
||||
--hash=sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f \
|
||||
--hash=sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73 \
|
||||
--hash=sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc \
|
||||
--hash=sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc \
|
||||
--hash=sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce \
|
||||
--hash=sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e \
|
||||
--hash=sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6 \
|
||||
--hash=sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269 \
|
||||
--hash=sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96 \
|
||||
--hash=sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4 \
|
||||
--hash=sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77 \
|
||||
--hash=sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d \
|
||||
--hash=sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed \
|
||||
--hash=sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068 \
|
||||
--hash=sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8 \
|
||||
--hash=sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab \
|
||||
--hash=sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26 \
|
||||
--hash=sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db \
|
||||
--hash=sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f \
|
||||
--hash=sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5 \
|
||||
--hash=sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d \
|
||||
--hash=sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa \
|
||||
--hash=sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a \
|
||||
--hash=sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03 \
|
||||
--hash=sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b \
|
||||
--hash=sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001 \
|
||||
--hash=sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389 \
|
||||
--hash=sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537 \
|
||||
--hash=sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143 \
|
||||
--hash=sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c \
|
||||
--hash=sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6 \
|
||||
--hash=sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7 \
|
||||
--hash=sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b \
|
||||
--hash=sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae \
|
||||
--hash=sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12 \
|
||||
--hash=sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae \
|
||||
--hash=sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887 \
|
||||
--hash=sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4 \
|
||||
--hash=sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f \
|
||||
--hash=sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5 \
|
||||
--hash=sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519
|
||||
click==8.1.7 \
|
||||
--hash=sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28 \
|
||||
--hash=sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de
|
||||
colorama==0.4.6; platform_system == "Windows" \
|
||||
--hash=sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44 \
|
||||
--hash=sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6
|
||||
flask==3.0.3 \
|
||||
--hash=sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3 \
|
||||
--hash=sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842
|
||||
flask-HTTPAuth==4.8.0 \
|
||||
--hash=sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a \
|
||||
--hash=sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0
|
||||
frozenlist==1.4.0 \
|
||||
--hash=sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01 \
|
||||
--hash=sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251 \
|
||||
--hash=sha256:0c7c1b47859ee2cac3846fde1c1dc0f15da6cec5a0e5c72d101e0f83dcb67ff9 \
|
||||
--hash=sha256:0e5c8764c7829343d919cc2dfc587a8db01c4f70a4ebbc49abde5d4b158b007b \
|
||||
--hash=sha256:1a0848b52815006ea6596c395f87449f693dc419061cc21e970f139d466dc0a0 \
|
||||
--hash=sha256:261b9f5d17cac914531331ff1b1d452125bf5daa05faf73b71d935485b0c510b \
|
||||
--hash=sha256:38461d02d66de17455072c9ba981d35f1d2a73024bee7790ac2f9e361ef1cd0c \
|
||||
--hash=sha256:490132667476f6781b4c9458298b0c1cddf237488abd228b0b3650e5ecba7467 \
|
||||
--hash=sha256:515e1abc578dd3b275d6a5114030b1330ba044ffba03f94091842852f806f1c1 \
|
||||
--hash=sha256:6918d49b1f90821e93069682c06ffde41829c346c66b721e65a5c62b4bab0300 \
|
||||
--hash=sha256:71932b597f9895f011f47f17d6428252fc728ba2ae6024e13c3398a087c2cdea \
|
||||
--hash=sha256:764226ceef3125e53ea2cb275000e309c0aa5464d43bd72abd661e27fffc26ab \
|
||||
--hash=sha256:76d4711f6f6d08551a7e9ef28c722f4a50dd0fc204c56b4bcd95c6cc05ce6fbb \
|
||||
--hash=sha256:8d0edd6b1c7fb94922bf569c9b092ee187a83f03fb1a63076e7774b60f9481a8 \
|
||||
--hash=sha256:901289d524fdd571be1c7be054f48b1f88ce8dddcbdf1ec698b27d4b8b9e5d62 \
|
||||
--hash=sha256:981b9ab5a0a3178ff413bca62526bb784249421c24ad7381e39d67981be2c326 \
|
||||
--hash=sha256:9ac08e601308e41eb533f232dbf6b7e4cea762f9f84f6357136eed926c15d12c \
|
||||
--hash=sha256:a02eb8ab2b8f200179b5f62b59757685ae9987996ae549ccf30f983f40602431 \
|
||||
--hash=sha256:ad2a9eb6d9839ae241701d0918f54c51365a51407fd80f6b8289e2dfca977cc3 \
|
||||
--hash=sha256:b206646d176a007466358aa21d85cd8600a415c67c9bd15403336c331a10d956 \
|
||||
--hash=sha256:b89ac9768b82205936771f8d2eb3ce88503b1556324c9f903e7156669f521472 \
|
||||
--hash=sha256:bd7bd3b3830247580de99c99ea2a01416dfc3c34471ca1298bccabf86d0ff4dc \
|
||||
--hash=sha256:bdf1847068c362f16b353163391210269e4f0569a3c166bc6a9f74ccbfc7e839 \
|
||||
--hash=sha256:d081f13b095d74b67d550de04df1c756831f3b83dc9881c38985834387487f1b \
|
||||
--hash=sha256:d5a32087d720c608f42caed0ef36d2b3ea61a9d09ee59a5142d6070da9041b8f \
|
||||
--hash=sha256:d6484756b12f40003c6128bfcc3fa9f0d49a687e171186c2d85ec82e3758c559 \
|
||||
--hash=sha256:dd65632acaf0d47608190a71bfe46b209719bf2beb59507db08ccdbe712f969b \
|
||||
--hash=sha256:de343e75f40e972bae1ef6090267f8260c1446a1695e77096db6cfa25e759a95 \
|
||||
--hash=sha256:e29cda763f752553fa14c68fb2195150bfab22b352572cb36c43c47bedba70eb \
|
||||
--hash=sha256:e41f3de4df3e80de75845d3e743b3f1c4c8613c3997a912dbf0229fc61a8b963 \
|
||||
--hash=sha256:e74b0506fa5aa5598ac6a975a12aa8928cbb58e1f5ac8360792ef15de1aa848f
|
||||
idna==3.4 \
|
||||
--hash=sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4 \
|
||||
--hash=sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2
|
||||
itsdangerous==2.1.2 \
|
||||
--hash=sha256:2c2349112351b88699d8d4b6b075022c0808887cb7ad10069318a8b0bc88db44 \
|
||||
--hash=sha256:5dbbc68b317e5e42f327f9021763545dc3fc3bfe22e6deb96aaf1fc38874156a
|
||||
Jinja2==3.1.3 \
|
||||
--hash=sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa \
|
||||
--hash=sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90
|
||||
dnspython==2.6.1 \
|
||||
--hash=sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50 \
|
||||
--hash=sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc
|
||||
email-validator==2.2.0 \
|
||||
--hash=sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631 \
|
||||
--hash=sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7
|
||||
exceptiongroup==1.2.2; python_version < "3.11" \
|
||||
--hash=sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b \
|
||||
--hash=sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc
|
||||
fastapi==0.111.1 \
|
||||
--hash=sha256:4f51cfa25d72f9fbc3280832e84b32494cf186f50158d364a8765aabf22587bf \
|
||||
--hash=sha256:ddd1ac34cb1f76c2e2d7f8545a4bcb5463bce4834e81abf0b189e0c359ab2413
|
||||
fastapi-cli==0.0.4 \
|
||||
--hash=sha256:a2552f3a7ae64058cdbb530be6fa6dbfc975dc165e4fa66d224c3d396e25e809 \
|
||||
--hash=sha256:e2e9ffaffc1f7767f488d6da34b6f5a377751c996f397902eb6abb99a67bde32
|
||||
frozenlist==1.4.1 \
|
||||
--hash=sha256:04ced3e6a46b4cfffe20f9ae482818e34eba9b5fb0ce4056e4cc9b6e212d09b7 \
|
||||
--hash=sha256:0633c8d5337cb5c77acbccc6357ac49a1770b8c487e5b3505c57b949b4b82e98 \
|
||||
--hash=sha256:068b63f23b17df8569b7fdca5517edef76171cf3897eb68beb01341131fbd2ad \
|
||||
--hash=sha256:1979bc0aeb89b33b588c51c54ab0161791149f2461ea7c7c946d95d5f93b56ae \
|
||||
--hash=sha256:1a4471094e146b6790f61b98616ab8e44f72661879cc63fa1049d13ef711e71e \
|
||||
--hash=sha256:1b280e6507ea8a4fa0c0a7150b4e526a8d113989e28eaaef946cc77ffd7efc0a \
|
||||
--hash=sha256:23b701e65c7b36e4bf15546a89279bd4d8675faabc287d06bbcfac7d3c33e1e6 \
|
||||
--hash=sha256:2471c201b70d58a0f0c1f91261542a03d9a5e088ed3dc6c160d614c01649c106 \
|
||||
--hash=sha256:27657df69e8801be6c3638054e202a135c7f299267f1a55ed3a598934f6c0d75 \
|
||||
--hash=sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868 \
|
||||
--hash=sha256:3e0153a805a98f5ada7e09826255ba99fb4f7524bb81bf6b47fb702666484ae1 \
|
||||
--hash=sha256:442acde1e068288a4ba7acfe05f5f343e19fac87bfc96d89eb886b0363e977ec \
|
||||
--hash=sha256:4f57dab5fe3407b6c0c1cc907ac98e8a189f9e418f3b6e54d65a718aaafe3950 \
|
||||
--hash=sha256:4f9c515e7914626b2a2e1e311794b4c35720a0be87af52b79ff8e1429fc25f19 \
|
||||
--hash=sha256:5667ed53d68d91920defdf4035d1cdaa3c3121dc0b113255124bcfada1cfa1b8 \
|
||||
--hash=sha256:590344787a90ae57d62511dd7c736ed56b428f04cd8c161fcc5e7232c130c69a \
|
||||
--hash=sha256:5c3894db91f5a489fc8fa6a9991820f368f0b3cbdb9cd8849547ccfab3392d86 \
|
||||
--hash=sha256:5c849d495bf5154cd8da18a9eb15db127d4dba2968d88831aff6f0331ea9bd4c \
|
||||
--hash=sha256:64536573d0a2cb6e625cf309984e2d873979709f2cf22839bf2d61790b448ad5 \
|
||||
--hash=sha256:722e1124aec435320ae01ee3ac7bec11a5d47f25d0ed6328f2273d287bc3abb0 \
|
||||
--hash=sha256:74fb4bee6880b529a0c6560885fce4dc95936920f9f20f53d99a213f7bf66776 \
|
||||
--hash=sha256:780d3a35680ced9ce682fbcf4cb9c2bad3136eeff760ab33707b71db84664e3a \
|
||||
--hash=sha256:8aefbba5f69d42246543407ed2461db31006b0f76c4e32dfd6f42215a2c41d09 \
|
||||
--hash=sha256:9750cc7fe1ae3b1611bb8cfc3f9ec11d532244235d75901fb6b8e42ce9229dfe \
|
||||
--hash=sha256:9acbb16f06fe7f52f441bb6f413ebae6c37baa6ef9edd49cdd567216da8600cd \
|
||||
--hash=sha256:a0cb6f11204443f27a1628b0e460f37fb30f624be6051d490fa7d7e26d4af3d0 \
|
||||
--hash=sha256:a828c57f00f729620a442881cc60e57cfcec6842ba38e1b19fd3e47ac0ff8dc1 \
|
||||
--hash=sha256:a9b2de4cf0cdd5bd2dee4c4f63a653c61d2408055ab77b151c1957f221cabf2a \
|
||||
--hash=sha256:b46c8ae3a8f1f41a0d2ef350c0b6e65822d80772fe46b653ab6b6274f61d4a49 \
|
||||
--hash=sha256:ba60bb19387e13597fb059f32cd4d59445d7b18b69a745b8f8e5db0346f33480 \
|
||||
--hash=sha256:beee944ae828747fd7cb216a70f120767fc9f4f00bacae8543c14a6831673f89 \
|
||||
--hash=sha256:c037a86e8513059a2613aaba4d817bb90b9d9b6b69aace3ce9c877e8c8ed402b \
|
||||
--hash=sha256:c302220494f5c1ebeb0912ea782bcd5e2f8308037b3c7553fad0e48ebad6ad82 \
|
||||
--hash=sha256:c757a9dd70d72b076d6f68efdbb9bc943665ae954dad2801b874c8c69e185068 \
|
||||
--hash=sha256:c9c92be9fd329ac801cc420e08452b70e7aeab94ea4233a4804f0915c14eba9b \
|
||||
--hash=sha256:cc7b01b3754ea68a62bd77ce6020afaffb44a590c2289089289363472d13aedb \
|
||||
--hash=sha256:db9e724bebd621d9beca794f2a4ff1d26eed5965b004a97f1f1685a173b869c2 \
|
||||
--hash=sha256:dd9b1baec094d91bf36ec729445f7769d0d0cf6b64d04d86e45baf89e2b9059b \
|
||||
--hash=sha256:e02a0e11cf6597299b9f3bbd3f93d79217cb90cfd1411aec33848b13f5c656cc \
|
||||
--hash=sha256:e774d53b1a477a67838a904131c4b0eef6b3d8a651f8b138b04f748fccfefe17 \
|
||||
--hash=sha256:f146e0911cb2f1da549fc58fc7bcd2b836a44b79ef871980d605ec392ff6b0d2 \
|
||||
--hash=sha256:f56e2333dda1fe0f909e7cc59f021eba0d2307bc6f012a1ccf2beca6ba362439 \
|
||||
--hash=sha256:f9a3ea26252bd92f570600098783d1371354d89d5f6b7dfd87359d669f2109b5 \
|
||||
--hash=sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac \
|
||||
--hash=sha256:fb3c2db03683b5767dedb5769b8a40ebb47d6f7f45b1b3e3b4b51ec8ad9d9825 \
|
||||
--hash=sha256:fde5bd59ab5357e3853313127f4d3565fc7dad314a74d7b5d43c22c6a5ed2ced \
|
||||
--hash=sha256:fe1a06da377e3a1062ae5fe0926e12b84eceb8a50b350ddca72dc85015873f74
|
||||
h11==0.14.0 \
|
||||
--hash=sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d \
|
||||
--hash=sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761
|
||||
httpcore==1.0.5 \
|
||||
--hash=sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61 \
|
||||
--hash=sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5
|
||||
httptools==0.6.1 \
|
||||
--hash=sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563 \
|
||||
--hash=sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142 \
|
||||
--hash=sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b \
|
||||
--hash=sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658 \
|
||||
--hash=sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2 \
|
||||
--hash=sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837 \
|
||||
--hash=sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3 \
|
||||
--hash=sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58 \
|
||||
--hash=sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d \
|
||||
--hash=sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90 \
|
||||
--hash=sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0 \
|
||||
--hash=sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1 \
|
||||
--hash=sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2 \
|
||||
--hash=sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0 \
|
||||
--hash=sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc \
|
||||
--hash=sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503 \
|
||||
--hash=sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949 \
|
||||
--hash=sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84 \
|
||||
--hash=sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb \
|
||||
--hash=sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a \
|
||||
--hash=sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f \
|
||||
--hash=sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185
|
||||
httpx==0.27.0 \
|
||||
--hash=sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5 \
|
||||
--hash=sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5
|
||||
idna==3.7 \
|
||||
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
|
||||
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
|
||||
jinja2==3.1.4 \
|
||||
--hash=sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369 \
|
||||
--hash=sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d
|
||||
markdown-it-py==3.0.0 \
|
||||
--hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
|
||||
--hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
|
||||
MarkupSafe==2.1.4 \
|
||||
--hash=sha256:0042d6a9880b38e1dd9ff83146cc3c9c18a059b9360ceae207805567aacccc69 \
|
||||
--hash=sha256:0c26f67b3fe27302d3a412b85ef696792c4a2386293c53ba683a89562f9399b0 \
|
||||
--hash=sha256:0fbad3d346df8f9d72622ac71b69565e621ada2ce6572f37c2eae8dacd60385d \
|
||||
--hash=sha256:31f57d64c336b8ccb1966d156932f3daa4fee74176b0fdc48ef580be774aae74 \
|
||||
--hash=sha256:396549cea79e8ca4ba65525470d534e8a41070e6b3500ce2414921099cb73e8d \
|
||||
--hash=sha256:3aae9af4cac263007fd6309c64c6ab4506dd2b79382d9d19a1994f9240b8db4f \
|
||||
--hash=sha256:3ab3a886a237f6e9c9f4f7d272067e712cdb4efa774bef494dccad08f39d8ae6 \
|
||||
--hash=sha256:5045e892cfdaecc5b4c01822f353cf2c8feb88a6ec1c0adef2a2e705eef0f656 \
|
||||
--hash=sha256:5244324676254697fe5c181fc762284e2c5fceeb1c4e3e7f6aca2b6f107e60dc \
|
||||
--hash=sha256:54a7e1380dfece8847c71bf7e33da5d084e9b889c75eca19100ef98027bd9f56 \
|
||||
--hash=sha256:55d03fea4c4e9fd0ad75dc2e7e2b6757b80c152c032ea1d1de487461d8140efc \
|
||||
--hash=sha256:78bc995e004681246e85e28e068111a4c3f35f34e6c62da1471e844ee1446250 \
|
||||
--hash=sha256:987d13fe1d23e12a66ca2073b8d2e2a75cec2ecb8eab43ff5624ba0ad42764bc \
|
||||
--hash=sha256:9e9e3c4020aa2dc62d5dd6743a69e399ce3de58320522948af6140ac959ab863 \
|
||||
--hash=sha256:a0b838c37ba596fcbfca71651a104a611543077156cb0a26fe0c475e1f152ee8 \
|
||||
--hash=sha256:a4d176cfdfde84f732c4a53109b293d05883e952bbba68b857ae446fa3119b4f \
|
||||
--hash=sha256:a76055d5cb1c23485d7ddae533229039b850db711c554a12ea64a0fd8a0129e2 \
|
||||
--hash=sha256:a76cd37d229fc385738bd1ce4cba2a121cf26b53864c1772694ad0ad348e509e \
|
||||
--hash=sha256:a7cc49ef48a3c7a0005a949f3c04f8baa5409d3f663a1b36f0eba9bfe2a0396e \
|
||||
--hash=sha256:abf5ebbec056817057bfafc0445916bb688a255a5146f900445d081db08cbabb \
|
||||
--hash=sha256:b83041cda633871572f0d3c41dddd5582ad7d22f65a72eacd8d3d6d00291df26 \
|
||||
--hash=sha256:c669391319973e49a7c6230c218a1e3044710bc1ce4c8e6eb71f7e6d43a2c131 \
|
||||
--hash=sha256:d5291d98cd3ad9a562883468c690a2a238c4a6388ab3bd155b0c75dd55ece858 \
|
||||
--hash=sha256:dac1ebf6983148b45b5fa48593950f90ed6d1d26300604f321c74a9ca1609f8e \
|
||||
--hash=sha256:de8153a7aae3835484ac168a9a9bdaa0c5eee4e0bc595503c95d53b942879c84 \
|
||||
--hash=sha256:e1a0d1924a5013d4f294087e00024ad25668234569289650929ab871231668e7 \
|
||||
--hash=sha256:e7902211afd0af05fbadcc9a312e4cf10f27b779cf1323e78d52377ae4b72bea \
|
||||
--hash=sha256:e888ff76ceb39601c59e219f281466c6d7e66bd375b4ec1ce83bcdc68306796b \
|
||||
--hash=sha256:f06e5a9e99b7df44640767842f414ed5d7bedaaa78cd817ce04bbd6fd86e2dd6 \
|
||||
--hash=sha256:f6be2d708a9d0e9b0054856f07ac7070fbe1754be40ca8525d5adccdbda8f475 \
|
||||
--hash=sha256:f9917691f410a2e0897d1ef99619fd3f7dd503647c8ff2475bf90c3cf222ad74
|
||||
markupsafe==2.1.5 \
|
||||
--hash=sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff \
|
||||
--hash=sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f \
|
||||
--hash=sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f \
|
||||
--hash=sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617 \
|
||||
--hash=sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906 \
|
||||
--hash=sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f \
|
||||
--hash=sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4 \
|
||||
--hash=sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169 \
|
||||
--hash=sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad \
|
||||
--hash=sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2 \
|
||||
--hash=sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f \
|
||||
--hash=sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced \
|
||||
--hash=sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5 \
|
||||
--hash=sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c \
|
||||
--hash=sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb \
|
||||
--hash=sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad \
|
||||
--hash=sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1 \
|
||||
--hash=sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc \
|
||||
--hash=sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee \
|
||||
--hash=sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900 \
|
||||
--hash=sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5 \
|
||||
--hash=sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f \
|
||||
--hash=sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5 \
|
||||
--hash=sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a \
|
||||
--hash=sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a \
|
||||
--hash=sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b \
|
||||
--hash=sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4 \
|
||||
--hash=sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46 \
|
||||
--hash=sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b \
|
||||
--hash=sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5 \
|
||||
--hash=sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd
|
||||
mdurl==0.1.2 \
|
||||
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
|
||||
--hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
|
||||
miservice-fork==2.6.1 \
|
||||
--hash=sha256:1702281e1e9827958eb3e82bc3242cd013c018e9aa1de8509b4805b5ccf5e60c \
|
||||
--hash=sha256:9b2cc4208486bbbf788d1bde6e2cbc70f241ce10db4dca6f918076a2d2942a39
|
||||
multidict==6.0.4 \
|
||||
--hash=sha256:01a3a55bd90018c9c080fbb0b9f4891db37d148a0a18722b42f94694f8b6d4c9 \
|
||||
--hash=sha256:0b1a97283e0c85772d613878028fec909f003993e1007eafa715b24b377cb9b8 \
|
||||
--hash=sha256:0dfad7a5a1e39c53ed00d2dd0c2e36aed4650936dc18fd9a1826a5ae1cad6f03 \
|
||||
--hash=sha256:11bdf3f5e1518b24530b8241529d2050014c884cf18b6fc69c0c2b30ca248710 \
|
||||
--hash=sha256:16d232d4e5396c2efbbf4f6d4df89bfa905eb0d4dc5b3549d872ab898451f569 \
|
||||
--hash=sha256:3601a3cece3819534b11d4efc1eb76047488fddd0c85a3948099d5da4d504636 \
|
||||
--hash=sha256:3666906492efb76453c0e7b97f2cf459b0682e7402c0489a95484965dbc1da49 \
|
||||
--hash=sha256:36c63aaa167f6c6b04ef2c85704e93af16c11d20de1d133e39de6a0e84582a93 \
|
||||
--hash=sha256:43644e38f42e3af682690876cff722d301ac585c5b9e1eacc013b7a3f7b696a0 \
|
||||
--hash=sha256:458f37be2d9e4c95e2d8866a851663cbc76e865b78395090786f6cd9b3bbf4f4 \
|
||||
--hash=sha256:4dcbb0906e38440fa3e325df2359ac6cb043df8e58c965bb45f4e406ecb162cc \
|
||||
--hash=sha256:574b7eae1ab267e5f8285f0fe881f17efe4b98c39a40858247720935b893bba8 \
|
||||
--hash=sha256:5979b5632c3e3534e42ca6ff856bb24b2e3071b37861c2c727ce220d80eee9ed \
|
||||
--hash=sha256:64bdf1086b6043bf519869678f5f2757f473dee970d7abf6da91ec00acb9cb98 \
|
||||
--hash=sha256:64da238a09d6039e3bd39bb3aee9c21a5e34f28bfa5aa22518581f910ff94af3 \
|
||||
--hash=sha256:666daae833559deb2d609afa4490b85830ab0dfca811a98b70a205621a6109fe \
|
||||
--hash=sha256:7582a1d1030e15422262de9f58711774e02fa80df0d1578995c76214f6954988 \
|
||||
--hash=sha256:7d18748f2d30f94f498e852c67d61261c643b349b9d2a581131725595c45ec6c \
|
||||
--hash=sha256:7d6ae9d593ef8641544d6263c7fa6408cc90370c8cb2bbb65f8d43e5b0351d9c \
|
||||
--hash=sha256:81a4f0b34bd92df3da93315c6a59034df95866014ac08535fc819f043bfd51f0 \
|
||||
--hash=sha256:a2e4369eb3d47d2034032a26c7a80fcb21a2cb22e1173d761a162f11e562caa5 \
|
||||
--hash=sha256:b1a2eeedcead3a41694130495593a559a668f382eee0727352b9a41e1c45759a \
|
||||
--hash=sha256:c048099e4c9e9d615545e2001d3d8a4380bd403e1a0578734e0d31703d1b0c0b \
|
||||
--hash=sha256:c5cb09abb18c1ea940fb99360ea0396f34d46566f157122c92dfa069d3e0e982 \
|
||||
--hash=sha256:d6d635d5209b82a3492508cf5b365f3446afb65ae7ebd755e70e18f287b0adf7 \
|
||||
--hash=sha256:dcfe792765fab89c365123c81046ad4103fcabbc4f56d1c1997e6715e8015461 \
|
||||
--hash=sha256:ddff9c4e225a63a5afab9dd15590432c22e8057e1a9a13d28ed128ecf047bbdc \
|
||||
--hash=sha256:ea20853c6dbbb53ed34cb4d080382169b6f4554d394015f1bef35e881bf83547 \
|
||||
--hash=sha256:ee2a1ece51b9b9e7752e742cfb661d2a29e7bcdba2d27e66e28a99f1890e4fa0 \
|
||||
--hash=sha256:eeb6dcc05e911516ae3d1f207d4b0520d07f54484c49dfc294d6e7d63b734171 \
|
||||
--hash=sha256:ff959bee35038c4624250473988b24f846cbeb2c6639de3602c073f10410ceba
|
||||
miservice-fork==2.7.0 \
|
||||
--hash=sha256:8e2c91ebe1fc4b3c63b01cbf1818e5d5833d024fd3a8311970d649ad2d49d6e6 \
|
||||
--hash=sha256:8e87ef6d89adceaf3f7a98242cdae1c9135498d77f2c743ec3871d2e42bcbab8
|
||||
multidict==6.0.5 \
|
||||
--hash=sha256:01265f5e40f5a17f8241d52656ed27192be03bfa8764d88e8220141d1e4b3556 \
|
||||
--hash=sha256:04bde7a7b3de05732a4eb39c94574db1ec99abb56162d6c520ad26f83267de29 \
|
||||
--hash=sha256:0d63c74e3d7ab26de115c49bffc92cc77ed23395303d496eae515d4204a625e7 \
|
||||
--hash=sha256:14c2976aa9038c2629efa2c148022ed5eb4cb939e15ec7aace7ca932f48f9ba6 \
|
||||
--hash=sha256:1d147090048129ce3c453f0292e7697d333db95e52616b3793922945804a433c \
|
||||
--hash=sha256:215ed703caf15f578dca76ee6f6b21b7603791ae090fbf1ef9d865571039ade5 \
|
||||
--hash=sha256:21fd81c4ebdb4f214161be351eb5bcf385426bf023041da2fd9e60681f3cebae \
|
||||
--hash=sha256:220dd781e3f7af2c2c1053da9fa96d9cf3072ca58f057f4c5adaaa1cab8fc442 \
|
||||
--hash=sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9 \
|
||||
--hash=sha256:29bfeb0dff5cb5fdab2023a7a9947b3b4af63e9c47cae2a10ad58394b517fddc \
|
||||
--hash=sha256:2f4848aa3baa109e6ab81fe2006c77ed4d3cd1e0ac2c1fbddb7b1277c168788c \
|
||||
--hash=sha256:2faa5ae9376faba05f630d7e5e6be05be22913782b927b19d12b8145968a85ea \
|
||||
--hash=sha256:2ffc42c922dbfddb4a4c3b438eb056828719f07608af27d163191cb3e3aa6cc5 \
|
||||
--hash=sha256:3cc2ad10255f903656017363cd59436f2111443a76f996584d1077e43ee51182 \
|
||||
--hash=sha256:411bf8515f3be9813d06004cac41ccf7d1cd46dfe233705933dd163b60e37600 \
|
||||
--hash=sha256:425bf820055005bfc8aa9a0b99ccb52cc2f4070153e34b701acc98d201693733 \
|
||||
--hash=sha256:435a0984199d81ca178b9ae2c26ec3d49692d20ee29bc4c11a2a8d4514c67eda \
|
||||
--hash=sha256:51d035609b86722963404f711db441cf7134f1889107fb171a970c9701f92e1e \
|
||||
--hash=sha256:53689bb4e102200a4fafa9de9c7c3c212ab40a7ab2c8e474491914d2305f187e \
|
||||
--hash=sha256:612d1156111ae11d14afaf3a0669ebf6c170dbb735e510a7438ffe2369a847fd \
|
||||
--hash=sha256:6939c95381e003f54cd4c5516740faba40cf5ad3eeff460c3ad1d3e0ea2549bf \
|
||||
--hash=sha256:766c8f7511df26d9f11cd3a8be623e59cca73d44643abab3f8c8c07620524e4a \
|
||||
--hash=sha256:76c0de87358b192de7ea9649beb392f107dcad9ad27276324c24c91774ca5271 \
|
||||
--hash=sha256:7901c05ead4b3fb75113fb1dd33eb1253c6d3ee37ce93305acd9d38e0b5f21a4 \
|
||||
--hash=sha256:79660376075cfd4b2c80f295528aa6beb2058fd289f4c9252f986751a4cd0496 \
|
||||
--hash=sha256:79a6d2ba910adb2cbafc95dad936f8b9386e77c84c35bc0add315b856d7c3abb \
|
||||
--hash=sha256:7afcdd1fc07befad18ec4523a782cde4e93e0a2bf71239894b8d61ee578c1319 \
|
||||
--hash=sha256:7be7047bd08accdb7487737631d25735c9a04327911de89ff1b26b81745bd4e3 \
|
||||
--hash=sha256:7c6390cf87ff6234643428991b7359b5f59cc15155695deb4eda5c777d2b880f \
|
||||
--hash=sha256:85f67aed7bb647f93e7520633d8f51d3cbc6ab96957c71272b286b2f30dc70ed \
|
||||
--hash=sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604 \
|
||||
--hash=sha256:92d16a3e275e38293623ebf639c471d3e03bb20b8ebb845237e0d3664914caef \
|
||||
--hash=sha256:99f60d34c048c5c2fabc766108c103612344c46e35d4ed9ae0673d33c8fb26e8 \
|
||||
--hash=sha256:9fe7b0653ba3d9d65cbe7698cca585bf0f8c83dbbcc710db9c90f478e175f2d5 \
|
||||
--hash=sha256:c1c1496e73051918fcd4f58ff2e0f2f3066d1c76a0c6aeffd9b45d53243702cc \
|
||||
--hash=sha256:cbebcd5bcaf1eaf302617c114aa67569dd3f090dd0ce8ba9e35e9985b41ac35b \
|
||||
--hash=sha256:ceb3b7e6a0135e092de86110c5a74e46bda4bd4fbfeeb3a3bcec79c0f861e450 \
|
||||
--hash=sha256:d3eb1ceec286eba8220c26f3b0096cf189aea7057b6e7b7a2e60ed36b373b77f \
|
||||
--hash=sha256:d84a5c3a5f7ce6db1f999fb9438f686bc2e09d38143f2d93d8406ed2dd6b9226 \
|
||||
--hash=sha256:de170c7b4fe6859beb8926e84f7d7d6c693dfe8e27372ce3b76f01c46e489fcf \
|
||||
--hash=sha256:e030047e85cbcedbfc073f71836d62dd5dadfbe7531cae27789ff66bc551bd5e \
|
||||
--hash=sha256:e0e79d91e71b9867c73323a3444724d496c037e578a0e1755ae159ba14f4f3d1 \
|
||||
--hash=sha256:e4428b29611e989719874670fd152b6625500ad6c686d464e99f5aaeeaca175a \
|
||||
--hash=sha256:f285e862d2f153a70586579c15c44656f888806ed0e5b56b64489afe4a2dbfba \
|
||||
--hash=sha256:f7e301075edaf50500f0b341543c41194d8df3ae5caf4702f2095f3ca73dd8da \
|
||||
--hash=sha256:fb616be3538599e797a2017cccca78e354c767165e8858ab5116813146041a24 \
|
||||
--hash=sha256:fe5d7785250541f7f5019ab9cba2c71169dc7d74d0f45253f8313f436458a4ef
|
||||
mutagen==1.47.0 \
|
||||
--hash=sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99 \
|
||||
--hash=sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719
|
||||
pycparser==2.21; implementation_name != "cpython" \
|
||||
--hash=sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9 \
|
||||
--hash=sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206
|
||||
pycryptodomex==3.19.0 \
|
||||
--hash=sha256:09c9401dc06fb3d94cb1ec23b4ea067a25d1f4c6b7b118ff5631d0b5daaab3cc \
|
||||
--hash=sha256:0b2f1982c5bc311f0aab8c293524b861b485d76f7c9ab2c3ac9a25b6f7655975 \
|
||||
--hash=sha256:136b284e9246b4ccf4f752d435c80f2c44fc2321c198505de1d43a95a3453b3c \
|
||||
--hash=sha256:2126bc54beccbede6eade00e647106b4f4c21e5201d2b0a73e9e816a01c50905 \
|
||||
--hash=sha256:263de9a96d2fcbc9f5bd3a279f14ea0d5f072adb68ebd324987576ec25da084d \
|
||||
--hash=sha256:50cb18d4dd87571006fd2447ccec85e6cec0136632a550aa29226ba075c80644 \
|
||||
--hash=sha256:5b883e1439ab63af976656446fb4839d566bb096f15fc3c06b5a99cde4927188 \
|
||||
--hash=sha256:5d73e9fa3fe830e7b6b42afc49d8329b07a049a47d12e0ef9225f2fd220f19b2 \
|
||||
--hash=sha256:67c8eb79ab33d0fbcb56842992298ddb56eb6505a72369c20f60bc1d2b6fb002 \
|
||||
--hash=sha256:7cb51096a6a8d400724104db8a7e4f2206041a1f23e58924aa3d8d96bcb48338 \
|
||||
--hash=sha256:800a2b05cfb83654df80266692f7092eeefe2a314fa7901dcefab255934faeec \
|
||||
--hash=sha256:a3866d68e2fc345162b1b9b83ef80686acfe5cec0d134337f3b03950a0a8bf56 \
|
||||
--hash=sha256:a588a1cb7781da9d5e1c84affd98c32aff9c89771eac8eaa659d2760666f7139 \
|
||||
--hash=sha256:a77b79852175064c822b047fee7cf5a1f434f06ad075cc9986aa1c19a0c53eb0 \
|
||||
--hash=sha256:af83a554b3f077564229865c45af0791be008ac6469ef0098152139e6bd4b5b6 \
|
||||
--hash=sha256:b801216c48c0886742abf286a9a6b117e248ca144d8ceec1f931ce2dd0c9cb40 \
|
||||
--hash=sha256:bfb040b5dda1dff1e197d2ef71927bd6b8bfcb9793bc4dfe0bb6df1e691eaacb \
|
||||
--hash=sha256:c01678aee8ac0c1a461cbc38ad496f953f9efcb1fa19f5637cbeba7544792a53 \
|
||||
--hash=sha256:c74eb1f73f788facece7979ce91594dc177e1a9b5d5e3e64697dd58299e5cb4d \
|
||||
--hash=sha256:d4dd3b381ff5a5907a3eb98f5f6d32c64d319a840278ceea1dcfcc65063856f3 \
|
||||
--hash=sha256:edbe083c299835de7e02c8aa0885cb904a75087d35e7bab75ebe5ed336e8c3e2
|
||||
pygments==2.16.1 \
|
||||
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
|
||||
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
|
||||
requests==2.31.0 \
|
||||
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
|
||||
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
|
||||
pycryptodomex==3.20.0 \
|
||||
--hash=sha256:25cd61e846aaab76d5791d006497134602a9e451e954833018161befc3b5b9ed \
|
||||
--hash=sha256:2a47bcc478741b71273b917232f521fd5704ab4b25d301669879e7273d3586cc \
|
||||
--hash=sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c \
|
||||
--hash=sha256:6e186342cfcc3aafaad565cbd496060e5a614b441cacc3995ef0091115c1f6c5 \
|
||||
--hash=sha256:7a710b79baddd65b806402e14766c721aee8fb83381769c27920f26476276c1e \
|
||||
--hash=sha256:7a7a8f33a1f1fb762ede6cc9cbab8f2a9ba13b196bfaf7bc6f0b39d2ba315a43 \
|
||||
--hash=sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3 \
|
||||
--hash=sha256:88afd7a3af7ddddd42c2deda43d53d3dfc016c11327d0915f90ca34ebda91499 \
|
||||
--hash=sha256:91852d4480a4537d169c29a9d104dda44094c78f1f5b67bca76c29a91042b623 \
|
||||
--hash=sha256:9c682436c359b5ada67e882fec34689726a09c461efd75b6ea77b2403d5665b7 \
|
||||
--hash=sha256:bca649483d5ed251d06daf25957f802e44e6bb6df2e8f218ae71968ff8f8edc4 \
|
||||
--hash=sha256:c39778fd0548d78917b61f03c1fa8bfda6cfcf98c767decf360945fe6f97461e \
|
||||
--hash=sha256:d00fe8596e1cc46b44bf3907354e9377aa030ec4cd04afbbf6e899fc1e2a7781 \
|
||||
--hash=sha256:e48217c7901edd95f9f097feaa0388da215ed14ce2ece803d3f300b4e694abea \
|
||||
--hash=sha256:f2e497413560e03421484189a6b65e33fe800d3bd75590e6d78d4dfdb7accf3b
|
||||
pydantic==2.8.2 \
|
||||
--hash=sha256:6f62c13d067b0755ad1c21a34bdd06c0c12625a22b0fc09c6b149816604f7c2a \
|
||||
--hash=sha256:73ee9fddd406dc318b885c7a2eab8a6472b68b8fb5ba8150949fc3db939f23c8
|
||||
pydantic-core==2.20.1 \
|
||||
--hash=sha256:035ede2e16da7281041f0e626459bcae33ed998cca6a0a007a5ebb73414ac72d \
|
||||
--hash=sha256:0827505a5c87e8aa285dc31e9ec7f4a17c81a813d45f70b1d9164e03a813a686 \
|
||||
--hash=sha256:084659fac3c83fd674596612aeff6041a18402f1e1bc19ca39e417d554468482 \
|
||||
--hash=sha256:11b71d67b4725e7e2a9f6e9c0ac1239bbc0c48cce3dc59f98635efc57d6dac83 \
|
||||
--hash=sha256:150906b40ff188a3260cbee25380e7494ee85048584998c1e66df0c7a11c17a6 \
|
||||
--hash=sha256:175873691124f3d0da55aeea1d90660a6ea7a3cfea137c38afa0a5ffabe37b88 \
|
||||
--hash=sha256:19c0fa39fa154e7e0b7f82f88ef85faa2a4c23cc65aae2f5aea625e3c13c735a \
|
||||
--hash=sha256:242b8feb3c493ab78be289c034a1f659e8826e2233786e36f2893a950a719bb6 \
|
||||
--hash=sha256:254ec27fdb5b1ee60684f91683be95e5133c994cc54e86a0b0963afa25c8f8a6 \
|
||||
--hash=sha256:25e9185e2d06c16ee438ed39bf62935ec436474a6ac4f9358524220f1b236e43 \
|
||||
--hash=sha256:26ca695eeee5f9f1aeeb211ffc12f10bcb6f71e2989988fda61dabd65db878d4 \
|
||||
--hash=sha256:26dc97754b57d2fd00ac2b24dfa341abffc380b823211994c4efac7f13b9e90e \
|
||||
--hash=sha256:270755f15174fb983890c49881e93f8f1b80f0b5e3a3cc1394a255706cabd203 \
|
||||
--hash=sha256:33499e85e739a4b60c9dac710c20a08dc73cb3240c9a0e22325e671b27b70d24 \
|
||||
--hash=sha256:37eee5b638f0e0dcd18d21f59b679686bbd18917b87db0193ae36f9c23c355fc \
|
||||
--hash=sha256:38cf1c40a921d05c5edc61a785c0ddb4bed67827069f535d794ce6bcded919fc \
|
||||
--hash=sha256:3acae97ffd19bf091c72df4d726d552c473f3576409b2a7ca36b2f535ffff4a3 \
|
||||
--hash=sha256:3d482efec8b7dc6bfaedc0f166b2ce349df0011f5d2f1f25537ced4cfc34fd98 \
|
||||
--hash=sha256:40a783fb7ee353c50bd3853e626f15677ea527ae556429453685ae32280c19c2 \
|
||||
--hash=sha256:41f4c96227a67a013e7de5ff8f20fb496ce573893b7f4f2707d065907bffdbd6 \
|
||||
--hash=sha256:469f29f9093c9d834432034d33f5fe45699e664f12a13bf38c04967ce233d688 \
|
||||
--hash=sha256:4aa223cd1e36b642092c326d694d8bf59b71ddddc94cdb752bbbb1c5c91d833b \
|
||||
--hash=sha256:4f2790949cf385d985a31984907fecb3896999329103df4e4983a4a41e13e840 \
|
||||
--hash=sha256:512ecfbefef6dac7bc5eaaf46177b2de58cdf7acac8793fe033b24ece0b9566c \
|
||||
--hash=sha256:516d9227919612425c8ef1c9b869bbbee249bc91912c8aaffb66116c0b447ebd \
|
||||
--hash=sha256:53e431da3fc53360db73eedf6f7124d1076e1b4ee4276b36fb25514544ceb4a3 \
|
||||
--hash=sha256:595ba5be69b35777474fa07f80fc260ea71255656191adb22a8c53aba4479231 \
|
||||
--hash=sha256:5d41e6daee2813ecceea8eda38062d69e280b39df793f5a942fa515b8ed67953 \
|
||||
--hash=sha256:5e999ba8dd90e93d57410c5e67ebb67ffcaadcea0ad973240fdfd3a135506250 \
|
||||
--hash=sha256:5f239eb799a2081495ea659d8d4a43a8f42cd1fe9ff2e7e436295c38a10c286a \
|
||||
--hash=sha256:65db0f2eefcaad1a3950f498aabb4875c8890438bc80b19362cf633b87a8ab20 \
|
||||
--hash=sha256:70c8daf4faca8da5a6d655f9af86faf6ec2e1768f4b8b9d0226c02f3d6209703 \
|
||||
--hash=sha256:7eb6a0587eded33aeefea9f916899d42b1799b7b14b8f8ff2753c0ac1741edac \
|
||||
--hash=sha256:8ad4aeb3e9a97286573c03df758fc7627aecdd02f1da04516a86dc159bf70121 \
|
||||
--hash=sha256:9dc1b507c12eb0481d071f3c1808f0529ad41dc415d0ca11f7ebfc666e66a18b \
|
||||
--hash=sha256:a45f84b09ac9c3d35dfcf6a27fd0634d30d183205230a0ebe8373a0e8cfa0906 \
|
||||
--hash=sha256:a4f55095ad087474999ee28d3398bae183a66be4823f753cd7d67dd0153427c9 \
|
||||
--hash=sha256:b0dae11d8f5ded51699c74d9548dcc5938e0804cc8298ec0aa0da95c21fff57b \
|
||||
--hash=sha256:b91ced227c41aa29c672814f50dbb05ec93536abf8f43cd14ec9521ea09afe4e \
|
||||
--hash=sha256:bc633a9fe1eb87e250b5c57d389cf28998e4292336926b0b6cdaee353f89a237 \
|
||||
--hash=sha256:bebb4d6715c814597f85297c332297c6ce81e29436125ca59d1159b07f423eb1 \
|
||||
--hash=sha256:c336a6d235522a62fef872c6295a42ecb0c4e1d0f1a3e500fe949415761b8a19 \
|
||||
--hash=sha256:c81131869240e3e568916ef4c307f8b99583efaa60a8112ef27a366eefba8ef0 \
|
||||
--hash=sha256:d02a72df14dfdbaf228424573a07af10637bd490f0901cee872c4f434a735b94 \
|
||||
--hash=sha256:d2a8fa9d6d6f891f3deec72f5cc668e6f66b188ab14bb1ab52422fe8e644f312 \
|
||||
--hash=sha256:d2b27e6af28f07e2f195552b37d7d66b150adbaa39a6d327766ffd695799780f \
|
||||
--hash=sha256:d3f3ed29cd9f978c604708511a1f9c2fdcb6c38b9aae36a51905b8811ee5cbf1 \
|
||||
--hash=sha256:d573faf8eb7e6b1cbbcb4f5b247c60ca8be39fe2c674495df0eb4318303137fe \
|
||||
--hash=sha256:e0bbdd76ce9aa5d4209d65f2b27fc6e5ef1312ae6c5333c26db3f5ade53a1e99 \
|
||||
--hash=sha256:e7c4ea22b6739b162c9ecaaa41d718dfad48a244909fe7ef4b54c0b530effc5a \
|
||||
--hash=sha256:e93e1a4b4b33daed65d781a57a522ff153dcf748dee70b40c7258c5861e1768a \
|
||||
--hash=sha256:e97fdf088d4b31ff4ba35db26d9cc472ac7ef4a2ff2badeabf8d727b3377fc52 \
|
||||
--hash=sha256:e9fa4c9bf273ca41f940bceb86922a7667cd5bf90e95dbb157cbb8441008482c \
|
||||
--hash=sha256:f1f62b2413c3a0e846c3b838b2ecd6c7a19ec6793b2a522745b0869e37ab5bc1 \
|
||||
--hash=sha256:f9aa05d09ecf4c75157197f27cdc9cfaeb7c5f15021c6373932bf3e124af029f \
|
||||
--hash=sha256:fa2fddcb7107e0d1808086ca306dcade7df60a13a6c347a7acf1ec139aa6789a \
|
||||
--hash=sha256:faa6b09ee09433b87992fb5a2859efd1c264ddc37280d2dd5db502126d0e7f27
|
||||
pygments==2.18.0 \
|
||||
--hash=sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199 \
|
||||
--hash=sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a
|
||||
python-dotenv==1.0.1 \
|
||||
--hash=sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca \
|
||||
--hash=sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a
|
||||
python-multipart==0.0.9 \
|
||||
--hash=sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026 \
|
||||
--hash=sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215
|
||||
pyyaml==6.0.1 \
|
||||
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
|
||||
--hash=sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df \
|
||||
--hash=sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741 \
|
||||
--hash=sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290 \
|
||||
--hash=sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9 \
|
||||
--hash=sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d \
|
||||
--hash=sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007 \
|
||||
--hash=sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938 \
|
||||
--hash=sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0 \
|
||||
--hash=sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d \
|
||||
--hash=sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28 \
|
||||
--hash=sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4 \
|
||||
--hash=sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef \
|
||||
--hash=sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515 \
|
||||
--hash=sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924 \
|
||||
--hash=sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34 \
|
||||
--hash=sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43 \
|
||||
--hash=sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673 \
|
||||
--hash=sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54 \
|
||||
--hash=sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a \
|
||||
--hash=sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b \
|
||||
--hash=sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab \
|
||||
--hash=sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d \
|
||||
--hash=sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f
|
||||
requests==2.32.3 \
|
||||
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||
rich==13.7.1 \
|
||||
--hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \
|
||||
--hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432
|
||||
typing-extensions==4.9.0; python_version < "3.11" \
|
||||
--hash=sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783 \
|
||||
--hash=sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd
|
||||
urllib3==2.0.6 \
|
||||
--hash=sha256:7a7c7003b000adf9e7ca2a377c9688bbc54ed41b985789ed576570342a375cd2 \
|
||||
--hash=sha256:b19e1a85d206b56d7df1d5e683df4a7725252a964e3993648dd0fb5a1c157564
|
||||
waitress==3.0.0 \
|
||||
--hash=sha256:005da479b04134cdd9dd602d1ee7c49d79de0537610d653674cc6cbde222b8a1 \
|
||||
--hash=sha256:2a06f242f4ba0cc563444ca3d1998959447477363a2d7e9b8b4d75d35cfd1669
|
||||
shellingham==1.5.4 \
|
||||
--hash=sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686 \
|
||||
--hash=sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de
|
||||
sniffio==1.3.1 \
|
||||
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
|
||||
--hash=sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc
|
||||
starlette==0.37.2 \
|
||||
--hash=sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee \
|
||||
--hash=sha256:9af890290133b79fc3db55474ade20f6220a364a0402e0b556e7cd5e1e093823
|
||||
typer==0.12.3 \
|
||||
--hash=sha256:070d7ca53f785acbccba8e7d28b08dcd88f79f1fbda035ade0aecec71ca5c914 \
|
||||
--hash=sha256:49e73131481d804288ef62598d97a1ceef3058905aa536a1134f90891ba35482
|
||||
typing-extensions==4.12.2 \
|
||||
--hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
|
||||
--hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
|
||||
urllib3==2.2.2 \
|
||||
--hash=sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472 \
|
||||
--hash=sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168
|
||||
uvicorn==0.30.1 \
|
||||
--hash=sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81 \
|
||||
--hash=sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8
|
||||
uvicorn[standard]==0.30.1 \
|
||||
--hash=sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81 \
|
||||
--hash=sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8
|
||||
uvloop==0.19.0; (sys_platform != "cygwin" and sys_platform != "win32") and platform_python_implementation != "PyPy" \
|
||||
--hash=sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd \
|
||||
--hash=sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec \
|
||||
--hash=sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc \
|
||||
--hash=sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2 \
|
||||
--hash=sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12 \
|
||||
--hash=sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef \
|
||||
--hash=sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24 \
|
||||
--hash=sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428 \
|
||||
--hash=sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1 \
|
||||
--hash=sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849 \
|
||||
--hash=sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593 \
|
||||
--hash=sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd \
|
||||
--hash=sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6 \
|
||||
--hash=sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3 \
|
||||
--hash=sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8 \
|
||||
--hash=sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533 \
|
||||
--hash=sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957 \
|
||||
--hash=sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650 \
|
||||
--hash=sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e
|
||||
watchfiles==0.22.0 \
|
||||
--hash=sha256:00095dd368f73f8f1c3a7982a9801190cc88a2f3582dd395b289294f8975172b \
|
||||
--hash=sha256:00f39592cdd124b4ec5ed0b1edfae091567c72c7da1487ae645426d1b0ffcad1 \
|
||||
--hash=sha256:030bc4e68d14bcad2294ff68c1ed87215fbd9a10d9dea74e7cfe8a17869785ab \
|
||||
--hash=sha256:052d668a167e9fc345c24203b104c313c86654dd6c0feb4b8a6dfc2462239249 \
|
||||
--hash=sha256:067dea90c43bf837d41e72e546196e674f68c23702d3ef80e4e816937b0a3ffd \
|
||||
--hash=sha256:1235c11510ea557fe21be5d0e354bae2c655a8ee6519c94617fe63e05bca4171 \
|
||||
--hash=sha256:1cc0cba54f47c660d9fa3218158b8963c517ed23bd9f45fe463f08262a4adae1 \
|
||||
--hash=sha256:1d9188979a58a096b6f8090e816ccc3f255f137a009dd4bbec628e27696d67c1 \
|
||||
--hash=sha256:213792c2cd3150b903e6e7884d40660e0bcec4465e00563a5fc03f30ea9c166c \
|
||||
--hash=sha256:2627a91e8110b8de2406d8b2474427c86f5a62bf7d9ab3654f541f319ef22bcb \
|
||||
--hash=sha256:28585744c931576e535860eaf3f2c0ec7deb68e3b9c5a85ca566d69d36d8dd27 \
|
||||
--hash=sha256:2bdadf6b90c099ca079d468f976fd50062905d61fae183f769637cb0f68ba59a \
|
||||
--hash=sha256:3218a6f908f6a276941422b035b511b6d0d8328edd89a53ae8c65be139073f84 \
|
||||
--hash=sha256:425440e55cd735386ec7925f64d5dde392e69979d4c8459f6bb4e920210407f2 \
|
||||
--hash=sha256:4b9f2a128a32a2c273d63eb1fdbf49ad64852fc38d15b34eaa3f7ca2f0d2b797 \
|
||||
--hash=sha256:52fc9b0dbf54d43301a19b236b4a4614e610605f95e8c3f0f65c3a456ffd7d35 \
|
||||
--hash=sha256:55b7cc10261c2786c41d9207193a85c1db1b725cf87936df40972aab466179b6 \
|
||||
--hash=sha256:581f0a051ba7bafd03e17127735d92f4d286af941dacf94bcf823b101366249e \
|
||||
--hash=sha256:5e45fb0d70dda1623a7045bd00c9e036e6f1f6a85e4ef2c8ae602b1dfadf7550 \
|
||||
--hash=sha256:61af9efa0733dc4ca462347becb82e8ef4945aba5135b1638bfc20fad64d4f0e \
|
||||
--hash=sha256:68fe0c4d22332d7ce53ad094622b27e67440dacefbaedd29e0794d26e247280c \
|
||||
--hash=sha256:8c39987a1397a877217be1ac0fb1d8b9f662c6077b90ff3de2c05f235e6a8f96 \
|
||||
--hash=sha256:94ebe84a035993bb7668f58a0ebf998174fb723a39e4ef9fce95baabb42b787f \
|
||||
--hash=sha256:9624a68b96c878c10437199d9a8b7d7e542feddda8d5ecff58fdc8e67b460848 \
|
||||
--hash=sha256:988e981aaab4f3955209e7e28c7794acdb690be1efa7f16f8ea5aba7ffdadacb \
|
||||
--hash=sha256:a8a31bfd98f846c3c284ba694c6365620b637debdd36e46e1859c897123aa232 \
|
||||
--hash=sha256:a927b3034d0672f62fb2ef7ea3c9fc76d063c4b15ea852d1db2dc75fe2c09696 \
|
||||
--hash=sha256:ace7d060432acde5532e26863e897ee684780337afb775107c0a90ae8dbccfd2 \
|
||||
--hash=sha256:aec83c3ba24c723eac14225194b862af176d52292d271c98820199110e31141e \
|
||||
--hash=sha256:b44b70850f0073b5fcc0b31ede8b4e736860d70e2dbf55701e05d3227a154a67 \
|
||||
--hash=sha256:b810a2c7878cbdecca12feae2c2ae8af59bea016a78bc353c184fa1e09f76b68 \
|
||||
--hash=sha256:bbf8a20266136507abf88b0df2328e6a9a7c7309e8daff124dda3803306a9fdb \
|
||||
--hash=sha256:bd4c06100bce70a20c4b81e599e5886cf504c9532951df65ad1133e508bf20be \
|
||||
--hash=sha256:c2444dc7cb9d8cc5ab88ebe792a8d75709d96eeef47f4c8fccb6df7c7bc5be71 \
|
||||
--hash=sha256:c49b76a78c156979759d759339fb62eb0549515acfe4fd18bb151cc07366629c \
|
||||
--hash=sha256:c4a65474fd2b4c63e2c18ac67a0c6c66b82f4e73e2e4d940f837ed3d2fd9d4da \
|
||||
--hash=sha256:c5af2347d17ab0bd59366db8752d9e037982e259cacb2ba06f2c41c08af02c39 \
|
||||
--hash=sha256:c668228833c5619f6618699a2c12be057711b0ea6396aeaece4ded94184304ea \
|
||||
--hash=sha256:c7b978c384e29d6c7372209cbf421d82286a807bbcdeb315427687f8371c340a \
|
||||
--hash=sha256:da1e0a8caebf17976e2ffd00fa15f258e14749db5e014660f53114b676e68538 \
|
||||
--hash=sha256:dc2e8fe41f3cac0660197d95216c42910c2b7e9c70d48e6d84e22f577d106fc1 \
|
||||
--hash=sha256:e0f0a874231e2839abbf473256efffe577d6ee2e3bfa5b540479e892e47c172d \
|
||||
--hash=sha256:f7e1f9c5d1160d03b93fc4b68a0aeb82fe25563e12fbcdc8507f8434ab6f823c
|
||||
websockets==12.0 \
|
||||
--hash=sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b \
|
||||
--hash=sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6 \
|
||||
--hash=sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df \
|
||||
--hash=sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b \
|
||||
--hash=sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2 \
|
||||
--hash=sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed \
|
||||
--hash=sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd \
|
||||
--hash=sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b \
|
||||
--hash=sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931 \
|
||||
--hash=sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30 \
|
||||
--hash=sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370 \
|
||||
--hash=sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be \
|
||||
--hash=sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf \
|
||||
--hash=sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b \
|
||||
--hash=sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402 \
|
||||
--hash=sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f \
|
||||
--hash=sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123 \
|
||||
--hash=sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603 \
|
||||
--hash=sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45 \
|
||||
--hash=sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558 \
|
||||
@@ -419,59 +537,67 @@ websockets==12.0 \
|
||||
--hash=sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92 \
|
||||
--hash=sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113 \
|
||||
--hash=sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f \
|
||||
--hash=sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468 \
|
||||
--hash=sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611 \
|
||||
--hash=sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d \
|
||||
--hash=sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca \
|
||||
--hash=sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f \
|
||||
--hash=sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2 \
|
||||
--hash=sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077 \
|
||||
--hash=sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2 \
|
||||
--hash=sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374 \
|
||||
--hash=sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc \
|
||||
--hash=sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e \
|
||||
--hash=sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53 \
|
||||
--hash=sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399 \
|
||||
--hash=sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547 \
|
||||
--hash=sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3 \
|
||||
--hash=sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870 \
|
||||
--hash=sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5 \
|
||||
--hash=sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7
|
||||
Werkzeug==3.0.1 \
|
||||
--hash=sha256:507e811ecea72b18a404947aded4b3390e1db8f826b494d76550ef45bb3b1dcc \
|
||||
--hash=sha256:90a285dc0e42ad56b34e696398b8122ee4c681833fb35b8334a095d82c56da10
|
||||
yarl==1.9.2 \
|
||||
--hash=sha256:04ab9d4b9f587c06d801c2abfe9317b77cdf996c65a90d5e84ecc45010823571 \
|
||||
--hash=sha256:159d81f22d7a43e6eabc36d7194cb53f2f15f498dbbfa8edc8a3239350f59fe7 \
|
||||
--hash=sha256:22a94666751778629f1ec4280b08eb11815783c63f52092a5953faf73be24191 \
|
||||
--hash=sha256:2a96c19c52ff442a808c105901d0bdfd2e28575b3d5f82e2f5fd67e20dc5f4ea \
|
||||
--hash=sha256:2b0738fb871812722a0ac2154be1f049c6223b9f6f22eec352996b69775b36d4 \
|
||||
--hash=sha256:32f1d071b3f362c80f1a7d322bfd7b2d11e33d2adf395cc1dd4df36c9c243095 \
|
||||
--hash=sha256:50f33040f3836e912ed16d212f6cc1efb3231a8a60526a407aeb66c1c1956dde \
|
||||
--hash=sha256:566185e8ebc0898b11f8026447eacd02e46226716229cea8db37496c8cdd26e0 \
|
||||
--hash=sha256:56ff08ab5df8429901ebdc5d15941b59f6253393cb5da07b4170beefcf1b2528 \
|
||||
--hash=sha256:646d663eb2232d7909e6601f1a9107e66f9791f290a1b3dc7057818fe44fc2b6 \
|
||||
--hash=sha256:783185c75c12a017cc345015ea359cc801c3b29a2966c2655cd12b233bf5a2be \
|
||||
--hash=sha256:822b30a0f22e588b32d3120f6d41e4ed021806418b4c9f0bc3048b8c8cb3f92a \
|
||||
--hash=sha256:82aa6264b36c50acfb2424ad5ca537a2060ab6de158a5bd2a72a032cc75b9eb8 \
|
||||
--hash=sha256:832b7e711027c114d79dffb92576acd1bd2decc467dec60e1cac96912602d0e6 \
|
||||
--hash=sha256:891c0e3ec5ec881541f6c5113d8df0315ce5440e244a716b95f2525b7b9f3608 \
|
||||
--hash=sha256:8c2ad583743d16ddbdf6bb14b5cd76bf43b0d0006e918809d5d4ddf7bde8dd82 \
|
||||
--hash=sha256:8ea48e0a2f931064469bdabca50c2f578b565fc446f302a79ba6cc0ee7f384d3 \
|
||||
--hash=sha256:8ec53a0ea2a80c5cd1ab397925f94bff59222aa3cf9c6da938ce05c9ec20428d \
|
||||
--hash=sha256:95d2ecefbcf4e744ea952d073c6922e72ee650ffc79028eb1e320e732898d7e8 \
|
||||
--hash=sha256:9bf345c3a4f5ba7f766430f97f9cc1320786f19584acc7086491f45524a551ac \
|
||||
--hash=sha256:a60347f234c2212a9f0361955007fcf4033a75bf600a33c88a0a8e91af77c0e8 \
|
||||
--hash=sha256:a83503934c6273806aed765035716216cc9ab4e0364f7f066227e1aaea90b8d0 \
|
||||
--hash=sha256:aff634b15beff8902d1f918012fc2a42e0dbae6f469fce134c8a0dc51ca423bb \
|
||||
--hash=sha256:b25322201585c69abc7b0e89e72790469f7dad90d26754717f3310bfe30331c2 \
|
||||
--hash=sha256:b8cc1863402472f16c600e3e93d542b7e7542a540f95c30afd472e8e549fc3f7 \
|
||||
--hash=sha256:be6b3fdec5c62f2a67cb3f8c6dbf56bbf3f61c0f046f84645cd1ca73532ea051 \
|
||||
--hash=sha256:c0c77533b5ed4bcc38e943178ccae29b9bcf48ffd1063f5821192f23a1bd27b9 \
|
||||
--hash=sha256:c3a53ba34a636a256d767c086ceb111358876e1fb6b50dfc4d3f4951d40133d5 \
|
||||
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
|
||||
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
|
||||
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560
|
||||
yt-dlp==2024.5.30.232720.dev0 \
|
||||
--hash=sha256:9e2b177c5b13ea6f54cee1c56a69dd7832d506fba73a2247c6470e7d1952f959 \
|
||||
--hash=sha256:d6e563a2923807392325722028e7792e35affb694a505617b008195d0d212d2c
|
||||
--hash=sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5
|
||||
yarl==1.9.4 \
|
||||
--hash=sha256:008d3e808d03ef28542372d01057fd09168419cdc8f848efe2804f894ae03e51 \
|
||||
--hash=sha256:03caa9507d3d3c83bca08650678e25364e1843b484f19986a527630ca376ecce \
|
||||
--hash=sha256:09efe4615ada057ba2d30df871d2f668af661e971dfeedf0c159927d48bbeff0 \
|
||||
--hash=sha256:0d2454f0aef65ea81037759be5ca9947539667eecebca092733b2eb43c965a81 \
|
||||
--hash=sha256:0e9d124c191d5b881060a9e5060627694c3bdd1fe24c5eecc8d5d7d0eb6faabc \
|
||||
--hash=sha256:357495293086c5b6d34ca9616a43d329317feab7917518bc97a08f9e55648455 \
|
||||
--hash=sha256:35a2b9396879ce32754bd457d31a51ff0a9d426fd9e0e3c33394bf4b9036b099 \
|
||||
--hash=sha256:3777ce5536d17989c91696db1d459574e9a9bd37660ea7ee4d3344579bb6f129 \
|
||||
--hash=sha256:3986b6f41ad22988e53d5778f91855dc0399b043fc8946d4f2e68af22ee9ff10 \
|
||||
--hash=sha256:44d8ffbb9c06e5a7f529f38f53eda23e50d1ed33c6c869e01481d3fafa6b8142 \
|
||||
--hash=sha256:49a180c2e0743d5d6e0b4d1a9e5f633c62eca3f8a86ba5dd3c471060e352ca98 \
|
||||
--hash=sha256:4b21516d181cd77ebd06ce160ef8cc2a5e9ad35fb1c5930882baff5ac865eee7 \
|
||||
--hash=sha256:4b3c1ffe10069f655ea2d731808e76e0f452fc6c749bea04781daf18e6039525 \
|
||||
--hash=sha256:4c7d56b293cc071e82532f70adcbd8b61909eec973ae9d2d1f9b233f3d943f2c \
|
||||
--hash=sha256:4e9035df8d0880b2f1c7f5031f33f69e071dfe72ee9310cfc76f7b605958ceb9 \
|
||||
--hash=sha256:54525ae423d7b7a8ee81ba189f131054defdb122cde31ff17477951464c1691c \
|
||||
--hash=sha256:549d19c84c55d11687ddbd47eeb348a89df9cb30e1993f1b128f4685cd0ebbf8 \
|
||||
--hash=sha256:54beabb809ffcacbd9d28ac57b0db46e42a6e341a030293fb3185c409e626b8b \
|
||||
--hash=sha256:566db86717cf8080b99b58b083b773a908ae40f06681e87e589a976faf8246bf \
|
||||
--hash=sha256:6f5cb257bc2ec58f437da2b37a8cd48f666db96d47b8a3115c29f316313654ff \
|
||||
--hash=sha256:7855426dfbddac81896b6e533ebefc0af2f132d4a47340cee6d22cac7190022d \
|
||||
--hash=sha256:7d5aaac37d19b2904bb9dfe12cdb08c8443e7ba7d2852894ad448d4b8f442863 \
|
||||
--hash=sha256:801e9264d19643548651b9db361ce3287176671fb0117f96b5ac0ee1c3530d53 \
|
||||
--hash=sha256:81eb57278deb6098a5b62e88ad8281b2ba09f2f1147c4767522353eaa6260b31 \
|
||||
--hash=sha256:848cd2a1df56ddbffeb375535fb62c9d1645dde33ca4d51341378b3f5954429b \
|
||||
--hash=sha256:928cecb0ef9d5a7946eb6ff58417ad2fe9375762382f1bf5c55e61645f2c43ad \
|
||||
--hash=sha256:992f18e0ea248ee03b5a6e8b3b4738850ae7dbb172cc41c966462801cbf62cf7 \
|
||||
--hash=sha256:9fc5fc1eeb029757349ad26bbc5880557389a03fa6ada41703db5e068881e5f2 \
|
||||
--hash=sha256:a3a6ed1d525bfb91b3fc9b690c5a21bb52de28c018530ad85093cc488bee2dd2 \
|
||||
--hash=sha256:a7409f968456111140c1c95301cadf071bd30a81cbd7ab829169fb9e3d72eae9 \
|
||||
--hash=sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e \
|
||||
--hash=sha256:a9bd00dc3bc395a662900f33f74feb3e757429e545d831eef5bb280252631984 \
|
||||
--hash=sha256:aa102d6d280a5455ad6a0f9e6d769989638718e938a6a0a2ff3f4a7ff8c62cc4 \
|
||||
--hash=sha256:aaaea1e536f98754a6e5c56091baa1b6ce2f2700cc4a00b0d49eca8dea471074 \
|
||||
--hash=sha256:b8477c1ee4bd47c57d49621a062121c3023609f7a13b8a46953eb6c9716ca392 \
|
||||
--hash=sha256:bac8d525a8dbc2a1507ec731d2867025d11ceadcb4dd421423a5d42c56818541 \
|
||||
--hash=sha256:c0ec0ed476f77db9fb29bca17f0a8fcc7bc97ad4c6c1d8959c507decb22e8572 \
|
||||
--hash=sha256:c38c9ddb6103ceae4e4498f9c08fac9b590c5c71b0370f98714768e22ac6fa66 \
|
||||
--hash=sha256:d1d2532b340b692880261c15aee4dc94dd22ca5d61b9db9a8a361953d36410b1 \
|
||||
--hash=sha256:d5ff2c858f5f6a42c2a8e751100f237c5e869cbde669a724f2062d4c4ef93551 \
|
||||
--hash=sha256:d8a1c6c0be645c745a081c192e747c5de06e944a0d21245f4cf7c05e457c36e0 \
|
||||
--hash=sha256:d8b889777de69897406c9fb0b76cdf2fd0f31267861ae7501d93003d55f54fbe \
|
||||
--hash=sha256:d9e09c9d74f4566e905a0b8fa668c58109f7624db96a2171f21747abc7524234 \
|
||||
--hash=sha256:e23a6d84d9d1738dbc6e38167776107e63307dfc8ad108e580548d1f2c587f42 \
|
||||
--hash=sha256:e516dc8baf7b380e6c1c26792610230f37147bb754d6426462ab115a02944385 \
|
||||
--hash=sha256:ea65804b5dc88dacd4a40279af0cdadcfe74b3e5b4c897aa0d81cf86927fee78 \
|
||||
--hash=sha256:ee04010f26d5102399bd17f8df8bc38dc7ccd7701dc77f4a68c5b8d733406958
|
||||
yt-dlp==2024.7.16 \
|
||||
--hash=sha256:424805a112e757b141e767bc938d49db56d13d6415a92fa4cd8acadd55790be0 \
|
||||
--hash=sha256:c5bd517a49dea1923ec8e14f51858f10fd89dfece14cb701392b480b41b2f516
|
||||
|
||||
57
update-static-version.py
Executable file
57
update-static-version.py
Executable file
@@ -0,0 +1,57 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_html_files(directory):
|
||||
"""
|
||||
获取指定目录下所有HTML文件的列表。
|
||||
|
||||
:param directory: 搜索HTML文件的目录。
|
||||
:return: 搜索到的HTML文件的路径列表。
|
||||
"""
|
||||
return list(Path(directory).rglob("*.html"))
|
||||
|
||||
|
||||
def update_html_version(html_files, version):
|
||||
"""
|
||||
更新HTML文件中所有以 /static/ 开头的CSS和JS文件引用的版本号。
|
||||
|
||||
:param html_files: 需要更新的HTML文件路径的列表。
|
||||
:param version: 新的版本号字符串。
|
||||
"""
|
||||
pattern = re.compile(r'(/static/.*(css|js))\?version=[^"]*"')
|
||||
# pattern = re.compile(r'(/static/.*html)\?version=[^"]*"')
|
||||
|
||||
for html_file in html_files:
|
||||
if not html_file.exists():
|
||||
print(f"文件 {html_file} 不存在。")
|
||||
continue
|
||||
|
||||
html_content = html_file.read_text()
|
||||
|
||||
# 更新CSS和JS版本号
|
||||
html_content = pattern.sub(rf'\g<1>?version={version}"', html_content)
|
||||
# html_content = pattern.sub(fr'\g<1>"', html_content)
|
||||
|
||||
# 保存更改到HTML文件
|
||||
html_file.write_text(html_content)
|
||||
|
||||
print(f"文件 {html_file} 已更新为使用新的版本号: {version}")
|
||||
|
||||
|
||||
# 使用案例
|
||||
if __name__ == "__main__":
|
||||
import time
|
||||
|
||||
t = str(int(time.time()))
|
||||
|
||||
# 指定目录
|
||||
html_directory = "xiaomusic/static" # 修改为实际的HTML文件目录路径
|
||||
|
||||
# 获取HTML文件列表
|
||||
html_files_to_update = get_html_files(html_directory)
|
||||
|
||||
# 执行更新
|
||||
update_html_version(html_files_to_update, t)
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.1.87"
|
||||
__version__ = "0.3.11"
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import asyncio
|
||||
|
||||
from xiaomusic import (
|
||||
__version__,
|
||||
)
|
||||
import uvicorn
|
||||
|
||||
from xiaomusic import __version__
|
||||
from xiaomusic.config import Config
|
||||
from xiaomusic.httpserver import HttpInit
|
||||
from xiaomusic.httpserver import app as HttpApp
|
||||
from xiaomusic.xiaomusic import XiaoMusic
|
||||
|
||||
LOGO = r"""
|
||||
@@ -19,10 +21,15 @@ LOGO = r"""
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument(
|
||||
"--port",
|
||||
dest="port",
|
||||
help="监听端口",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--hardware",
|
||||
dest="hardware",
|
||||
help="小爱 hardware",
|
||||
help="小爱音箱型号",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--account",
|
||||
@@ -56,6 +63,12 @@ def main():
|
||||
dest="ffmpeg_location",
|
||||
help="ffmpeg bin path",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--enable_config_example",
|
||||
dest="enable_config_example",
|
||||
help="是否输出示例配置文件",
|
||||
action="store_true",
|
||||
)
|
||||
|
||||
print(LOGO.format(f"XiaoMusic v{__version__} by: github.com/hanxi"))
|
||||
|
||||
@@ -63,8 +76,28 @@ def main():
|
||||
config = Config.from_options(options)
|
||||
|
||||
xiaomusic = XiaoMusic(config)
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(xiaomusic.run_forever())
|
||||
HttpInit(xiaomusic)
|
||||
|
||||
from uvicorn.config import LOGGING_CONFIG
|
||||
|
||||
LOGGING_CONFIG["formatters"]["access"] = {
|
||||
"format": f"%(asctime)s [{__version__}] [%(levelname)s] %(filename)s:%(lineno)d: %(message)s",
|
||||
"datefmt": "[%X]",
|
||||
}
|
||||
LOGGING_CONFIG["handlers"]["access"] = {
|
||||
"level": "INFO",
|
||||
"class": "logging.handlers.RotatingFileHandler",
|
||||
"formatter": "access",
|
||||
"filename": config.log_file,
|
||||
"maxBytes": 10 * 1024 * 1024,
|
||||
"backupCount": 1,
|
||||
}
|
||||
uvicorn.run(
|
||||
HttpApp,
|
||||
host=["::", "0.0.0.0"],
|
||||
port=config.port,
|
||||
log_config=LOGGING_CONFIG,
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -3,85 +3,112 @@ from __future__ import annotations
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
from dataclasses import dataclass
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import get_type_hints
|
||||
|
||||
from xiaomusic.utils import validate_proxy
|
||||
|
||||
|
||||
# 默认口令
|
||||
DEFAULT_KEY_WORD_DICT = {
|
||||
"播放歌曲": "play",
|
||||
"播放本地歌曲": "playlocal",
|
||||
"关机": "stop",
|
||||
"下一首": "play_next",
|
||||
"单曲循环": "set_play_type_one",
|
||||
"全部循环": "set_play_type_all",
|
||||
"随机播放": "random_play",
|
||||
"分钟后关机": "stop_after_minute",
|
||||
"播放列表": "play_music_list",
|
||||
"刷新列表": "gen_music_list",
|
||||
"set_volume#": "set_volume",
|
||||
"get_volume#": "get_volume",
|
||||
}
|
||||
def default_key_word_dict():
|
||||
return {
|
||||
"播放歌曲": "play",
|
||||
"播放本地歌曲": "playlocal",
|
||||
"关机": "stop",
|
||||
"下一首": "play_next",
|
||||
"单曲循环": "set_play_type_one",
|
||||
"全部循环": "set_play_type_all",
|
||||
"随机播放": "set_random_play",
|
||||
"分钟后关机": "stop_after_minute",
|
||||
"播放列表": "play_music_list",
|
||||
"刷新列表": "gen_music_list",
|
||||
}
|
||||
|
||||
|
||||
def default_user_key_word_dict():
|
||||
return {
|
||||
"测试自定义口令": 'exec#code1("hello")',
|
||||
"测试链接": 'exec#httpget("https://github.com/hanxi/xiaomusic")',
|
||||
}
|
||||
|
||||
|
||||
# 命令参数在前面
|
||||
KEY_WORD_ARG_BEFORE_DICT = {
|
||||
"分钟后关机": True,
|
||||
}
|
||||
|
||||
|
||||
# 口令匹配优先级
|
||||
DEFAULT_KEY_MATCH_ORDER = [
|
||||
"set_volume#",
|
||||
"get_volume#",
|
||||
"分钟后关机",
|
||||
"播放歌曲",
|
||||
"下一首",
|
||||
"单曲循环",
|
||||
"全部循环",
|
||||
"随机播放",
|
||||
"关机",
|
||||
"刷新列表",
|
||||
"播放列表",
|
||||
]
|
||||
def default_key_match_order():
|
||||
return [
|
||||
"分钟后关机",
|
||||
"播放歌曲",
|
||||
"下一首",
|
||||
"单曲循环",
|
||||
"全部循环",
|
||||
"随机播放",
|
||||
"关机",
|
||||
"刷新列表",
|
||||
"播放列表",
|
||||
]
|
||||
|
||||
|
||||
@dataclass
|
||||
class Device:
|
||||
did: str = ""
|
||||
device_id: str = ""
|
||||
hardware: str = ""
|
||||
name: str = ""
|
||||
play_type: int = ""
|
||||
cur_music: str = ""
|
||||
cur_playlist: str = ""
|
||||
|
||||
|
||||
@dataclass
|
||||
class Config:
|
||||
hardware: str = os.getenv("MI_HARDWARE", "L07A")
|
||||
account: str = os.getenv("MI_USER", "")
|
||||
password: str = os.getenv("MI_PASS", "")
|
||||
mi_did: str = os.getenv("MI_DID", "")
|
||||
mi_did: str = os.getenv("MI_DID", "") # 逗号分割支持多设备
|
||||
cookie: str = ""
|
||||
verbose: bool = os.getenv("XIAOMUSIC_VERBOSE", "").lower() == "true"
|
||||
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
|
||||
conf_path: str = os.getenv("XIAOMUSIC_CONF_PATH", None)
|
||||
music_path: str = os.getenv(
|
||||
"XIAOMUSIC_MUSIC_PATH", "music"
|
||||
) # 只能是music目录下的子目录
|
||||
download_path: str = os.getenv("XIAOMUSIC_DOWNLOAD_PATH", "")
|
||||
conf_path: str = os.getenv("XIAOMUSIC_CONF_PATH", "conf")
|
||||
hostname: str = os.getenv("XIAOMUSIC_HOSTNAME", "192.168.2.5")
|
||||
port: int = int(os.getenv("XIAOMUSIC_PORT", "8090"))
|
||||
proxy: str | None = os.getenv("XIAOMUSIC_PROXY", None)
|
||||
port: int = int(os.getenv("XIAOMUSIC_PORT", "8090")) # 监听端口
|
||||
public_port: int = int(os.getenv("XIAOMUSIC_PUBLIC_PORT", 0)) # 歌曲访问端口
|
||||
proxy: str = os.getenv("XIAOMUSIC_PROXY", None)
|
||||
search_prefix: str = os.getenv(
|
||||
"XIAOMUSIC_SEARCH", "ytsearch:"
|
||||
"XIAOMUSIC_SEARCH", "bilisearch:"
|
||||
) # "bilisearch:" or "ytsearch:"
|
||||
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
|
||||
active_cmd: str = os.getenv(
|
||||
"XIAOMUSIC_ACTIVE_CMD", "play,random_play,playlocal,play_music_list,stop"
|
||||
"XIAOMUSIC_ACTIVE_CMD", "play,set_random_play,playlocal,play_music_list,stop"
|
||||
)
|
||||
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir")
|
||||
music_path_depth: int = int(os.getenv("XIAOMUSIC_MUSIC_PATH_DEPTH", "10"))
|
||||
disable_httpauth: bool = (
|
||||
os.getenv("XIAOMUSIC_DISABLE_HTTPAUTH", "true").lower() == "true"
|
||||
)
|
||||
httpauth_username: str = os.getenv("XIAOMUSIC_HTTPAUTH_USERNAME", "admin")
|
||||
httpauth_password: str = os.getenv("XIAOMUSIC_HTTPAUTH_PASSWORD", "admin")
|
||||
httpauth_username: str = os.getenv("XIAOMUSIC_HTTPAUTH_USERNAME", "")
|
||||
httpauth_password: str = os.getenv("XIAOMUSIC_HTTPAUTH_PASSWORD", "")
|
||||
music_list_url: str = os.getenv("XIAOMUSIC_MUSIC_LIST_URL", "")
|
||||
music_list_json: str = os.getenv("XIAOMUSIC_MUSIC_LIST_JSON", "")
|
||||
disable_download: bool = (
|
||||
os.getenv("XIAOMUSIC_DISABLE_DOWNLOAD", "false").lower() == "true"
|
||||
)
|
||||
key_word_dict = DEFAULT_KEY_WORD_DICT.copy()
|
||||
key_match_order = DEFAULT_KEY_MATCH_ORDER.copy()
|
||||
key_word_dict: dict[str, str] = field(default_factory=default_key_word_dict)
|
||||
key_match_order: list[str] = field(default_factory=default_key_match_order)
|
||||
use_music_api: bool = (
|
||||
os.getenv("XIAOMUSIC_USE_MUSIC_API", "false").lower() == "true"
|
||||
)
|
||||
log_file: str = os.getenv("XIAOMUSIC_MUSIC_LOG_FILE", "/tmp/xiaomusic.txt")
|
||||
use_music_audio_id: str = os.getenv(
|
||||
"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")
|
||||
# 模糊搜索匹配的最低相似度阈值
|
||||
fuzzy_match_cutoff: float = float(os.getenv("XIAOMUSIC_FUZZY_MATCH_CUTOFF", "0.6"))
|
||||
# 开启模糊搜索
|
||||
@@ -89,12 +116,26 @@ class Config:
|
||||
os.getenv("XIAOMUSIC_ENABLE_FUZZY_MATCH", "true").lower() == "true"
|
||||
)
|
||||
stop_tts_msg: str = os.getenv("XIAOMUSIC_STOP_TTS_MSG", "收到,再见")
|
||||
enable_config_example: bool = False
|
||||
|
||||
keywords_playlocal: str = os.getenv(
|
||||
"XIAOMUSIC_KEYWORDS_PLAYLOCAL", "播放本地歌曲,本地播放歌曲"
|
||||
)
|
||||
keywords_play: str = os.getenv("XIAOMUSIC_KEYWORDS_PLAY", "播放歌曲,放歌曲")
|
||||
keywords_stop: str = os.getenv("XIAOMUSIC_KEYWORDS_STOP", "关机,暂停,停止,停止播放")
|
||||
user_key_word_dict: dict[str, str] = field(
|
||||
default_factory=default_user_key_word_dict
|
||||
)
|
||||
enable_force_stop: bool = (
|
||||
os.getenv("XIAOMUSIC_ENABLE_FORCE_STOP", "false").lower() == "true"
|
||||
)
|
||||
devices: dict[str, Device] = field(default_factory=dict)
|
||||
group_list: str = os.getenv(
|
||||
"XIAOMUSIC_GROUP_LIST", ""
|
||||
) # did1:group_name,did2:group_name
|
||||
remove_id3tag: bool = (
|
||||
os.getenv("XIAOMUSIC_REMOVE_ID3TAG", "false").lower() == "true"
|
||||
)
|
||||
|
||||
def append_keyword(self, keys, action):
|
||||
for key in keys.split(","):
|
||||
@@ -102,17 +143,27 @@ class Config:
|
||||
if key not in self.key_match_order:
|
||||
self.key_match_order.append(key)
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.proxy:
|
||||
validate_proxy(self.proxy)
|
||||
def append_user_keyword(self):
|
||||
for k, v in self.user_key_word_dict.items():
|
||||
self.key_word_dict[k] = v
|
||||
self.key_match_order.append(k)
|
||||
|
||||
def init_keyword(self):
|
||||
self.append_keyword(self.keywords_playlocal, "playlocal")
|
||||
self.append_keyword(self.keywords_play, "play")
|
||||
self.append_keyword(self.keywords_stop, "stop")
|
||||
self.append_user_keyword()
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.proxy:
|
||||
validate_proxy(self.proxy)
|
||||
|
||||
self.init_keyword()
|
||||
# 保存配置到 config-example.json 文件
|
||||
# with open("config-example.json", "w") as f:
|
||||
# data = asdict(self)
|
||||
# json.dump(data, f, ensure_ascii=False, indent=4)
|
||||
if self.enable_config_example:
|
||||
with open("config-example.json", "w") as f:
|
||||
data = asdict(self)
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
|
||||
@classmethod
|
||||
def from_options(cls, options: argparse.Namespace) -> Config:
|
||||
@@ -124,12 +175,44 @@ class Config:
|
||||
config[key] = value
|
||||
return cls(**config)
|
||||
|
||||
@classmethod
|
||||
def convert_value(cls, k, v, type_hints):
|
||||
if v is not None and k in type_hints:
|
||||
expected_type = type_hints[k]
|
||||
try:
|
||||
if expected_type is bool:
|
||||
converted_value = False
|
||||
if str(v).lower() == "true":
|
||||
converted_value = True
|
||||
elif expected_type == dict[str, Device]:
|
||||
converted_value = {}
|
||||
for kk, vv in v.items():
|
||||
converted_value[kk] = Device(**vv)
|
||||
else:
|
||||
converted_value = expected_type(v)
|
||||
return converted_value
|
||||
except (ValueError, TypeError) as e:
|
||||
print(f"Error converting {k}:{v} to {expected_type}: {e}")
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def read_from_file(cls, config_path: str) -> dict:
|
||||
result = {}
|
||||
with open(config_path, "rb") as f:
|
||||
config = json.load(f)
|
||||
for key, value in config.items():
|
||||
if value is not None and key in cls.__dataclass_fields__:
|
||||
result[key] = value
|
||||
data = json.load(f)
|
||||
type_hints = get_type_hints(cls)
|
||||
|
||||
for k, v in data.items():
|
||||
converted_value = cls.convert_value(k, v, type_hints)
|
||||
if converted_value is not None:
|
||||
result[k] = converted_value
|
||||
return result
|
||||
|
||||
def update_config(self, data):
|
||||
type_hints = get_type_hints(self, globals(), locals())
|
||||
|
||||
for k, v in data.items():
|
||||
converted_value = self.convert_value(k, v, type_hints)
|
||||
if converted_value is not None:
|
||||
setattr(self, k, converted_value)
|
||||
self.init_keyword()
|
||||
|
||||
@@ -4,7 +4,18 @@ SUPPORT_MUSIC_TYPE = [
|
||||
".wav",
|
||||
".ape",
|
||||
".ogg",
|
||||
".m4a",
|
||||
]
|
||||
|
||||
LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation?source=dialogu&hardware={hardware}×tamp={timestamp}&limit=2"
|
||||
COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}"
|
||||
|
||||
PLAY_TYPE_ONE = 0 # 单曲循环
|
||||
PLAY_TYPE_ALL = 1 # 全部循环
|
||||
PLAY_TYPE_RND = 2 # 随机播放
|
||||
|
||||
PLAY_TYPE_TTS = {
|
||||
PLAY_TYPE_ONE: "已经设置为单曲循环",
|
||||
PLAY_TYPE_ALL: "已经设置为全部循环",
|
||||
PLAY_TYPE_RND: "已经设置为随机播放",
|
||||
}
|
||||
|
||||
@@ -1,161 +1,240 @@
|
||||
#!/usr/bin/env python3
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
from threading import Thread
|
||||
import secrets
|
||||
import shutil
|
||||
import tempfile
|
||||
from contextlib import asynccontextmanager
|
||||
from dataclasses import asdict
|
||||
from typing import Annotated
|
||||
|
||||
from flask import Flask, request, send_file, send_from_directory
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from waitress import serve
|
||||
from fastapi import Depends, FastAPI, HTTPException, Request, status
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from pydantic import BaseModel
|
||||
from starlette.background import BackgroundTask
|
||||
from starlette.responses import FileResponse
|
||||
|
||||
from xiaomusic import (
|
||||
__version__,
|
||||
)
|
||||
from xiaomusic import __version__
|
||||
from xiaomusic.utils import (
|
||||
deepcopy_data_no_sensitive_info,
|
||||
downloadfile,
|
||||
)
|
||||
|
||||
app = Flask(__name__)
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
host = "0.0.0.0"
|
||||
port = 8090
|
||||
static_path = "music"
|
||||
xiaomusic = None
|
||||
config = None
|
||||
log = None
|
||||
|
||||
|
||||
@auth.verify_password
|
||||
def verify_password(username, password):
|
||||
if xiaomusic.config.disable_httpauth:
|
||||
return True
|
||||
|
||||
if (
|
||||
xiaomusic.config.httpauth_username == username
|
||||
and xiaomusic.config.httpauth_password == password
|
||||
):
|
||||
return username
|
||||
@asynccontextmanager
|
||||
async def app_lifespan(app):
|
||||
if xiaomusic is not None:
|
||||
task = asyncio.create_task(xiaomusic.run_forever())
|
||||
yield
|
||||
task.cancel()
|
||||
|
||||
|
||||
@app.route("/allcmds")
|
||||
@auth.login_required
|
||||
def allcmds():
|
||||
return xiaomusic.config.key_word_dict
|
||||
security = HTTPBasic()
|
||||
|
||||
|
||||
@app.route("/getversion", methods=["GET"])
|
||||
def verification(
|
||||
credentials: Annotated[HTTPBasicCredentials, Depends(security)],
|
||||
):
|
||||
current_username_bytes = credentials.username.encode("utf8")
|
||||
correct_username_bytes = config.httpauth_username.encode("utf8")
|
||||
is_correct_username = secrets.compare_digest(
|
||||
current_username_bytes, correct_username_bytes
|
||||
)
|
||||
current_password_bytes = credentials.password.encode("utf8")
|
||||
correct_password_bytes = config.httpauth_password.encode("utf8")
|
||||
is_correct_password = secrets.compare_digest(
|
||||
current_password_bytes, correct_password_bytes
|
||||
)
|
||||
if not (is_correct_username and is_correct_password):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_401_UNAUTHORIZED,
|
||||
detail="Incorrect username or password",
|
||||
headers={"WWW-Authenticate": "Basic"},
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
def no_verification():
|
||||
return True
|
||||
|
||||
|
||||
app = FastAPI(
|
||||
lifespan=app_lifespan,
|
||||
version=__version__,
|
||||
dependencies=[Depends(verification)],
|
||||
)
|
||||
|
||||
|
||||
def reset_http_server():
|
||||
log.info(f"disable_httpauth:{config.disable_httpauth}")
|
||||
if config.disable_httpauth:
|
||||
app.dependency_overrides[verification] = no_verification
|
||||
else:
|
||||
app.dependency_overrides = {}
|
||||
|
||||
# 更新 music 链接
|
||||
app.router.routes = [route for route in app.router.routes if route.path != "/music"]
|
||||
app.mount(
|
||||
"/music",
|
||||
StaticFiles(directory=config.music_path, follow_symlink=True),
|
||||
name="music",
|
||||
)
|
||||
|
||||
|
||||
def HttpInit(_xiaomusic):
|
||||
global xiaomusic, config, log
|
||||
xiaomusic = _xiaomusic
|
||||
config = xiaomusic.config
|
||||
log = xiaomusic.log
|
||||
|
||||
folder = os.path.dirname(__file__)
|
||||
app.mount("/static", StaticFiles(directory=f"{folder}/static"), name="static")
|
||||
reset_http_server()
|
||||
|
||||
|
||||
@app.get("/")
|
||||
async def read_index():
|
||||
folder = os.path.dirname(__file__)
|
||||
return FileResponse(f"{folder}/static/index.html")
|
||||
|
||||
|
||||
@app.get("/getversion")
|
||||
def getversion():
|
||||
log.debug("getversion %s", __version__)
|
||||
return {
|
||||
"version": __version__,
|
||||
}
|
||||
return {"version": __version__}
|
||||
|
||||
|
||||
@app.route("/getvolume", methods=["GET"])
|
||||
@auth.login_required
|
||||
def getvolume():
|
||||
volume = xiaomusic.get_volume_ret()
|
||||
return {
|
||||
"volume": volume,
|
||||
}
|
||||
@app.get("/getvolume")
|
||||
async def getvolume(did: str = ""):
|
||||
if not xiaomusic.did_exist(did):
|
||||
return {"volume": 0}
|
||||
|
||||
volume = await xiaomusic.get_volume(did=did)
|
||||
return {"volume": volume}
|
||||
|
||||
|
||||
@app.route("/searchmusic", methods=["GET"])
|
||||
@auth.login_required
|
||||
def searchmusic():
|
||||
name = request.args.get("name")
|
||||
class DidVolume(BaseModel):
|
||||
did: str
|
||||
volume: int = 0
|
||||
|
||||
|
||||
@app.post("/setvolume")
|
||||
async def setvolume(data: DidVolume):
|
||||
did = data.did
|
||||
volume = data.volume
|
||||
if not xiaomusic.did_exist(did):
|
||||
return {"ret": "Did not exist"}
|
||||
|
||||
log.info(f"set_volume {did} {volume}")
|
||||
await xiaomusic.set_volume(did=did, arg1=volume)
|
||||
return {"ret": "OK", "volume": volume}
|
||||
|
||||
|
||||
@app.get("/searchmusic")
|
||||
def searchmusic(name: str = ""):
|
||||
return xiaomusic.searchmusic(name)
|
||||
|
||||
|
||||
@app.route("/playingmusic", methods=["GET"])
|
||||
@auth.login_required
|
||||
def playingmusic():
|
||||
return xiaomusic.playingmusic()
|
||||
@app.get("/playingmusic")
|
||||
def playingmusic(did: str = ""):
|
||||
if not xiaomusic.did_exist(did):
|
||||
return {"ret": "Did not exist"}
|
||||
|
||||
is_playing = xiaomusic.isplaying(did)
|
||||
cur_music = xiaomusic.playingmusic(did)
|
||||
return {
|
||||
"ret": "OK",
|
||||
"is_playing": is_playing,
|
||||
"cur_music": cur_music,
|
||||
}
|
||||
|
||||
|
||||
@app.route("/isplaying", methods=["GET"])
|
||||
@auth.login_required
|
||||
def isplaying():
|
||||
return xiaomusic.isplaying()
|
||||
class DidCmd(BaseModel):
|
||||
did: str
|
||||
cmd: str
|
||||
|
||||
|
||||
@app.route("/", methods=["GET"])
|
||||
def index():
|
||||
return send_from_directory("static", "index.html")
|
||||
@app.post("/cmd")
|
||||
async def do_cmd(data: DidCmd):
|
||||
did = data.did
|
||||
cmd = data.cmd
|
||||
log.info(f"docmd. did:{did} cmd:{cmd}")
|
||||
if not xiaomusic.did_exist(did):
|
||||
return {"ret": "Did not exist"}
|
||||
|
||||
|
||||
@app.route("/cmd", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def do_cmd():
|
||||
data = request.get_json()
|
||||
cmd = data.get("cmd")
|
||||
if len(cmd) > 0:
|
||||
log.debug("docmd. cmd:%s", cmd)
|
||||
xiaomusic.set_last_record(cmd)
|
||||
asyncio.create_task(xiaomusic.do_check_cmd(did=did, query=cmd))
|
||||
return {"ret": "OK"}
|
||||
return {"ret": "Unknow cmd"}
|
||||
|
||||
|
||||
@app.route("/getsetting", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def getsetting():
|
||||
@app.get("/getsetting")
|
||||
async def getsetting(need_device_list: bool = False):
|
||||
config = xiaomusic.getconfig()
|
||||
log.debug(config)
|
||||
|
||||
alldevices = await xiaomusic.call_main_thread_function(xiaomusic.getalldevices)
|
||||
log.info(alldevices)
|
||||
data = {
|
||||
"mi_did": config.mi_did,
|
||||
"mi_did_list": alldevices["did_list"],
|
||||
"mi_hardware": config.hardware,
|
||||
"mi_hardware_list": alldevices["hardware_list"],
|
||||
"xiaomusic_search": config.search_prefix,
|
||||
"xiaomusic_proxy": config.proxy,
|
||||
"xiaomusic_music_list_url": config.music_list_url,
|
||||
"xiaomusic_music_list_json": config.music_list_json,
|
||||
}
|
||||
data = asdict(config)
|
||||
if need_device_list:
|
||||
device_list = await xiaomusic.getalldevices()
|
||||
log.info(f"getsetting device_list: {device_list}")
|
||||
data["device_list"] = device_list
|
||||
return data
|
||||
|
||||
|
||||
@app.route("/savesetting", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def savesetting():
|
||||
data = request.get_json()
|
||||
log.info(data)
|
||||
await xiaomusic.saveconfig(data)
|
||||
return "save success"
|
||||
@app.post("/savesetting")
|
||||
async def savesetting(request: Request):
|
||||
try:
|
||||
data_json = await request.body()
|
||||
data = json.loads(data_json.decode("utf-8"))
|
||||
debug_data = deepcopy_data_no_sensitive_info(data)
|
||||
log.info(f"saveconfig: {debug_data}")
|
||||
await xiaomusic.saveconfig(data)
|
||||
reset_http_server()
|
||||
return "save success"
|
||||
except json.JSONDecodeError as err:
|
||||
raise HTTPException(status_code=400, detail="Invalid JSON") from err
|
||||
|
||||
|
||||
@app.route("/musiclist", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def musiclist():
|
||||
@app.get("/musiclist")
|
||||
async def musiclist(Verifcation=Depends(verification)):
|
||||
return xiaomusic.get_music_list()
|
||||
|
||||
|
||||
@app.route("/curplaylist", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def curplaylist():
|
||||
return xiaomusic.get_cur_play_list()
|
||||
@app.get("/curplaylist")
|
||||
async def curplaylist(did: str = ""):
|
||||
if not xiaomusic.did_exist(did):
|
||||
return ""
|
||||
return xiaomusic.get_cur_play_list(did)
|
||||
|
||||
|
||||
@app.route("/delmusic", methods=["POST"])
|
||||
@auth.login_required
|
||||
def delmusic():
|
||||
data = request.get_json()
|
||||
class MusicItem(BaseModel):
|
||||
name: str
|
||||
|
||||
|
||||
@app.post("/delmusic")
|
||||
def delmusic(data: MusicItem):
|
||||
log.info(data)
|
||||
xiaomusic.del_music(data["name"])
|
||||
xiaomusic.del_music(data.name)
|
||||
return "success"
|
||||
|
||||
|
||||
@app.route("/downloadjson", methods=["POST"])
|
||||
@auth.login_required
|
||||
def downloadjson():
|
||||
data = request.get_json()
|
||||
class UrlInfo(BaseModel):
|
||||
url: str
|
||||
|
||||
|
||||
@app.post("/downloadjson")
|
||||
async def downloadjson(data: UrlInfo):
|
||||
log.info(data)
|
||||
url = data["url"]
|
||||
url = data.url
|
||||
content = ""
|
||||
try:
|
||||
ret = "OK"
|
||||
content = downloadfile(url)
|
||||
content = await downloadfile(url)
|
||||
except Exception as e:
|
||||
log.warning(f"downloadjson failed. url:{url} e:{e}")
|
||||
log.exception(f"Execption {e}")
|
||||
ret = "Download JSON file failed."
|
||||
return {
|
||||
"ret": ret,
|
||||
@@ -163,54 +242,52 @@ def downloadjson():
|
||||
}
|
||||
|
||||
|
||||
@app.route("/downloadlog", methods=["GET"])
|
||||
@auth.login_required
|
||||
def downloadlog():
|
||||
return send_file(xiaomusic.config.log_file, as_attachment=True)
|
||||
@app.get("/downloadlog")
|
||||
def downloadlog(Verifcation=Depends(verification)):
|
||||
file_path = xiaomusic.config.log_file
|
||||
if os.path.exists(file_path):
|
||||
# 创建一个临时文件来保存日志的快照
|
||||
temp_file = tempfile.NamedTemporaryFile(delete=False)
|
||||
try:
|
||||
with open(file_path, "rb") as f:
|
||||
shutil.copyfileobj(f, temp_file)
|
||||
temp_file.close()
|
||||
|
||||
# 使用BackgroundTask在响应发送完毕后删除临时文件
|
||||
def cleanup_temp_file(tmp_file_path):
|
||||
os.remove(tmp_file_path)
|
||||
|
||||
background_task = BackgroundTask(cleanup_temp_file, temp_file.name)
|
||||
return FileResponse(
|
||||
temp_file.name,
|
||||
media_type="text/plain",
|
||||
filename="xiaomusic.txt",
|
||||
background=background_task,
|
||||
)
|
||||
except Exception as e:
|
||||
os.remove(temp_file.name)
|
||||
raise HTTPException(
|
||||
status_code=500, detail="Error capturing log file"
|
||||
) from e
|
||||
else:
|
||||
return {"message": "File not found."}
|
||||
|
||||
|
||||
@app.route("/playurl", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def playurl():
|
||||
url = request.args.get("url")
|
||||
log.info(f"play_url:{url}")
|
||||
return await xiaomusic.call_main_thread_function(xiaomusic.play_url, arg1=url)
|
||||
@app.get("/playurl")
|
||||
async def playurl(did: str, url: str):
|
||||
if not xiaomusic.did_exist(did):
|
||||
return {"ret": "Did not exist"}
|
||||
|
||||
log.info(f"playurl did: {did} url: {url}")
|
||||
return await xiaomusic.play_url(did=did, arg1=url)
|
||||
|
||||
|
||||
@app.route("/debug_play_by_music_url", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def debug_play_by_music_url():
|
||||
data = request.get_json()
|
||||
log.info(f"data:{data}")
|
||||
return await xiaomusic.call_main_thread_function(
|
||||
xiaomusic.debug_play_by_music_url, arg1=data
|
||||
)
|
||||
|
||||
|
||||
def static_path_handler(filename):
|
||||
log.debug(filename)
|
||||
log.debug(static_path)
|
||||
absolute_path = os.path.abspath(static_path)
|
||||
log.debug(absolute_path)
|
||||
return send_from_directory(absolute_path, filename)
|
||||
|
||||
|
||||
def run_app():
|
||||
serve(app, host=host, port=port)
|
||||
|
||||
|
||||
def StartHTTPServer(_port, _static_path, _xiaomusic):
|
||||
global port, static_path, xiaomusic, log
|
||||
port = _port
|
||||
static_path = _static_path
|
||||
xiaomusic = _xiaomusic
|
||||
log = xiaomusic.log
|
||||
|
||||
app.add_url_rule(
|
||||
f"/{static_path}/<path:filename>", "static_path_handler", static_path_handler
|
||||
)
|
||||
|
||||
server_thread = Thread(target=run_app)
|
||||
server_thread.daemon = True
|
||||
server_thread.start()
|
||||
xiaomusic.log.info(f"Serving on {host}:{port}")
|
||||
@app.post("/debug_play_by_music_url")
|
||||
async def debug_play_by_music_url(request: Request):
|
||||
try:
|
||||
data = await request.body()
|
||||
data_dict = json.loads(data.decode("utf-8"))
|
||||
log.info(f"data:{data_dict}")
|
||||
return await xiaomusic.debug_play_by_music_url(arg1=data_dict)
|
||||
except json.JSONDecodeError as err:
|
||||
raise HTTPException(status_code=400, detail="Invalid JSON") from err
|
||||
|
||||
69
xiaomusic/plugin.py
Normal file
69
xiaomusic/plugin.py
Normal file
@@ -0,0 +1,69 @@
|
||||
import importlib
|
||||
import inspect
|
||||
import pkgutil
|
||||
|
||||
|
||||
class PluginManager:
|
||||
def __init__(self, xiaomusic, plugin_dir="plugins"):
|
||||
self.xiaomusic = xiaomusic
|
||||
self.log = xiaomusic.log
|
||||
self._funcs = {}
|
||||
self._load_plugins(plugin_dir)
|
||||
|
||||
def _load_plugins(self, plugin_dir):
|
||||
# 假设 plugins 已经在搜索路径上
|
||||
package_name = plugin_dir
|
||||
package = importlib.import_module(package_name)
|
||||
|
||||
# 遍历 package 中所有模块并动态导入它们
|
||||
for _, modname, _ in pkgutil.iter_modules(package.__path__, package_name + "."):
|
||||
# 跳过__init__文件
|
||||
if modname.endswith("__init__"):
|
||||
continue
|
||||
module = importlib.import_module(modname)
|
||||
# 将 log 和 xiaomusic 注入模块的命名空间
|
||||
module.log = self.log
|
||||
module.xiaomusic = self.xiaomusic
|
||||
|
||||
# 动态获取模块中与文件名同名的函数
|
||||
function_name = modname.split(".")[-1] # 从模块全名提取函数名
|
||||
if hasattr(module, function_name):
|
||||
self._funcs[function_name] = getattr(module, function_name)
|
||||
else:
|
||||
self.log.error(
|
||||
f"No function named '{function_name}' found in module {modname}"
|
||||
)
|
||||
|
||||
def get_func(self, plugin_name):
|
||||
"""根据插件名获取插件函数"""
|
||||
return self._funcs.get(plugin_name)
|
||||
|
||||
def get_local_namespace(self):
|
||||
"""返回包含所有插件函数的字典,可以用作 exec 要执行的代码的命名空间"""
|
||||
return self._funcs.copy()
|
||||
|
||||
async def execute_plugin(self, code):
|
||||
"""
|
||||
执行指定的插件代码。插件函数可以是同步或异步。
|
||||
:param code: 需要执行的插件函数代码(例如 'plugin1("hello")')
|
||||
"""
|
||||
# 分解代码字符串以获取函数名
|
||||
func_name = code.split("(")[0]
|
||||
|
||||
# 根据解析出的函数名从插件字典中获取函数
|
||||
plugin_func = self.get_func(func_name)
|
||||
|
||||
if not plugin_func:
|
||||
raise ValueError(f"No plugin function named '{func_name}' found.")
|
||||
|
||||
# 检查函数是否是异步函数
|
||||
global_namespace = globals().copy()
|
||||
local_namespace = self.get_local_namespace()
|
||||
if inspect.iscoroutinefunction(plugin_func):
|
||||
# 如果是异步函数,构建执行用的协程对象
|
||||
coroutine = eval(code, global_namespace, local_namespace)
|
||||
# 等待协程执行
|
||||
await coroutine
|
||||
else:
|
||||
# 如果是普通函数,直接执行代码
|
||||
eval(code, global_namespace, local_namespace)
|
||||
@@ -1,8 +1,13 @@
|
||||
$(function(){
|
||||
$container=$("#cmds");
|
||||
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; // 随机播放
|
||||
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("关机");
|
||||
@@ -13,11 +18,61 @@ $(function(){
|
||||
append_op_button_name("30分钟后关机");
|
||||
append_op_button_name("60分钟后关机");
|
||||
|
||||
// 拉取声音
|
||||
sendcmd("get_volume#");
|
||||
$.get("/getvolume", function(data, status) {
|
||||
console.log(data, status, data["volume"]);
|
||||
$("#volume").val(data.volume);
|
||||
// 拉取现有配置
|
||||
$.get("/getsetting", function(data, status) {
|
||||
console.log(data, status);
|
||||
localStorage.setItem('mi_did', data.mi_did);
|
||||
|
||||
var did = localStorage.getItem('cur_did');
|
||||
var dids = [];
|
||||
if (data.mi_did != null) {
|
||||
dids = data.mi_did.split(',');
|
||||
}
|
||||
console.log('cur_did', did);
|
||||
console.log('dids', dids);
|
||||
if ((dids.length > 0) && (did == null || did == "" || !dids.includes(did))) {
|
||||
did = dids[0];
|
||||
localStorage.setItem('cur_did', did);
|
||||
}
|
||||
|
||||
window.did = did;
|
||||
$.get(`/getvolume?did=${did}`, function(data, status) {
|
||||
console.log(data, status, data["volume"]);
|
||||
$("#volume").val(data.volume);
|
||||
});
|
||||
refresh_music_list();
|
||||
|
||||
$("#did").empty();
|
||||
var dids = data.mi_did.split(',');
|
||||
$.each(dids, function(index, value) {
|
||||
var cur_device = Object.values(data.devices).find(device => device.did === value);
|
||||
if (cur_device) {
|
||||
var option = $('<option></option>')
|
||||
.val(value)
|
||||
.text(cur_device.name)
|
||||
.prop('selected', value === did);
|
||||
$("#did").append(option);
|
||||
|
||||
if (cur_device.play_type == PLAY_TYPE_ALL) {
|
||||
$("#play_type_all").css('background-color', '#b1a8f3');
|
||||
$("#play_type_all").text('✔️ 全部循环');
|
||||
} else if (cur_device.play_type == PLAY_TYPE_ONE) {
|
||||
$("#play_type_one").css('background-color', '#b1a8f3');
|
||||
$("#play_type_one").text('✔️ 单曲循环');
|
||||
} else if (cur_device.play_type == PLAY_TYPE_RND) {
|
||||
$("#play_type_rnd").css('background-color', '#b1a8f3');
|
||||
$("#play_type_rnd").text('✔️ 随机播放');
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
console.log('cur_did', did);
|
||||
$('#did').change(function() {
|
||||
did = $(this).val();
|
||||
localStorage.setItem('cur_did', did);
|
||||
window.did = did;
|
||||
console.log('cur_did', did);
|
||||
})
|
||||
});
|
||||
|
||||
// 拉取版本
|
||||
@@ -47,13 +102,20 @@ $(function(){
|
||||
$('#music_list').trigger('change');
|
||||
|
||||
// 获取当前播放列表
|
||||
$.get("curplaylist", function(data, status) {
|
||||
$('#music_list').val(data);
|
||||
$('#music_list').trigger('change');
|
||||
$.get(`curplaylist?did=${did}`, function(data, status) {
|
||||
if (data != "") {
|
||||
$('#music_list').val(data);
|
||||
$('#music_list').trigger('change');
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
// 每3秒获取下正在播放的音乐
|
||||
get_playing_music();
|
||||
setInterval(() => {
|
||||
get_playing_music();
|
||||
}, 3000);
|
||||
}
|
||||
refresh_music_list();
|
||||
|
||||
$("#play_music_list").on("click", () => {
|
||||
var music_list = $("#music_list").val();
|
||||
@@ -84,20 +146,23 @@ $(function(){
|
||||
|
||||
$("#playurl").on("click", () => {
|
||||
var url = $("#music-url").val();
|
||||
$.get(`/playurl?url=${url}`, function(data, status) {
|
||||
$.get(`/playurl?url=${url}&did=${did}`, function(data, status) {
|
||||
console.log(data);
|
||||
});
|
||||
});
|
||||
|
||||
function append_op_button_name(name) {
|
||||
append_op_button(name, name);
|
||||
append_op_button(null, name, name);
|
||||
}
|
||||
|
||||
function append_op_button(name, cmd) {
|
||||
function append_op_button(id, name, cmd) {
|
||||
// 创建按钮
|
||||
const $button = $("<button>");
|
||||
$button.text(name);
|
||||
$button.attr("type", "button");
|
||||
if (id !== null) {
|
||||
$button.attr("id", id);
|
||||
}
|
||||
|
||||
// 设置按钮点击事件
|
||||
$button.on("click", () => {
|
||||
@@ -115,9 +180,18 @@ $(function(){
|
||||
sendcmd(cmd);
|
||||
});
|
||||
|
||||
$("#volume").on('input', function () {
|
||||
$("#volume").on('change', function () {
|
||||
var value = $(this).val();
|
||||
sendcmd("set_volume#"+value);
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/setvolume",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({did: did, volume: value}),
|
||||
success: () => {
|
||||
},
|
||||
error: () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function sendcmd(cmd) {
|
||||
@@ -125,11 +199,14 @@ $(function(){
|
||||
type: "POST",
|
||||
url: "/cmd",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({cmd: cmd}),
|
||||
data: JSON.stringify({did: did, cmd: cmd}),
|
||||
success: () => {
|
||||
if (cmd == "刷新列表") {
|
||||
setTimeout(refresh_music_list, 3000);
|
||||
}
|
||||
if (["全部循环", "单曲循环", "随机播放"].includes(cmd)) {
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
error: () => {
|
||||
// 请求失败时执行的操作
|
||||
@@ -160,18 +237,18 @@ $(function(){
|
||||
});
|
||||
|
||||
function get_playing_music() {
|
||||
$.get("/playingmusic", function(data, status) {
|
||||
$.get(`/playingmusic?did=${did}`, function(data, status) {
|
||||
console.log(data);
|
||||
$("#playering-music").text(data);
|
||||
if (data.ret == "OK") {
|
||||
if (data.is_playing) {
|
||||
$("#playering-music").text(`【播放中】 ${data.cur_music}`);
|
||||
} else {
|
||||
$("#playering-music").text(`【空闲中】 ${data.cur_music}`);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 每3秒获取下正在播放的音乐
|
||||
get_playing_music();
|
||||
setInterval(() => {
|
||||
get_playing_music();
|
||||
}, 3000);
|
||||
|
||||
function custom_sort_key(a, b) {
|
||||
// 使用正则表达式提取数字前缀
|
||||
const numericPrefixA = a.match(/^(\d+)/) ? parseInt(a.match(/^(\d+)/)[1], 10) : null;
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Debug For XiaoMusic</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1721662254">
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script src="/static/jquery-3.7.1.min.js"></script>
|
||||
<script src="/static/jquery-3.7.1.min.js?version=1721662254"></script>
|
||||
|
||||
<script>
|
||||
var vConsole = new window.VConsole();
|
||||
@@ -27,13 +27,34 @@ function postJSON() {
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
function sendDebugCmd() {
|
||||
var cmd = $("#cmd").val();
|
||||
var did = localStorage.getItem('cur_did');
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/cmd",
|
||||
contentType: "application/json; charset=utf-8",
|
||||
data: JSON.stringify({did: did, cmd: cmd}),
|
||||
success: () => {
|
||||
},
|
||||
error: () => {
|
||||
// 请求失败时执行的操作
|
||||
}
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Debug For XiaoMusic</h1>
|
||||
<textarea id="post-input" rows="10" cols="50" placeholder="粘贴json数据..."></textarea><br>
|
||||
<button onclick="postJSON()">提交</button><br>
|
||||
|
||||
<hr>
|
||||
<input id="cmd" type="text"></input>
|
||||
<button onclick="sendDebugCmd()">测试自定义口令</button><br>
|
||||
</body>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
|
||||
@@ -3,17 +3,31 @@
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="/static/jquery-3.7.1.min.js"></script>
|
||||
<script src="/static/app.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
<script src="/static/jquery-3.7.1.min.js?version=1721662254"></script>
|
||||
<script src="/static/app.js?version=1721662254"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1721662254">
|
||||
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
var vConsole = new window.VConsole();
|
||||
</script>
|
||||
-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱操控面板
|
||||
(<a id="version" href="https://github.com/hanxi/xiaomusic/releases">
|
||||
(<a id="version" href="https://github.com/hanxi/xiaomusic/blob/main/CHANGELOG.md">
|
||||
版本未知
|
||||
</a>)
|
||||
</h2>
|
||||
<hr>
|
||||
|
||||
<div class="rows">
|
||||
<select id="did">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="cmds">
|
||||
</div>
|
||||
<hr>
|
||||
@@ -27,14 +41,14 @@
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div>
|
||||
<div class="rows">
|
||||
<datalist id="autocomplete-list"></datalist>
|
||||
<input id="music-name" type="text" placeholder="请输入搜索关键词(如:MV高清版 周杰伦 七里香)" list="autocomplete-list"></input>
|
||||
<input id="music-filename" type="text" placeholder="请输入保存为的文件名称(如:周杰伦七里香)"></input>
|
||||
</div>
|
||||
<button id="play">播放</button>
|
||||
<div class="container">
|
||||
<div id="playering-music" class="text"></div>
|
||||
<div>
|
||||
<button id="play">播放</button>
|
||||
<div id="playering-music" class="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
@@ -43,15 +57,17 @@
|
||||
<select id="music_list"></select>
|
||||
<label for="music_name">歌曲:</label>
|
||||
<select id="music_name"></select>
|
||||
<div>
|
||||
<button id="play_music_list">播放列表歌曲</button>
|
||||
<button id="del_music">删除选中歌曲</button>
|
||||
</div>
|
||||
</div>
|
||||
<button id="play_music_list">播放列表歌曲</button>
|
||||
<button id="del_music">删除选中歌曲</button>
|
||||
|
||||
<hr>
|
||||
<div>
|
||||
<input id="music-url" type="text" placeholder="链接(http://ngcdn001.cnr.cn/live/zgzs/index.m3u8)"></input>
|
||||
<div class="rows">
|
||||
<input id="music-url" type="text" value="https://lhttp.qtfm.cn/live/4915/64k.mp3"></input>
|
||||
<button id="playurl">播放链接</button>
|
||||
</div>
|
||||
<button id="playurl">播放链接</button>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>M3U to JSON Converter</title>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1721662254">
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
|
||||
@@ -3,38 +3,154 @@
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="/static/jquery-3.7.1.min.js"></script>
|
||||
<script src="/static/setting.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css">
|
||||
<script src="/static/jquery-3.7.1.min.js?version=1721662254"></script>
|
||||
<script src="/static/setting.js?version=1721662254"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1721662254">
|
||||
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
var vConsole = new window.VConsole();
|
||||
</script>
|
||||
-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱设置面板
|
||||
(<a id="version" href="https://github.com/hanxi/xiaomusic/releases">
|
||||
(<a id="version" href="https://github.com/hanxi/xiaomusic/blob/main/CHANGELOG.md">
|
||||
版本未知
|
||||
</a>)
|
||||
</h2>
|
||||
<hr>
|
||||
|
||||
<div class="rows">
|
||||
<label for="mi_did">MI_DID:</label>
|
||||
<select id="mi_did"></select>
|
||||
<label for="mi_hardware">MI_HARDWARE(型号):</label>
|
||||
<select id="mi_hardware" disabled></select>
|
||||
<label for="xiaomusic_search">XIAOMUSIC_SEARCH:</label>
|
||||
<select id="xiaomusic_search">
|
||||
<option value="ytsearch:">ytsearch:</option>
|
||||
<option value="bilisearch:">bilisearch:</option>
|
||||
</select>
|
||||
<label for="xiaomusic_proxy">XIAOMUSIC_PROXY(ytsearch需要):</label>
|
||||
<input id="xiaomusic_proxy" type="text" placeholder="http://192.168.2.5:8080"></input>
|
||||
<label for="xiaomusic_music_list_url">歌单地址:</label>
|
||||
<input id="xiaomusic_music_list_url" type="text" value="https://gist.githubusercontent.com/hanxi/dda82d964a28f8110f8fba81c3ff8314/raw/example.json"></input>
|
||||
<label for="xiaomusic_music_list_json">歌单内容:</label>
|
||||
<textarea id="xiaomusic_music_list_json" type="text"></textarea>
|
||||
<label for="mi_did">*勾选设备(至少勾选1个):</label>
|
||||
<div id="mi_did">
|
||||
</div>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div id="setting">
|
||||
<div class="rows">
|
||||
<label for="account">*小米账号:</label>
|
||||
<input id="account" type="text" placeholder="填写小米登录账号"></input>
|
||||
|
||||
<label for="password">*小米密码:</label>
|
||||
<input id="password" type="password" placeholder="填写小米登录密码"></input>
|
||||
|
||||
<label for="hostname">*XIAOMUSIC_HOSTNAME(IP或域名):</label>
|
||||
<input id="hostname" type="text"></input>
|
||||
|
||||
<label for="verbose">是否开启调试日志:</label>
|
||||
<select id="verbose">
|
||||
<option value="true" selected>true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
|
||||
<div>
|
||||
<button class="save-button">保存</button>
|
||||
<button onclick="location.href='/';">返回首页</button>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<label for="group_list">设备分组配置:</label>
|
||||
<input id="group_list" type="text" placeholder="did1:组名1,did2:组名1,did3:组名2"></input>
|
||||
|
||||
<label for="music_path">音乐目录:</label>
|
||||
<input id="music_path" type="text" value="music"></input>
|
||||
|
||||
<label for="download_path">音乐下载目录(必须是music的子目录):</label>
|
||||
<input id="download_path" type="text" value='music/download'></input>
|
||||
|
||||
<label for="conf_path">配置文件目录:</label>
|
||||
<input id="conf_path" type="text"></input>
|
||||
|
||||
<label for="ffmpeg_location">ffmpeg路径:</label>
|
||||
<input id="ffmpeg_location" type="text" value="./ffmpeg/bin"></input>
|
||||
|
||||
<label for="log_file">日志路径:</label>
|
||||
<input id="log_file" type="text" value="/tmp/xiaomusic.txt"></input>
|
||||
|
||||
<label for="active_cmd">允许唤醒的命令:</label>
|
||||
<input id="active_cmd" type="text" value="play,random_play,playlocal,play_music_list,stop"></input>
|
||||
|
||||
<label for="exclude_dirs">忽略目录(逗号分割):</label>
|
||||
<input id="exclude_dirs" type="text" value="@eaDir"></input>
|
||||
|
||||
<label for="music_path_depth">目录深度:</label>
|
||||
<input id="music_path_depth" type="number" value="10"></input>
|
||||
|
||||
<label for="search_prefix">XIAOMUSIC_SEARCH(歌曲下载方式):</label>
|
||||
<select id="search_prefix">
|
||||
<option value="bilisearch:">bilisearch:</option>
|
||||
<option value="ytsearch:">ytsearch:</option>
|
||||
</select>
|
||||
|
||||
<label for="proxy">XIAOMUSIC_PROXY(ytsearch需要):</label>
|
||||
<input id="proxy" type="text" placeholder="http://192.168.2.5:8080"></input>
|
||||
|
||||
<label for="disable_httpauth">关闭密码验证:</label>
|
||||
<select id="disable_httpauth">
|
||||
<option value="true" selected>true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
|
||||
<label for="remove_id3tag">去除MP3 ID3v2和填充,减少播放前延迟:</label>
|
||||
<select id="remove_id3tag">
|
||||
<option value="true" >true</option>
|
||||
<option value="false" selected>false</option>
|
||||
</select>
|
||||
|
||||
<label for="httpauth_username">web控制台账户:</label>
|
||||
<input id="httpauth_username" type="text" value=""></input>
|
||||
<label for="httpauth_password">web控制台密码:</label>
|
||||
<input id="httpauth_password" type="password" value=""></input>
|
||||
|
||||
<label for="disable_download">关闭下载功能:</label>
|
||||
<select id="disable_download">
|
||||
<option value="true">true</option>
|
||||
<option value="false" selected>false</option>
|
||||
</select>
|
||||
|
||||
<label for="use_music_audio_id">触屏版显示歌曲ID:</label>
|
||||
<input id="use_music_audio_id" type="text" value="1582971365183456177"></input>
|
||||
<label for="use_music_id">触屏版显示歌曲分段ID:</label>
|
||||
<input id="use_music_id" type="text" value="355454500"></input>
|
||||
|
||||
<label for="fuzzy_match_cutoff">模糊匹配阈值(0.1~0.9):</label>
|
||||
<input id="fuzzy_match_cutoff" type="number" value="0.6"></input>
|
||||
|
||||
<label for="enable_fuzzy_match">开启模糊搜索:</label>
|
||||
<select id="enable_fuzzy_match">
|
||||
<option value="true" selected>true</option>
|
||||
<option value="false">false</option>
|
||||
</select>
|
||||
|
||||
<label for="public_port">外网访问端口(0表示跟监听端口一致):</label>
|
||||
<input id="public_port" type="number" value="0"></input>
|
||||
|
||||
<label for="stop_tts_msg">停止提示音:</label>
|
||||
<input id="stop_tts_msg" type="text" value="收到,再见"></input>
|
||||
<label for="keywords_playlocal">播放本地歌曲口令:</label>
|
||||
<input id="keywords_playlocal" type="text" value="播放本地歌曲,本地播放歌曲"></input>
|
||||
<label for="keywords_play">播放歌曲口令:</label>
|
||||
<input id="keywords_play" type="text" value="播放歌曲,放歌曲"></input>
|
||||
<label for="keywords_stop">停止口令:</label>
|
||||
<input id="keywords_stop" type="text" value="关机,暂停,停止,停止播放"></input>
|
||||
|
||||
<label for="music_list_url">歌单地址:</label>
|
||||
<input id="music_list_url" type="text" value="https://gist.githubusercontent.com/hanxi/dda82d964a28f8110f8fba81c3ff8314/raw/example.json"></input>
|
||||
|
||||
<label for="music_list_json">歌单内容:</label>
|
||||
<textarea id="music_list_json" type="text"></textarea>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<button onclick="location.href='/';">返回首页</button>
|
||||
<button id="get_music_list">获取歌单</button>
|
||||
<button id="save">保存</button>
|
||||
<button class="save-button">保存</button>
|
||||
<a class="button" href="/downloadlog" download="xiaomusic.txt">下载日志文件</a>
|
||||
<hr>
|
||||
|
||||
|
||||
@@ -5,88 +5,100 @@ $(function(){
|
||||
$("#version").text(`${data.version}`);
|
||||
});
|
||||
|
||||
const updateSelectOptions = (selectId, optionsList, selectedOption) => {
|
||||
const select = $(selectId);
|
||||
select.empty();
|
||||
optionsList.forEach(option => {
|
||||
select.append(new Option(option, option));
|
||||
});
|
||||
select.val(selectedOption);
|
||||
};
|
||||
|
||||
let isChanging = false;
|
||||
// 更新下拉菜单的函数
|
||||
const updateSelect = (selectId, value) => {
|
||||
if (!isChanging) {
|
||||
isChanging = true;
|
||||
$(selectId).val(value);
|
||||
isChanging = false;
|
||||
}
|
||||
};
|
||||
|
||||
// 联动逻辑
|
||||
const linkSelects = (sourceSelect, sourceList, targetSelect, targetList) => {
|
||||
$(sourceSelect).change(function() {
|
||||
if (!isChanging) {
|
||||
const selectedValue = $(this).val();
|
||||
const selectedIndex = sourceList.indexOf(selectedValue);
|
||||
console.log(selectedIndex, selectedValue,sourceList,targetList)
|
||||
if (selectedIndex !== -1) {
|
||||
updateSelect(targetSelect, targetList[selectedIndex]);
|
||||
}
|
||||
// 遍历所有的select元素,默认选中只有1个选项的
|
||||
const autoSelectOne = () => {
|
||||
$('select').each(function() {
|
||||
// 如果select元素仅有一个option子元素
|
||||
if ($(this).children('option').length === 1) {
|
||||
// 选中这个option
|
||||
$(this).find('option').prop('selected', true);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function updateCheckbox(selector, mi_did, device_list) {
|
||||
// 清除现有的内容
|
||||
$(selector).empty();
|
||||
|
||||
// 将 mi_did 字符串通过逗号分割转换为数组,以便于判断默认选中项
|
||||
var selected_dids = mi_did.split(',');
|
||||
|
||||
$.each(device_list, function(index, device) {
|
||||
var did = device.miotDID;
|
||||
var hardware = device.hardware;
|
||||
var name = device.name;
|
||||
// 创建复选框元素
|
||||
var checkbox = $('<input>', {
|
||||
type: 'checkbox',
|
||||
id: did,
|
||||
value: `${did}`,
|
||||
class: 'custom-checkbox', // 添加样式类
|
||||
// 如果mi_did中包含了该did,则默认选中
|
||||
checked: selected_dids.indexOf(did) !== -1
|
||||
});
|
||||
|
||||
// 创建标签元素
|
||||
var label = $('<label>', {
|
||||
for: did,
|
||||
class: 'checkbox-label', // 添加样式类
|
||||
text: `【${hardware} ${did}】${name}` // 设定标签内容
|
||||
});
|
||||
|
||||
// 将复选框和标签添加到目标选择器元素中
|
||||
$(selector).append(checkbox).append(label);
|
||||
});
|
||||
}
|
||||
|
||||
function getSelectedDids(containerSelector) {
|
||||
var selectedDids = [];
|
||||
|
||||
// 仅选择给定容器中选中的复选框
|
||||
$(containerSelector + ' .custom-checkbox:checked').each(function() {
|
||||
var did = this.value;
|
||||
selectedDids.push(did);
|
||||
});
|
||||
|
||||
return selectedDids.join(',');
|
||||
}
|
||||
|
||||
// 拉取现有配置
|
||||
$.get("/getsetting", function(data, status) {
|
||||
$.get("/getsetting?need_device_list=true", function(data, status) {
|
||||
console.log(data, status);
|
||||
updateCheckbox("#mi_did", data.mi_did, data.device_list);
|
||||
|
||||
updateSelectOptions("#mi_did", data.mi_did_list, data.mi_did);
|
||||
updateSelectOptions("#mi_hardware", data.mi_hardware_list, data.mi_hardware);
|
||||
|
||||
// 初始化联动
|
||||
linkSelects('#mi_did', data.mi_did_list, '#mi_hardware', data.mi_hardware_list);
|
||||
|
||||
if (data.xiaomusic_search != "") {
|
||||
$("#xiaomusic_search").val(data.xiaomusic_search);
|
||||
// 初始化显示
|
||||
for (const key in data) {
|
||||
if (data.hasOwnProperty(key)) {
|
||||
const $element = $("#" + key);
|
||||
if ($element.length && data[key] !== '') {
|
||||
if (data[key] === true) {
|
||||
$element.val('true');
|
||||
} else if (data[key] === false) {
|
||||
$element.val('false');
|
||||
} else {
|
||||
$element.val(data[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.xiaomusic_proxy != "") {
|
||||
$("#xiaomusic_proxy").val(data.xiaomusic_proxy);
|
||||
}
|
||||
|
||||
if (data.xiaomusic_music_list_url != "") {
|
||||
$("#xiaomusic_music_list_url").val(data.xiaomusic_music_list_url);
|
||||
}
|
||||
|
||||
if (data.xiaomusic_music_list_json != "") {
|
||||
$("#xiaomusic_music_list_json").val(data.xiaomusic_music_list_json);
|
||||
}
|
||||
autoSelectOne();
|
||||
});
|
||||
|
||||
$("#save").on("click", () => {
|
||||
var mi_did = $("#mi_did").val();
|
||||
var mi_hardware = $("#mi_hardware").val();
|
||||
var xiaomusic_search = $("#xiaomusic_search").val();
|
||||
var xiaomusic_proxy = $("#xiaomusic_proxy").val();
|
||||
var xiaomusic_music_list_url = $("#xiaomusic_music_list_url").val();
|
||||
var xiaomusic_music_list_json = $("#xiaomusic_music_list_json").val();
|
||||
console.log("mi_did", mi_did);
|
||||
console.log("mi_hardware", mi_hardware);
|
||||
console.log("xiaomusic_search", xiaomusic_search);
|
||||
console.log("xiaomusic_proxy", xiaomusic_proxy);
|
||||
console.log("xiaomusic_music_list_url", xiaomusic_music_list_url);
|
||||
console.log("xiaomusic_music_list_json", xiaomusic_music_list_json);
|
||||
var data = {
|
||||
mi_did: mi_did,
|
||||
mi_hardware: mi_hardware,
|
||||
xiaomusic_search: xiaomusic_search,
|
||||
xiaomusic_proxy: xiaomusic_proxy,
|
||||
xiaomusic_music_list_url: xiaomusic_music_list_url,
|
||||
xiaomusic_music_list_json: xiaomusic_music_list_json,
|
||||
};
|
||||
$(".save-button").on("click", () => {
|
||||
var setting = $('#setting');
|
||||
var inputs = setting.find('input, select, textarea');
|
||||
var data = {};
|
||||
inputs.each(function() {
|
||||
var id = this.id;
|
||||
if (id) {
|
||||
data[id] = $(this).val();
|
||||
}
|
||||
});
|
||||
var did_list = getSelectedDids("#mi_did");
|
||||
data["mi_did"] = did_list;
|
||||
console.log(data)
|
||||
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
url: "/savesetting",
|
||||
@@ -94,6 +106,7 @@ $(function(){
|
||||
data: JSON.stringify(data),
|
||||
success: (msg) => {
|
||||
alert(msg);
|
||||
location.reload();
|
||||
},
|
||||
error: (msg) => {
|
||||
alert(msg);
|
||||
@@ -102,10 +115,10 @@ $(function(){
|
||||
});
|
||||
|
||||
$("#get_music_list").on("click", () => {
|
||||
var xiaomusic_music_list_url = $("#xiaomusic_music_list_url").val();
|
||||
console.log("xiaomusic_music_list_url", xiaomusic_music_list_url);
|
||||
var music_list_url = $("#music_list_url").val();
|
||||
console.log("music_list_url", music_list_url);
|
||||
var data = {
|
||||
url: xiaomusic_music_list_url,
|
||||
url: music_list_url,
|
||||
};
|
||||
$.ajax({
|
||||
type: "POST",
|
||||
@@ -114,7 +127,7 @@ $(function(){
|
||||
data: JSON.stringify(data),
|
||||
success: (res) => {
|
||||
if (res.ret == "OK") {
|
||||
$("#xiaomusic_music_list_json").val(res.content);
|
||||
$("#music_list_json").val(res.content);
|
||||
} else {
|
||||
console.log(res);
|
||||
alert(res.ret);
|
||||
|
||||
@@ -29,35 +29,6 @@ input,select {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
.container{
|
||||
width: 280px;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
@keyframes text-scroll {
|
||||
0% {
|
||||
left: 100%;
|
||||
}
|
||||
25% {
|
||||
left: 50%;
|
||||
}
|
||||
50% {
|
||||
left: 0%;
|
||||
}
|
||||
75% {
|
||||
left: -50%;
|
||||
}
|
||||
100% {
|
||||
left: -100%;
|
||||
}
|
||||
}
|
||||
.text {
|
||||
white-space: nowrap;
|
||||
font-weight: bold;
|
||||
position: relative;
|
||||
animation: text-scroll 10s linear infinite;
|
||||
}
|
||||
|
||||
.rows {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
@@ -77,3 +48,32 @@ footer {
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.custom-checkbox {
|
||||
display: inline-block;
|
||||
margin: 10px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
vertical-align: middle; /* 确保与标签垂直居中对齐 */
|
||||
}
|
||||
|
||||
.checkbox-label {
|
||||
display: inline-block;
|
||||
width: 260px;
|
||||
background-color: #fff;
|
||||
border: 0px solid #ccc;
|
||||
border-radius: 3px;
|
||||
position: relative;
|
||||
cursor: pointer;
|
||||
vertical-align: middle; /* 确保与复选框垂直居中对齐 */
|
||||
margin-left: 1px; /* 给复选框和标签之间一些距离,如果需要的话 */
|
||||
}
|
||||
|
||||
.text {
|
||||
margin: 10px;
|
||||
width: 150px;
|
||||
height: 50px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
#!/usr/bin/env python3
|
||||
from __future__ import annotations
|
||||
|
||||
import copy
|
||||
import difflib
|
||||
import mimetypes
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import string
|
||||
import tempfile
|
||||
from collections.abc import AsyncIterator
|
||||
@@ -13,7 +16,8 @@ from urllib.parse import urlparse
|
||||
|
||||
import aiohttp
|
||||
import mutagen
|
||||
import requests
|
||||
from mutagen.id3 import ID3
|
||||
from mutagen.mp3 import MP3
|
||||
from requests.utils import cookiejar_from_dict
|
||||
|
||||
from xiaomusic.const import SUPPORT_MUSIC_TYPE
|
||||
@@ -72,12 +76,21 @@ def validate_proxy(proxy_str: str) -> bool:
|
||||
|
||||
# 模糊搜索
|
||||
def fuzzyfinder(user_input, collection):
|
||||
return difflib.get_close_matches(user_input, collection, n=10, cutoff=0.1)
|
||||
lower_collection = {item.lower(): item for item in collection}
|
||||
user_input = user_input.lower()
|
||||
matches = difflib.get_close_matches(
|
||||
user_input, lower_collection.keys(), n=10, cutoff=0.1
|
||||
)
|
||||
return [lower_collection[match] for match in matches]
|
||||
|
||||
|
||||
def find_best_match(user_input, collection, cutoff=0.6):
|
||||
matches = difflib.get_close_matches(user_input, collection, n=1, cutoff=cutoff)
|
||||
return matches[0] if matches else None
|
||||
lower_collection = {item.lower(): item for item in collection}
|
||||
user_input = user_input.lower()
|
||||
matches = difflib.get_close_matches(
|
||||
user_input, lower_collection.keys(), n=1, cutoff=cutoff
|
||||
)
|
||||
return lower_collection[matches[0]] if matches else None
|
||||
|
||||
|
||||
# 歌曲排序
|
||||
@@ -100,83 +113,79 @@ def custom_sort_key(s):
|
||||
return (2, s)
|
||||
|
||||
|
||||
# fork from https://gist.github.com/dougthor42/001355248518bc64d2f8
|
||||
def walk_to_depth(root, depth=None, *args, **kwargs):
|
||||
"""
|
||||
Wrapper around os.walk that stops after going down `depth` folders.
|
||||
I had my own version, but it wasn't as efficient as
|
||||
http://stackoverflow.com/a/234329/1354930, so I modified to be more
|
||||
similar to nosklo's answer.
|
||||
However, nosklo's answer doesn't work if topdown=False, so I kept my
|
||||
version.
|
||||
"""
|
||||
# Let people use this as a standard `os.walk` function.
|
||||
if depth is None:
|
||||
return os.walk(root, *args, **kwargs)
|
||||
def _get_depth_path(root, directory, depth):
|
||||
# 计算当前目录的深度
|
||||
relative_path = root[len(directory) :].strip(os.sep)
|
||||
path_parts = relative_path.split(os.sep)
|
||||
if len(path_parts) >= depth:
|
||||
return os.path.join(directory, *path_parts[:depth])
|
||||
else:
|
||||
return root
|
||||
|
||||
# remove any trailing separators so that our counts are correct.
|
||||
root = root.rstrip(os.path.sep)
|
||||
|
||||
def main_func(root, depth, *args, **kwargs):
|
||||
"""Faster because it skips traversing dirs that are too deep."""
|
||||
root_depth = root.count(os.path.sep)
|
||||
for dirpath, dirnames, filenames in os.walk(root, *args, **kwargs):
|
||||
yield (dirpath, dirnames, filenames)
|
||||
def _append_files_result(result, root, joinpath, files, support_extension):
|
||||
dir_name = os.path.basename(root)
|
||||
if dir_name not in result:
|
||||
result[dir_name] = []
|
||||
for file in files:
|
||||
# 过滤隐藏文件
|
||||
if file.startswith("."):
|
||||
continue
|
||||
# 过滤文件后缀
|
||||
(name, extension) = os.path.splitext(file)
|
||||
if extension.lower() not in support_extension:
|
||||
continue
|
||||
|
||||
# calculate how far down we are.
|
||||
current_folder_depth = dirpath.count(os.path.sep)
|
||||
if current_folder_depth >= root_depth + depth:
|
||||
del dirnames[:]
|
||||
result[dir_name].append(os.path.join(joinpath, file))
|
||||
|
||||
def fallback_func(root, depth, *args, **kwargs):
|
||||
"""Slower, but works when topdown is False"""
|
||||
root_depth = root.count(os.path.sep)
|
||||
for dirpath, dirnames, filenames in os.walk(root, *args, **kwargs):
|
||||
current_folder_depth = dirpath.count(os.path.sep)
|
||||
if current_folder_depth <= root_depth + depth:
|
||||
yield (dirpath, dirnames, filenames)
|
||||
|
||||
# there's gotta be a better way do do this...
|
||||
try:
|
||||
if args[0] is False:
|
||||
yield from fallback_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
def traverse_music_directory(
|
||||
directory, depth=10, exclude_dirs=None, support_extension=None
|
||||
):
|
||||
result = {}
|
||||
for root, dirs, files in os.walk(directory, followlinks=True):
|
||||
# 忽略排除的目录
|
||||
dirs[:] = [d for d in dirs if d not in exclude_dirs]
|
||||
|
||||
# 计算当前目录的深度
|
||||
current_depth = root[len(directory) :].count(os.sep) + 1
|
||||
if current_depth > depth:
|
||||
depth_path = _get_depth_path(root, directory, depth - 1)
|
||||
_append_files_result(result, depth_path, root, files, support_extension)
|
||||
else:
|
||||
yield from main_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
except IndexError:
|
||||
pass
|
||||
|
||||
try:
|
||||
if kwargs["topdown"] is False:
|
||||
yield from fallback_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
else:
|
||||
yield from main_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
except KeyError:
|
||||
yield from main_func(root, depth, *args, **kwargs)
|
||||
return
|
||||
_append_files_result(result, root, root, files, support_extension)
|
||||
return result
|
||||
|
||||
|
||||
def downloadfile(url):
|
||||
async def downloadfile(url):
|
||||
# 清理和验证URL
|
||||
# 解析URL
|
||||
parsed_url = urlparse(url)
|
||||
|
||||
# 基础验证:仅允许HTTP和HTTPS协议
|
||||
if parsed_url.scheme not in ("http", "https"):
|
||||
raise Warning(
|
||||
f"Invalid URL scheme: {parsed_url.scheme}. Only HTTP and HTTPS are allowed."
|
||||
)
|
||||
|
||||
# 构建目标URL
|
||||
cleaned_url = parsed_url.geturl()
|
||||
|
||||
# 发起请求
|
||||
response = requests.get(cleaned_url, timeout=5) # 增加超时以避免长时间挂起
|
||||
response.raise_for_status() # 如果响应不是200,引发HTTPError异常
|
||||
return response.text
|
||||
# 使用 aiohttp 创建一个客户端会话来发起请求
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(
|
||||
cleaned_url, timeout=5
|
||||
) as response: # 增加超时以避免长时间挂起
|
||||
# 如果响应不是200,引发异常
|
||||
response.raise_for_status()
|
||||
# 读取响应文本
|
||||
text = await response.text()
|
||||
return text
|
||||
|
||||
|
||||
def is_mp3(url):
|
||||
mt = mimetypes.guess_type(url)
|
||||
if mt and mt[0] == "audio/mpeg":
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
async def _get_web_music_duration(session, url, start=0, end=500):
|
||||
@@ -189,7 +198,10 @@ async def _get_web_music_duration(session, url, start=0, end=500):
|
||||
name = tmp.name
|
||||
|
||||
try:
|
||||
m = mutagen.File(name)
|
||||
if is_mp3(url):
|
||||
m = mutagen.mp3.MP3(name)
|
||||
else:
|
||||
m = mutagen.File(name)
|
||||
duration = m.info.length
|
||||
except Exception:
|
||||
pass
|
||||
@@ -231,7 +243,10 @@ async def get_web_music_duration(url, start=0, end=500):
|
||||
def get_local_music_duration(filename):
|
||||
duration = 0
|
||||
try:
|
||||
m = mutagen.File(filename)
|
||||
if is_mp3(filename):
|
||||
m = mutagen.mp3.MP3(filename)
|
||||
else:
|
||||
m = mutagen.File(filename)
|
||||
duration = m.info.length
|
||||
except Exception:
|
||||
pass
|
||||
@@ -240,3 +255,80 @@ def get_local_music_duration(filename):
|
||||
|
||||
def get_random(length):
|
||||
return "".join(random.sample(string.ascii_letters + string.digits, length))
|
||||
|
||||
|
||||
# 深拷贝把敏感数据设置位*
|
||||
def deepcopy_data_no_sensitive_info(data, fields_to_anonymize=None):
|
||||
if fields_to_anonymize is None:
|
||||
fields_to_anonymize = [
|
||||
"account",
|
||||
"password",
|
||||
"httpauth_username",
|
||||
"httpauth_password",
|
||||
]
|
||||
|
||||
copy_data = copy.deepcopy(data)
|
||||
|
||||
# 检查copy_data是否是字典或具有属性的对象
|
||||
if isinstance(copy_data, dict):
|
||||
# 对字典进行处理
|
||||
for field in fields_to_anonymize:
|
||||
if field in copy_data:
|
||||
copy_data[field] = "******"
|
||||
else:
|
||||
# 对对象进行处理
|
||||
for field in fields_to_anonymize:
|
||||
if hasattr(copy_data, field):
|
||||
setattr(copy_data, field, "******")
|
||||
|
||||
return copy_data
|
||||
|
||||
|
||||
# k1:v1,k2:v2
|
||||
def parse_str_to_dict(s, d1=",", d2=":"):
|
||||
# 初始化一个空字典
|
||||
result = {}
|
||||
parts = s.split(d1)
|
||||
|
||||
for part in parts:
|
||||
# 根据冒号切割
|
||||
subparts = part.split(d2)
|
||||
if len(subparts) == 2: # 防止数据不是成对出现
|
||||
k, v = subparts
|
||||
result[k] = v
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# remove mp3 file id3 tag and padding to reduce delay
|
||||
def no_padding(info):
|
||||
# this will remove all padding
|
||||
return 0
|
||||
|
||||
|
||||
def remove_id3_tags(file_path):
|
||||
audio = MP3(file_path, ID3=ID3)
|
||||
change = False
|
||||
|
||||
# 检查是否存在ID3 v2.3或v2.4标签
|
||||
if audio.tags and (
|
||||
audio.tags.version == (2, 3, 0) or audio.tags.version == (2, 4, 0)
|
||||
):
|
||||
# 构造新文件的路径
|
||||
new_file_path = file_path + ".bak"
|
||||
|
||||
# 备份原始文件为新文件
|
||||
shutil.copy(file_path, new_file_path)
|
||||
|
||||
# 删除ID3标签
|
||||
audio.delete()
|
||||
|
||||
# 删除padding
|
||||
audio.save(padding=no_padding)
|
||||
|
||||
# 保存修改后的文件
|
||||
audio.save()
|
||||
|
||||
change = True
|
||||
|
||||
return change
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user