1
0
mirror of https://github.com/hanxi/xiaomusic.git synced 2025-12-07 15:02:55 +08:00

Compare commits

...

56 Commits

Author SHA1 Message Date
涵曦
cca6e47da5 bump: version 0.3.24 → 0.3.25 2024-08-16 11:18:21 +00:00
涵曦
415e75d4b4 build: update static version 2024-08-16 11:18:20 +00:00
涵曦
3c5573a2fc feat: 设置页面支持配置 use_music_api 选项 2024-08-16 11:18:11 +00:00
涵曦
7275b59d40 Update README.md 2024-08-08 09:35:17 +08:00
涵曦
a8d0631c33 bump: version 0.3.23 → 0.3.24 2024-08-01 23:47:58 +00:00
涵曦
3cfc96b779 build: update static version 2024-08-01 23:47:57 +00:00
涵曦
489f3f1d6f fix: #131 修复多设备切换时播放模式显示错误问题 2024-08-01 23:21:31 +00:00
涵曦
a5f2fc195e bump: version 0.3.22 → 0.3.23 2024-08-01 16:00:06 +00:00
涵曦
393dbabf4b build: update static version 2024-08-01 16:00:05 +00:00
涵曦
444e697f9d fix: 修复部分文件获取不到播放时长问题 2024-08-01 15:52:20 +00:00
涵曦
cf01039b53 fix: 处理安全问题 2024-08-01 00:46:18 +00:00
涵曦
a8fefc6f82 bump: version 0.3.21 → 0.3.22 2024-08-01 00:23:17 +00:00
涵曦
ae0b6066d9 build: update static version 2024-08-01 00:23:17 +00:00
涵曦
53f5e7db8c feat: 网关模式支持配置,默认关闭 2024-08-01 00:22:48 +00:00
涵曦
2a1fa9f8cf fix: 继续优化延迟问题 2024-08-01 00:05:19 +00:00
涵曦
6e2d674758 bump: version 0.3.20 → 0.3.21 2024-07-30 22:55:35 +00:00
涵曦
3bb6573ec0 build: update static version 2024-07-30 22:55:34 +00:00
涵曦
4ae3774a0e fix: 使用前置网关处理静态文件来加速,尝试解决延迟的问题 2024-07-30 11:49:29 +00:00
涵曦
b34215560c feat: 尝试加个网关在前面处理静态文件来加速文件获取 2024-07-30 11:36:51 +00:00
涵曦
4426017ba8 fix: 播放前先立即暂停之前的音乐 2024-07-30 11:36:35 +00:00
涵曦
f1635f8e32 build: 限定python版本必须是3.10和3.11 2024-07-30 06:41:52 +00:00
涵曦
4de032e193 bump: version 0.3.19 → 0.3.20 2024-07-30 06:09:27 +00:00
涵曦
d655157e1d build: update static version 2024-07-30 06:09:26 +00:00
涵曦
ff06958ab3 fix: 尝试修复延迟问题,修复播放停止不了的问题 2024-07-30 06:09:18 +00:00
涵曦
6e98b5ee2b bump: version 0.3.18 → 0.3.19 2024-07-30 01:59:32 +00:00
涵曦
da90fe2633 build: update static version 2024-07-30 01:59:31 +00:00
涵曦
eaedef452c fix: 调整配置,优化获取歌曲时长接口 2024-07-30 01:09:01 +00:00
涵曦
2d5f3799a3 bump: version 0.3.17 → 0.3.18 2024-07-29 10:16:10 +00:00
涵曦
b52bfe0848 build: update static version 2024-07-29 10:16:09 +00:00
涵曦
e2261b2d19 fix: #135 修复获取不到播放时长时只播放3秒的问题 2024-07-29 10:15:49 +00:00
涵曦
2443444165 Update release.yml 2024-07-29 05:51:04 +08:00
涵曦
7c912a51be bump: version 0.3.16 → 0.3.17 2024-07-28 21:42:49 +00:00
涵曦
bda55a1faa build: update static version 2024-07-28 21:42:48 +00:00
涵曦
5b5f957f8e fix: 优化日志输出,尝试排查延迟播放的问题 2024-07-28 21:42:23 +00:00
涵曦
12f54e3ad4 Update release.yml 2024-07-29 04:48:39 +08:00
quxiaozha
d6594e1270 Fix docker run command 2024-07-29 04:42:02 +08:00
涵曦
b678447417 bump: version 0.3.15 → 0.3.16 2024-07-28 13:58:52 +00:00
涵曦
02508f6997 build: update static version 2024-07-28 13:58:52 +00:00
涵曦
d50fff9e31 build: 修复版本打包问题 2024-07-28 13:58:44 +00:00
涵曦
2d7d7ddc95 bump: version 0.3.14 → 0.3.15 2024-07-28 13:07:36 +00:00
涵曦
9c9825d423 build: update static version 2024-07-28 13:07:35 +00:00
涵曦
f788c0f37b fix: 修复自定义口令重复的问题 2024-07-28 13:07:14 +00:00
涵曦
36d72d1eca fix: 修复日志输出问题 2024-07-28 12:59:32 +00:00
涵曦
6b17779c59 Update release.yml 2024-07-28 17:33:43 +08:00
涵曦
759130e38d fix: 修复退出异常问题 2024-07-28 08:48:39 +00:00
涵曦
49f727477e style: 优化日志输出,方便排查问题 2024-07-28 08:09:34 +00:00
涵曦
43886116c1 bump: version 0.3.13 → 0.3.14 2024-07-28 02:02:09 +00:00
涵曦
a38194027d build: update static version 2024-07-28 02:02:08 +00:00
涵曦
eab4f4bd46 feat: 优化播放延迟问题,并新增配置下一首播放的延迟秒数 2024-07-28 00:51:20 +00:00
涵曦
6b38676766 build: 打包优化 2024-07-26 14:21:43 +00:00
涵曦
3830f58c0b bump: version 0.3.12 → 0.3.13 2024-07-24 23:07:11 +00:00
涵曦
34cdea1731 build: update static version 2024-07-24 23:07:10 +00:00
涵曦
22f545b99c fix: 解决 docker 镜像问题 2024-07-24 21:58:28 +00:00
涵曦
37f73dc31f bump: version 0.3.11 → 0.3.12 2024-07-24 13:34:37 +00:00
涵曦
10e52f0b63 build: update static version 2024-07-24 13:34:36 +00:00
涵曦
b0ac1034d2 feat: 优化获取文件播放时长接口,尝试解决播放延迟和操作面板卡顿的问题 2024-07-24 01:47:46 +00:00
22 changed files with 725 additions and 772 deletions

View File

@@ -10,31 +10,25 @@ on:
workflow_dispatch:
jobs:
release-pypi:
name: Build and Release PyPI
pypi-publish:
name: upload release to PyPI
runs-on: ubuntu-latest
permissions:
contents: write
id-token: write
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- uses: actions/setup-python@v4
with:
python-version: "3.10"
- uses: pdm-project/setup-pdm@v3
- name: Publish package distributions to PyPI
run: pdm publish
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Build artifacts
run: |
pip install build
python -m build
- uses: pypa/gh-action-pypi-publish@release/v1
with:
password: ${{ secrets.PYPI_API_TOKEN }}
node-version: 16.x
- run: npx changelogithub
continue-on-error: true

View File

@@ -1,3 +1,95 @@
## v0.3.25 (2024-08-16)
### Feat
- 设置页面支持配置 use_music_api 选项
## v0.3.24 (2024-08-01)
### Fix
- #131 修复多设备切换时播放模式显示错误问题
## v0.3.23 (2024-08-01)
### Fix
- 修复部分文件获取不到播放时长问题
- 处理安全问题
## v0.3.22 (2024-08-01)
### Feat
- 网关模式支持配置,默认关闭
### Fix
- 继续优化延迟问题
## v0.3.21 (2024-07-30)
### Feat
- 尝试加个网关在前面处理静态文件来加速文件获取
### Fix
- 使用前置网关处理静态文件来加速,尝试解决延迟的问题
- 播放前先立即暂停之前的音乐
## v0.3.20 (2024-07-30)
### Fix
- 尝试修复延迟问题,修复播放停止不了的问题
## v0.3.19 (2024-07-30)
### Fix
- 调整配置,优化获取歌曲时长接口
## v0.3.18 (2024-07-29)
### Fix
- #135 修复获取不到播放时长时只播放3秒的问题
## v0.3.17 (2024-07-28)
### Fix
- 优化日志输出,尝试排查延迟播放的问题
## v0.3.16 (2024-07-28)
## v0.3.15 (2024-07-28)
### Fix
- 修复自定义口令重复的问题
- 修复日志输出问题
- 修复退出异常问题
## v0.3.14 (2024-07-28)
### Feat
- 优化播放延迟问题,并新增配置下一首播放的延迟秒数
## v0.3.13 (2024-07-24)
### Fix
- 解决 docker 镜像问题
## v0.3.12 (2024-07-24)
### Feat
- 优化获取文件播放时长接口,尝试解决播放延迟和操作面板卡顿的问题
## v0.3.11 (2024-07-22)
### Feat

View File

@@ -1,8 +1,13 @@
FROM python:3.10 AS builder
ENV DEBIAN_FRONTEND=noninteractive
RUN pip install -U pdm
ENV PDM_CHECK_UPDATE=false
WORKDIR /app
COPY requirements.txt .
RUN python3 -m venv .venv && .venv/bin/pip install --upgrade pip && .venv/bin/pip install --no-cache-dir -r requirements.txt
COPY pyproject.toml README.md .
COPY xiaomusic/ ./xiaomusic/
COPY plugins/ ./plugins/
COPY xiaomusic.py .
RUN pdm install --prod --no-editable
COPY install_dependencies.sh .
RUN bash install_dependencies.sh
@@ -13,7 +18,6 @@ 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 /app/conf

View File

@@ -37,7 +37,7 @@ services:
```yaml
docker run -p 8090:8090 \
-v ./music:/app/music \
-v ./conf:/app/conf
-v ./conf:/app/conf \
hanxi/xiaomusic
```
@@ -63,6 +63,8 @@ services:
XIAOMUSIC_PORT: 5678
```
如果不是首次修改端口,还需要修改 setting.json 文件里的端口。
遇到问题可以去 web 设置页面底部点击【下载日志文件】按钮,然后搜索一下日志文件内容确保里面没有账号密码信息后(有就删除这些敏感信息),然后在提 issues 反馈问题时把下载的日志文件带上。
> 目前除了 XIAOMUSIC_PORT 只能在启动前配置,其他参数都可以在 web 网页里配置。

159
pdm.lock generated
View File

@@ -4,16 +4,48 @@
[metadata]
groups = ["default", "dev", "lint"]
strategy = ["inherit_metadata"]
lock_version = "4.4.2"
content_hash = "sha256:fe8f356d82d38641f48975833c27c352829a895c3c3293c36e0e010a3202966e"
lock_version = "4.5.0"
content_hash = "sha256:0a0b1f63fdd9dd2c4ca2a777f12d294126a880631c1b3d48108d1df283ba14a8"
[[metadata.targets]]
requires_python = "==3.10.12"
platform = "manylinux_2_35_x86_64"
implementation = "cpython"
gil_disabled = false
[[package]]
name = "aiofiles"
version = "24.1.0"
requires_python = ">=3.8"
summary = "File support for asyncio."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5"},
{file = "aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c"},
]
[[package]]
name = "aiohappyeyeballs"
version = "2.3.4"
requires_python = "<4.0,>=3.8"
summary = "Happy Eyeballs for asyncio"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "aiohappyeyeballs-2.3.4-py3-none-any.whl", hash = "sha256:40a16ceffcf1fc9e142fd488123b2e218abc4188cf12ac20c67200e1579baa42"},
{file = "aiohappyeyeballs-2.3.4.tar.gz", hash = "sha256:7e1ae8399c320a8adec76f6c919ed5ceae6edd4c3672f4d9eae2b27e37c80ff6"},
]
[[package]]
name = "aiohttp"
version = "3.9.5"
version = "3.10.0"
requires_python = ">=3.8"
summary = "Async http client/server framework (asyncio)"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"aiohappyeyeballs>=2.3.0",
"aiosignal>=1.1.2",
"async-timeout<5.0,>=4.0; python_version < \"3.11\"",
"attrs>=17.3.0",
@@ -22,8 +54,8 @@ dependencies = [
"yarl<2.0,>=1.0",
]
files = [
{file = "aiohttp-3.9.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72"},
{file = "aiohttp-3.9.5.tar.gz", hash = "sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551"},
{file = "aiohttp-3.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06ef0135d7ab7fb0284342fbbf8e8ddf73b7fee8ecc55f5c3a3d0a6b765e6d8b"},
{file = "aiohttp-3.10.0.tar.gz", hash = "sha256:e8dd7da2609303e3574c95b0ec9f1fd49647ef29b94701a2862cceae76382e1d"},
]
[[package]]
@@ -32,6 +64,7 @@ version = "1.3.1"
requires_python = ">=3.7"
summary = "aiosignal: a list of registered asynchronous callbacks"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"frozenlist>=1.1.0",
]
@@ -46,6 +79,10 @@ version = "0.7.0"
requires_python = ">=3.8"
summary = "Reusable constraint types to use with typing.Annotated"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"typing-extensions>=4.0.0; python_version < \"3.9\"",
]
files = [
{file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"},
{file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"},
@@ -57,6 +94,7 @@ version = "4.4.0"
requires_python = ">=3.8"
summary = "High level compatibility layer for multiple asynchronous event loop implementations"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"exceptiongroup>=1.0.2; python_version < \"3.11\"",
"idna>=2.8",
@@ -74,6 +112,7 @@ version = "3.4.0"
requires_python = ">=3.8"
summary = "Bash tab completion for argparse"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "argcomplete-3.4.0-py3-none-any.whl", hash = "sha256:69a79e083a716173e5532e0fa3bef45f793f4e61096cf52b5a42c0211c8b8aa5"},
{file = "argcomplete-3.4.0.tar.gz", hash = "sha256:c2abcdfe1be8ace47ba777d4fce319eb13bf8ad9dace8d085dcad6eded88057f"},
@@ -85,7 +124,10 @@ version = "4.0.3"
requires_python = ">=3.7"
summary = "Timeout context manager for asyncio programs"
groups = ["default"]
marker = "python_version < \"3.11\""
marker = "python_full_version == \"3.10.12\""
dependencies = [
"typing-extensions>=3.6.5; python_version < \"3.8\"",
]
files = [
{file = "async-timeout-4.0.3.tar.gz", hash = "sha256:4640d96be84d82d02ed59ea2b7105a0f7b33abe8703703cd0ab0bf87c427522f"},
{file = "async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028"},
@@ -97,6 +139,10 @@ version = "23.2.0"
requires_python = ">=3.7"
summary = "Classes Without Boilerplate"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"importlib-metadata; python_version < \"3.8\"",
]
files = [
{file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"},
{file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"},
@@ -107,7 +153,7 @@ name = "brotli"
version = "1.1.0"
summary = "Python bindings for the Brotli compression library"
groups = ["default"]
marker = "implementation_name == \"cpython\""
marker = "implementation_name == \"cpython\" and python_full_version == \"3.10.12\""
files = [
{file = "Brotli-1.1.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752"},
{file = "Brotli-1.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9"},
@@ -154,6 +200,7 @@ version = "2024.7.4"
requires_python = ">=3.6"
summary = "Python package for providing Mozilla's CA Bundle."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
@@ -165,6 +212,7 @@ version = "3.3.2"
requires_python = ">=3.7.0"
summary = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
groups = ["default", "dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
{file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
@@ -221,6 +269,11 @@ version = "8.1.7"
requires_python = ">=3.7"
summary = "Composable command line interface toolkit"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"colorama; platform_system == \"Windows\"",
"importlib-metadata; python_version < \"3.8\"",
]
files = [
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
@@ -232,6 +285,7 @@ version = "0.4.6"
requires_python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
summary = "Cross-platform colored terminal text."
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
@@ -243,17 +297,20 @@ version = "3.28.0"
requires_python = ">=3.8"
summary = "Python commitizen client tool"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"argcomplete<3.5,>=1.12.1",
"charset-normalizer<4,>=2.1.0",
"colorama<0.5.0,>=0.4.1",
"decli<0.7.0,>=0.6.0",
"importlib-metadata<9,>=8.0.0; python_version < \"3.10\"",
"jinja2>=2.10.3",
"packaging>=19",
"pyyaml>=3.08",
"questionary<3.0,>=2.0",
"termcolor<3,>=1.1",
"tomlkit<1.0.0,>=0.5.3",
"typing-extensions<5.0.0,>=4.0.1; python_version < \"3.8\"",
]
files = [
{file = "commitizen-3.28.0-py3-none-any.whl", hash = "sha256:372dba10bb082be0e571cfa9ac0946f4333c3f4b2e242fbe32ae2f2afea143e4"},
@@ -266,6 +323,7 @@ version = "0.6.2"
requires_python = ">=3.7"
summary = "Minimal, easy-to-use, declarative cli tool"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "decli-0.6.2-py3-none-any.whl", hash = "sha256:2fc84106ce9a8f523ed501ca543bdb7e416c064917c12a59ebdc7f311a97b7ed"},
{file = "decli-0.6.2.tar.gz", hash = "sha256:36f71eb55fd0093895efb4f416ec32b7f6e00147dda448e3365cf73ceab42d6f"},
@@ -277,6 +335,7 @@ version = "2.6.1"
requires_python = ">=3.8"
summary = "DNS toolkit"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "dnspython-2.6.1-py3-none-any.whl", hash = "sha256:5ef3b9680161f6fa89daf8ad451b5f1a33b18ae8a1c6778cdf4b43f08c0a6e50"},
{file = "dnspython-2.6.1.tar.gz", hash = "sha256:e8f0f9c23a7b7cb99ded64e6c3a6f3e701d78f50c55e002b839dea7225cff7cc"},
@@ -288,6 +347,7 @@ version = "2.2.0"
requires_python = ">=3.8"
summary = "A robust email address syntax and deliverability validation library."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"dnspython>=2.0.0",
"idna>=2.0.0",
@@ -303,7 +363,7 @@ version = "1.2.2"
requires_python = ">=3.7"
summary = "Backport of PEP 654 (exception groups)"
groups = ["default"]
marker = "python_version < \"3.11\""
marker = "python_full_version == \"3.10.12\""
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
@@ -315,6 +375,7 @@ version = "0.111.1"
requires_python = ">=3.8"
summary = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"email-validator>=2.0.0",
"fastapi-cli>=0.0.2",
@@ -337,6 +398,7 @@ version = "0.0.4"
requires_python = ">=3.8"
summary = "Run and manage FastAPI apps from the command line with FastAPI CLI. 🚀"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"typer>=0.12.3",
]
@@ -351,6 +413,7 @@ version = "1.4.1"
requires_python = ">=3.8"
summary = "A list-like structure which implements collections.abc.MutableSequence"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:f9aa1878d1083b276b0196f2dfbe00c9b7e752475ed3b682025ff20c1c1f51ac"},
{file = "frozenlist-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:29acab3f66f0f24674b7dc4736477bcd4bc3ad4b896f5f45379a67bce8b96868"},
@@ -407,6 +470,10 @@ version = "0.14.0"
requires_python = ">=3.7"
summary = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"typing-extensions; python_version < \"3.8\"",
]
files = [
{file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"},
{file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"},
@@ -418,6 +485,7 @@ version = "1.0.5"
requires_python = ">=3.8"
summary = "A minimal low-level HTTP client."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"certifi",
"h11<0.15,>=0.13",
@@ -433,6 +501,7 @@ version = "0.6.1"
requires_python = ">=3.8.0"
summary = "A collection of framework independent HTTP protocol utils."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"},
{file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"},
@@ -464,6 +533,7 @@ version = "0.27.0"
requires_python = ">=3.8"
summary = "The next generation HTTP client."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"anyio",
"certifi",
@@ -482,6 +552,7 @@ version = "3.7"
requires_python = ">=3.5"
summary = "Internationalized Domain Names in Applications (IDNA)"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
@@ -493,6 +564,7 @@ version = "3.1.4"
requires_python = ">=3.7"
summary = "A very fast and expressive template engine."
groups = ["default", "dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"MarkupSafe>=2.0",
]
@@ -507,6 +579,7 @@ version = "3.0.0"
requires_python = ">=3.8"
summary = "Python port of markdown-it. Markdown parsing, done right!"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"mdurl~=0.1",
]
@@ -521,6 +594,7 @@ version = "2.1.5"
requires_python = ">=3.7"
summary = "Safely add untrusted strings to HTML/XML markup."
groups = ["default", "dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
{file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
@@ -561,6 +635,7 @@ version = "0.1.2"
requires_python = ">=3.7"
summary = "Markdown URL utilities"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"},
{file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"},
@@ -572,6 +647,7 @@ version = "2.7.0"
requires_python = ">=3.8"
summary = "XiaoMi Cloud Service fork from https://github.com/Yonsm/MiService"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"aiohttp",
"mutagen",
@@ -588,6 +664,7 @@ version = "6.0.5"
requires_python = ">=3.7"
summary = "multidict implementation"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "multidict-6.0.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:228b644ae063c10e7f324ab1ab6b548bdf6f8b47f3ec234fef1093bc2735e5f9"},
{file = "multidict-6.0.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:896ebdcf62683551312c30e20614305f53125750803b614e9e6ce74a96232604"},
@@ -644,6 +721,7 @@ version = "1.47.0"
requires_python = ">=3.7"
summary = "read and write audio tags for many formats"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "mutagen-1.47.0-py3-none-any.whl", hash = "sha256:edd96f50c5907a9539d8e5bba7245f62c9f520aef333d13392a79a4f70aca719"},
{file = "mutagen-1.47.0.tar.gz", hash = "sha256:719fadef0a978c31b4cf3c956261b3c58b6948b32023078a2117b1de09f0fc99"},
@@ -655,6 +733,7 @@ version = "24.1"
requires_python = ">=3.8"
summary = "Core utilities for Python packages"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
{file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
@@ -666,6 +745,7 @@ version = "3.0.36"
requires_python = ">=3.6.2"
summary = "Library for building powerful interactive command lines in Python"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"wcwidth",
]
@@ -680,6 +760,7 @@ version = "3.20.0"
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
summary = "Cryptographic library for Python"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_universal2.whl", hash = "sha256:59af01efb011b0e8b686ba7758d59cf4a8263f9ad35911bfe3f416cee4f5c08c"},
{file = "pycryptodomex-3.20.0-cp35-abi3-macosx_10_9_x86_64.whl", hash = "sha256:82ee7696ed8eb9a82c7037f32ba9b7c59e51dda6f105b39f043b6ef293989cb3"},
@@ -704,9 +785,11 @@ version = "2.8.2"
requires_python = ">=3.8"
summary = "Data validation using Python type hints"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"annotated-types>=0.4.0",
"pydantic-core==2.20.1",
"typing-extensions>=4.12.2; python_version >= \"3.13\"",
"typing-extensions>=4.6.1; python_version < \"3.13\"",
]
files = [
@@ -720,6 +803,7 @@ version = "2.20.1"
requires_python = ">=3.8"
summary = "Core functionality for Pydantic validation and serialization"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"typing-extensions!=4.7.0,>=4.6.0",
]
@@ -789,6 +873,7 @@ version = "2.18.0"
requires_python = ">=3.8"
summary = "Pygments is a syntax highlighting package written in Python."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"},
{file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"},
@@ -800,6 +885,7 @@ version = "1.0.1"
requires_python = ">=3.8"
summary = "Read key-value pairs from a .env file and set them as environment variables"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "python-dotenv-1.0.1.tar.gz", hash = "sha256:e324ee90a023d808f1959c46bcbc04446a10ced277783dc6ee09987c37ec10ca"},
{file = "python_dotenv-1.0.1-py3-none-any.whl", hash = "sha256:f7b63ef50f1b690dddf550d03497b66d609393b40b564ed0d674909a68ebf16a"},
@@ -811,6 +897,7 @@ version = "0.0.9"
requires_python = ">=3.8"
summary = "A streaming multipart parser for Python"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "python_multipart-0.0.9-py3-none-any.whl", hash = "sha256:97ca7b8ea7b05f977dc3849c3ba99d51689822fab725c3703af7c866a0c2b215"},
{file = "python_multipart-0.0.9.tar.gz", hash = "sha256:03f54688c663f1b7977105f021043b0793151e4cb1c1a9d4a11fc13d622c4026"},
@@ -822,6 +909,7 @@ version = "6.0.1"
requires_python = ">=3.6"
summary = "YAML parser and emitter for Python"
groups = ["default", "dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"},
{file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"},
@@ -855,6 +943,7 @@ version = "2.0.1"
requires_python = ">=3.8"
summary = "Python library to build pretty command line user prompts ⭐️"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"prompt-toolkit<=3.0.36,>=2.0",
]
@@ -869,6 +958,7 @@ version = "2.32.3"
requires_python = ">=3.8"
summary = "Python HTTP for Humans."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"certifi>=2017.4.17",
"charset-normalizer<4,>=2",
@@ -886,9 +976,11 @@ version = "13.7.1"
requires_python = ">=3.7.0"
summary = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"markdown-it-py>=2.2.0",
"pygments<3.0.0,>=2.13.0",
"typing-extensions<5.0,>=4.0.0; python_version < \"3.9\"",
]
files = [
{file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"},
@@ -897,13 +989,14 @@ files = [
[[package]]
name = "ruff"
version = "0.5.3"
version = "0.5.5"
requires_python = ">=3.7"
summary = "An extremely fast Python linter and code formatter, written in Rust."
groups = ["lint"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "ruff-0.5.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03bfe9ab5bdc0b08470c3b261643ad54ea86edc32b64d1e080892d7953add3ad"},
{file = "ruff-0.5.3.tar.gz", hash = "sha256:2a3eb4f1841771fa5b67a56be9c2d16fd3cc88e378bd86aaeaec2f7e6bcdd0a2"},
{file = "ruff-0.5.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3687d002f911e8a5faf977e619a034d159a8373514a587249cc00f211c67a091"},
{file = "ruff-0.5.5.tar.gz", hash = "sha256:cc5516bdb4858d972fbc31d246bdb390eab8df1a26e2353be2dbc0c2d7f5421a"},
]
[[package]]
@@ -912,6 +1005,7 @@ version = "1.5.4"
requires_python = ">=3.7"
summary = "Tool to Detect Surrounding Shell"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"},
{file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"},
@@ -923,6 +1017,7 @@ version = "1.3.1"
requires_python = ">=3.7"
summary = "Sniff out which async library your code is running under"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
@@ -934,8 +1029,10 @@ version = "0.37.2"
requires_python = ">=3.8"
summary = "The little ASGI library that shines."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"anyio<5,>=3.4.0",
"typing-extensions>=3.10.0; python_version < \"3.10\"",
]
files = [
{file = "starlette-0.37.2-py3-none-any.whl", hash = "sha256:6fe59f29268538e5d0d182f2791a479a0c64638e6935d1c6989e63fb2699c6ee"},
@@ -948,6 +1045,7 @@ version = "2.4.0"
requires_python = ">=3.8"
summary = "ANSI color formatting for output in terminal"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "termcolor-2.4.0-py3-none-any.whl", hash = "sha256:9297c0df9c99445c2412e832e882a7884038a25617c60cea2ad69488d4040d63"},
{file = "termcolor-2.4.0.tar.gz", hash = "sha256:aab9e56047c8ac41ed798fa36d892a37aca6b3e9159f3e0c24bc64a9b3ac7b7a"},
@@ -959,6 +1057,7 @@ version = "0.13.0"
requires_python = ">=3.8"
summary = "Style preserving TOML library"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "tomlkit-0.13.0-py3-none-any.whl", hash = "sha256:7075d3042d03b80f603482d69bf0c8f345c2b30e41699fd8883227f89972b264"},
{file = "tomlkit-0.13.0.tar.gz", hash = "sha256:08ad192699734149f5b97b45f1f18dad7eb1b6d16bc72ad0c2335772650d7b72"},
@@ -970,6 +1069,7 @@ version = "0.12.3"
requires_python = ">=3.7"
summary = "Typer, build great CLIs. Easy to code. Based on Python type hints."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"click>=8.0.0",
"rich>=10.11.0",
@@ -987,6 +1087,7 @@ version = "4.12.2"
requires_python = ">=3.8"
summary = "Backported and Experimental Type Hints for Python 3.8+"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
@@ -998,6 +1099,7 @@ version = "2.2.2"
requires_python = ">=3.8"
summary = "HTTP library with thread-safe connection pooling, file post, and more."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
{file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
@@ -1005,39 +1107,42 @@ files = [
[[package]]
name = "uvicorn"
version = "0.30.1"
version = "0.30.4"
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"click>=7.0",
"h11>=0.8",
"typing-extensions>=4.0; python_version < \"3.11\"",
]
files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"},
{file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"},
{file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"},
]
[[package]]
name = "uvicorn"
version = "0.30.1"
version = "0.30.4"
extras = ["standard"]
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"colorama>=0.4; sys_platform == \"win32\"",
"httptools>=0.5.0",
"python-dotenv>=0.13",
"pyyaml>=5.1",
"uvicorn==0.30.1",
"uvicorn==0.30.4",
"uvloop!=0.15.0,!=0.15.1,>=0.14.0; (sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\"",
"watchfiles>=0.13",
"websockets>=10.4",
]
files = [
{file = "uvicorn-0.30.1-py3-none-any.whl", hash = "sha256:cd17daa7f3b9d7a24de3617820e634d0933b69eed8e33a516071174427238c81"},
{file = "uvicorn-0.30.1.tar.gz", hash = "sha256:d46cd8e0fd80240baffbcd9ec1012a712938754afcf81bce56c024c1656aece8"},
{file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"},
{file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"},
]
[[package]]
@@ -1046,7 +1151,7 @@ version = "0.19.0"
requires_python = ">=3.8.0"
summary = "Fast implementation of asyncio event loop on top of libuv"
groups = ["default"]
marker = "(sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\""
marker = "(sys_platform != \"cygwin\" and sys_platform != \"win32\") and platform_python_implementation != \"PyPy\" and python_full_version == \"3.10.12\""
files = [
{file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"},
{file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"},
@@ -1075,6 +1180,7 @@ version = "0.22.0"
requires_python = ">=3.8"
summary = "Simple, modern and high performance file watching and code reload in python."
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"anyio>=3.0.0",
]
@@ -1129,6 +1235,10 @@ name = "wcwidth"
version = "0.2.13"
summary = "Measures the displayed width of unicode strings in a terminal"
groups = ["dev"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"backports-functools-lru-cache>=1.2.1; python_version < \"3.2\"",
]
files = [
{file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"},
{file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"},
@@ -1140,6 +1250,7 @@ version = "12.0"
requires_python = ">=3.8"
summary = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
files = [
{file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"},
{file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"},
@@ -1189,9 +1300,11 @@ version = "1.9.4"
requires_python = ">=3.7"
summary = "Yet another URL library"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"idna>=2.0",
"multidict>=4.0",
"typing-extensions>=3.7.4; python_version < \"3.8\"",
]
files = [
{file = "yarl-1.9.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a8c1df72eb746f4136fe9a2e72b0c9dc1da1cbd23b5372f94b5820ff8ae30e0e"},
@@ -1245,12 +1358,14 @@ files = [
[[package]]
name = "yt-dlp"
version = "2024.7.16"
version = "2024.8.1"
requires_python = ">=3.8"
summary = "A feature-rich command-line audio/video downloader"
groups = ["default"]
marker = "python_full_version == \"3.10.12\""
dependencies = [
"brotli; implementation_name == \"cpython\"",
"brotlicffi; implementation_name != \"cpython\"",
"certifi",
"mutagen",
"pycryptodomex",
@@ -1259,6 +1374,6 @@ dependencies = [
"websockets>=12.0",
]
files = [
{file = "yt_dlp-2024.7.16-py3-none-any.whl", hash = "sha256:424805a112e757b141e767bc938d49db56d13d6415a92fa4cd8acadd55790be0"},
{file = "yt_dlp-2024.7.16.tar.gz", hash = "sha256:c5bd517a49dea1923ec8e14f51858f10fd89dfece14cb701392b480b41b2f516"},
{file = "yt_dlp-2024.8.1-py3-none-any.whl", hash = "sha256:d0d927038e30a05f6eab26ff6189628456ea21bb159a3d9dc2e855eef2810eac"},
{file = "yt_dlp-2024.8.1.tar.gz", hash = "sha256:4318aa523694611562f01419c8d526b662a72df34ef8ba454016b34c8366c158"},
]

View File

@@ -1,6 +1,6 @@
[project]
name = "xiaomusic"
version = "0.3.11"
version = "0.3.25"
description = "Play Music with xiaomi AI speaker"
authors = [
{name = "涵曦", email = "im.hanxi@gmail.com"},
@@ -13,8 +13,9 @@ dependencies = [
"uvicorn>=0.30.1",
"fastapi>=0.111.0",
"starlette>=0.37.2",
"aiofiles>=24.1.0",
]
requires-python = ">=3.10"
requires-python = ">=3.10,<3.12"
readme = "README.md"
license = {text = "MIT"}

View File

@@ -1,603 +0,0 @@
# This file is @generated by PDM.
# Please do not edit it manually.
aiohttp==3.9.5 \
--hash=sha256:c26959ca7b75ff768e2776d8055bf9582a6267e24556bb7f7bd29e677932be72 \
--hash=sha256:edea7d15772ceeb29db4aff55e482d4bcfb6ae160ce144f2682de02f6d693551
aiosignal==1.3.1 \
--hash=sha256:54cd96e15e1649b75d6c87526a6ff0b6c1b0dd3459f43d9ca11d48c339b68cfc \
--hash=sha256:f8376fb07dd1e86a584e4fcdec80b36b7f81aac666ebc724e2c090300dd83b17
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.2.0 \
--hash=sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30 \
--hash=sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1
brotli==1.1.0; implementation_name == "cpython" \
--hash=sha256:0c6244521dda65ea562d5a69b9a26120769b7a9fb3db2fe9545935ed6735b128 \
--hash=sha256:19c116e796420b0cee3da1ccec3b764ed2952ccfcc298b55a10e5610ad7885f9 \
--hash=sha256:1ae56aca0402a0f9a3431cddda62ad71666ca9d4dc3a10a142b9dce2e3c0cda3 \
--hash=sha256:30924eb4c57903d5a7526b08ef4a584acc22ab1ffa085faceb521521d2de32dd \
--hash=sha256:316cc9b17edf613ac76b1f1f305d2a748f1b976b033b049a6ecdfd5612c70409 \
--hash=sha256:38025d9f30cf4634f8309c6874ef871b841eb3c347e90b0851f63d1ded5212da \
--hash=sha256:39da8adedf6942d76dc3e46653e52df937a3c4d6d18fdc94a7c29d263b1f5b50 \
--hash=sha256:4093c631e96fdd49e0377a9c167bfd75b6d0bad2ace734c6eb20b348bc3ea180 \
--hash=sha256:43ce1b9935bfa1ede40028054d7f48b5469cd02733a365eec8a329ffd342915d \
--hash=sha256:4ed11165dd45ce798d99a136808a794a748d5dc38511303239d4e2363c0695dc \
--hash=sha256:510b5b1bfbe20e1a7b3baf5fed9e9451873559a976c1a78eebaa3b86c57b4265 \
--hash=sha256:524f35912131cc2cabb00edfd8d573b07f2d9f21fa824bd3fb19725a9cf06327 \
--hash=sha256:5b3cc074004d968722f51e550b41a27be656ec48f8afaeeb45ebf65b561481dd \
--hash=sha256:5f4d5ea15c9382135076d2fb28dde923352fe02951e66935a9efaac8f10e81b0 \
--hash=sha256:6c3020404e0b5eefd7c9485ccf8393cfb75ec38ce75586e046573c9dc29967a0 \
--hash=sha256:70051525001750221daa10907c77830bc889cb6d865cc0b813d9db7fefc21451 \
--hash=sha256:7c4855522edb2e6ae7fdb58e07c3ba9111e7621a8956f481c68d5d979c93032e \
--hash=sha256:7e4c4629ddad63006efa0ef968c8e4751c5868ff0b1c5c40f76524e894c50248 \
--hash=sha256:7f4bf76817c14aa98cc6697ac02f3972cb8c3da93e9ef16b9c66573a68014f91 \
--hash=sha256:81de08ac11bcb85841e440c13611c00b67d3bf82698314928d0b676362546724 \
--hash=sha256:861bf317735688269936f755fa136a99d1ed526883859f86e41a5d43c61d8966 \
--hash=sha256:906bc3a79de8c4ae5b86d3d75a8b77e44404b0f4261714306e3ad248d8ab0951 \
--hash=sha256:a1fd8a29719ccce974d523580987b7f8229aeace506952fa9ce1d53a033873c8 \
--hash=sha256:a37b8f0391212d29b3a91a799c8e4a2855e0576911cdfb2515487e30e322253d \
--hash=sha256:a3daabb76a78f829cafc365531c972016e4aa8d5b4bf60660ad8ecee19df7ccc \
--hash=sha256:a469274ad18dc0e4d316eefa616d1d0c2ff9da369af19fa6f3daa4f09671fd61 \
--hash=sha256:aac0411d20e345dc0920bdec5548e438e999ff68d77564d5e9463a7ca9d3e7b1 \
--hash=sha256:be36e3d172dc816333f33520154d708a2657ea63762ec16b62ece02ab5e4daf2 \
--hash=sha256:c8146669223164fc87a7e3de9f81e9423c67a79d6b3447994dfb9c95da16e2d6 \
--hash=sha256:c8fd5270e906eef71d4a8d19b7c6a43760c6abcfcc10c9101d14eb2357418de9 \
--hash=sha256:caf9ee9a5775f3111642d33b86237b05808dafcd6268faa492250e9b78046eb2 \
--hash=sha256:ceb64bbc6eac5a140ca649003756940f8d6a7c444a68af170b3187623b43bebf \
--hash=sha256:d0c5516f0aed654134a2fc936325cc2e642f8a0e096d075209672eb321cff408 \
--hash=sha256:e1140c64812cb9b06c922e77f1c26a75ec5e3f0fb2bf92cc8c58720dec276752 \
--hash=sha256:e6a904cb26bfefc2f0a6f240bdf5233be78cd2488900a2f846f3c3ac8489ab80 \
--hash=sha256:e84799f09591700a4154154cab9787452925578841a94321d5ee8fb9a9a328f0 \
--hash=sha256:f66b5337fa213f1da0d9000bc8dc0cb5b896b726eefd9c6046f699b169c41b9e
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
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.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.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
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
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:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df \
--hash=sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b \
--hash=sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2 \
--hash=sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed \
--hash=sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd \
--hash=sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b \
--hash=sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30 \
--hash=sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be \
--hash=sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf \
--hash=sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b \
--hash=sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402 \
--hash=sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f \
--hash=sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603 \
--hash=sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45 \
--hash=sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558 \
--hash=sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4 \
--hash=sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480 \
--hash=sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447 \
--hash=sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8 \
--hash=sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04 \
--hash=sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c \
--hash=sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb \
--hash=sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b \
--hash=sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c \
--hash=sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92 \
--hash=sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113 \
--hash=sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f \
--hash=sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d \
--hash=sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca \
--hash=sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f \
--hash=sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077 \
--hash=sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2 \
--hash=sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374 \
--hash=sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc \
--hash=sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e \
--hash=sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53 \
--hash=sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547 \
--hash=sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3 \
--hash=sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870 \
--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

View File

@@ -0,0 +1,32 @@
import math
from xiaomusic.const import (
SUPPORT_MUSIC_TYPE,
)
from xiaomusic.utils import (
get_local_music_duration,
traverse_music_directory,
)
async def test_one_music(filename):
# 获取播放时长
duration = await get_local_music_duration(filename)
sec = math.ceil(duration)
print(f"本地歌曲 : {filename} 的时长 {duration} {sec}")
async def main(directory):
# 获取所有歌曲文件
local_musics = traverse_music_directory(directory, 10, [], SUPPORT_MUSIC_TYPE)
print(local_musics)
for _, files in local_musics.items():
for file in files:
await test_one_music(file)
if __name__ == "__main__":
import asyncio
directory = "./music" # 替换为你的音乐目录路径
asyncio.run(main(directory))

View File

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

View File

@@ -1 +1 @@
__version__ = "0.3.11"
__version__ = "0.3.25"

View File

@@ -1,5 +1,9 @@
#!/usr/bin/env python3
import argparse
import json
import os
import signal
import subprocess
import uvicorn
@@ -75,29 +79,113 @@ def main():
options = parser.parse_args()
config = Config.from_options(options)
xiaomusic = XiaoMusic(config)
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 = {
"version": 1,
"disable_existing_loggers": False,
"formatters": {
"default": {
"format": f"%(asctime)s [{__version__}] [%(levelname)s] %(message)s",
"datefmt": "[%X]",
"use_colors": False,
},
"access": {
"format": f"%(asctime)s [{__version__}] [%(levelname)s] %(message)s",
"datefmt": "[%X]",
},
},
"handlers": {
"default": {
"formatter": "default",
"class": "logging.StreamHandler",
"stream": "ext://sys.stderr",
},
"access": {
"formatter": "access",
"class": "logging.StreamHandler",
"stream": "ext://sys.stdout",
},
"file": {
"level": "INFO",
"class": "logging.handlers.RotatingFileHandler",
"formatter": "access",
"filename": config.log_file,
"maxBytes": 10 * 1024 * 1024,
"backupCount": 1,
},
},
"loggers": {
"uvicorn": {
"handlers": [
"default",
"file",
],
"level": "INFO",
},
"uvicorn.error": {
"level": "INFO",
},
"uvicorn.access": {
"handlers": [
"access",
"file",
],
"level": "INFO",
"propagate": False,
},
},
}
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,
)
try:
filename = config.getsettingfile()
with open(filename) as f:
data = json.loads(f.read())
config.update_config(data)
except Exception as e:
print(f"Execption {e}")
def run_server(port):
xiaomusic = XiaoMusic(config)
HttpInit(xiaomusic)
uvicorn.run(
HttpApp,
host=["0.0.0.0", "::"],
port=port,
log_config=LOGGING_CONFIG,
)
process = None
def run_gate():
command = [
"uvicorn",
"xiaomusic.gate:app",
"--workers",
"4",
"--host",
"0.0.0.0",
"--port",
str(config.port),
]
global process
process = subprocess.Popen(command)
def signal_handler(sig, frame):
print("主进程收到退出信号,准备退出...")
if process is not None:
process.terminate() # 终止子进程
process.wait() # 等待子进程退出
print("子进程已退出")
os._exit(0) # 退出主进程
# 捕获主进程的退出信号
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
port = int(config.port)
if config.enable_gate:
run_gate()
run_server(port + 1)
else:
run_server(port)
if __name__ == "__main__":

View File

@@ -136,6 +136,8 @@ class Config:
remove_id3tag: bool = (
os.getenv("XIAOMUSIC_REMOVE_ID3TAG", "false").lower() == "true"
)
delay_sec: int = int(os.getenv("XIAOMUSIC_DELAY_SEC", 3)) # 下一首歌延迟播放秒数
enable_gate: bool = os.getenv("XIAOMUSIC_ENABLE_GATE", "false").lower() == "true"
def append_keyword(self, keys, action):
for key in keys.split(","):
@@ -146,9 +148,11 @@ class Config:
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)
if k not in self.key_match_order:
self.key_match_order.append(k)
def init_keyword(self):
self.key_match_order = default_key_match_order()
self.append_keyword(self.keywords_playlocal, "playlocal")
self.append_keyword(self.keywords_play, "play")
self.append_keyword(self.keywords_stop, "stop")
@@ -216,3 +220,13 @@ class Config:
if converted_value is not None:
setattr(self, k, converted_value)
self.init_keyword()
# 获取设置文件
def getsettingfile(self):
# 兼容旧配置空的情况
if not self.conf_path:
self.conf_path = "conf"
if not os.path.exists(self.conf_path):
os.makedirs(self.conf_path)
filename = os.path.join(self.conf_path, "setting.json")
return filename

124
xiaomusic/gate.py Normal file
View File

@@ -0,0 +1,124 @@
import json
import logging
import mimetypes
import os
import re
from contextlib import asynccontextmanager
import aiofiles
import httpx
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import Response, StreamingResponse
from fastapi.staticfiles import StaticFiles
from xiaomusic import __version__
from xiaomusic.config import Config
config = Config()
logging.basicConfig(level=logging.INFO)
log = logging.getLogger(__name__)
@asynccontextmanager
async def app_lifespan(app):
global config
try:
filename = config.getsettingfile()
with open(filename) as f:
data = json.loads(f.read())
config.update_config(data)
except Exception as e:
log.exception(f"Execption {e}")
yield
app = FastAPI(
lifespan=app_lifespan,
version=__version__,
)
folder = os.path.dirname(__file__)
app.mount("/static", StaticFiles(directory=f"{folder}/static"), name="static")
async def file_iterator(file_path, start, end):
async with aiofiles.open(file_path, mode="rb") as file:
await file.seek(start)
chunk_size = 1024
while start <= end:
read_size = min(chunk_size, end - start + 1)
data = await file.read(read_size)
if not data:
break
start += len(data)
yield data
range_pattern = re.compile(r"bytes=(\d+)-(\d*)")
@app.get("/music/{file_path:path}")
async def music_file(request: Request, file_path: str):
absolute_path = os.path.abspath(config.music_path)
absolute_file_path = os.path.normpath(os.path.join(absolute_path, file_path))
if not absolute_file_path.startswith(absolute_path):
raise HTTPException(status_code=404, detail="File not found")
if not os.path.exists(absolute_file_path):
raise HTTPException(status_code=404, detail="File not found")
file_size = os.path.getsize(absolute_file_path)
range_start, range_end = 0, file_size - 1
range_header = request.headers.get("Range")
log.info(f"music_file range_header {range_header}")
if range_header:
range_match = range_pattern.match(range_header)
if range_match:
range_start = int(range_match.group(1))
if range_match.group(2):
range_end = int(range_match.group(2))
log.info(f"music_file in range {absolute_file_path}")
log.info(f"music_file {range_start} {range_end} {absolute_file_path}")
headers = {
"Content-Range": f"bytes {range_start}-{range_end}/{file_size}",
"Accept-Ranges": "bytes",
}
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type is None:
mime_type = "application/octet-stream"
return StreamingResponse(
file_iterator(absolute_file_path, range_start, range_end),
headers=headers,
status_code=206 if range_header else 200,
media_type=mime_type,
)
@app.options("/music/{file_path:path}")
async def music_options():
headers = {
"Accept-Ranges": "bytes",
}
return Response(headers=headers)
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
async def proxy(path: str, request: Request):
async with httpx.AsyncClient() as client:
port = config.port + 1
url = f"http://127.0.0.1:{port}/{path}"
response = await client.request(
method=request.method,
url=url,
headers=request.headers,
params=request.query_params,
content=await request.body() if request.method in ["POST", "PUT"] else None,
)
return Response(
content=response.content,
status_code=response.status_code,
headers=dict(response.headers),
)

View File

@@ -1,6 +1,8 @@
import asyncio
import json
import mimetypes
import os
import re
import secrets
import shutil
import tempfile
@@ -8,12 +10,14 @@ from contextlib import asynccontextmanager
from dataclasses import asdict
from typing import Annotated
import aiofiles
from fastapi import Depends, FastAPI, HTTPException, Request, status
from fastapi.responses import StreamingResponse
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 starlette.responses import FileResponse, Response
from xiaomusic import __version__
from xiaomusic.utils import (
@@ -29,9 +33,11 @@ log = None
@asynccontextmanager
async def app_lifespan(app):
if xiaomusic is not None:
task = asyncio.create_task(xiaomusic.run_forever())
asyncio.create_task(xiaomusic.run_forever())
try:
yield
task.cancel()
except Exception as e:
log.exception(f"Execption {e}")
security = HTTPBasic()
@@ -77,14 +83,6 @@ def reset_http_server():
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
@@ -168,7 +166,12 @@ async def do_cmd(data: DidCmd):
return {"ret": "Did not exist"}
if len(cmd) > 0:
asyncio.create_task(xiaomusic.do_check_cmd(did=did, query=cmd))
try:
await xiaomusic.cancel_all_tasks()
task = asyncio.create_task(xiaomusic.do_check_cmd(did=did, query=cmd))
xiaomusic.append_running_task(task)
except Exception as e:
log.warning(f"Execption {e}")
return {"ret": "OK"}
return {"ret": "Unknow cmd"}
@@ -291,3 +294,66 @@ async def debug_play_by_music_url(request: Request):
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
async def file_iterator(file_path, start, end):
async with aiofiles.open(file_path, mode="rb") as file:
await file.seek(start)
chunk_size = 1024
while start <= end:
read_size = min(chunk_size, end - start + 1)
data = await file.read(read_size)
if not data:
break
start += len(data)
yield data
range_pattern = re.compile(r"bytes=(\d+)-(\d*)")
@app.get("/music/{file_path:path}")
async def music_file(request: Request, file_path: str):
absolute_path = os.path.abspath(config.music_path)
absolute_file_path = os.path.normpath(os.path.join(absolute_path, file_path))
if not absolute_file_path.startswith(absolute_path):
raise HTTPException(status_code=404, detail="File not found")
if not os.path.exists(absolute_file_path):
raise HTTPException(status_code=404, detail="File not found")
file_size = os.path.getsize(absolute_file_path)
range_start, range_end = 0, file_size - 1
range_header = request.headers.get("Range")
log.info(f"music_file range_header {range_header}")
if range_header:
range_match = range_pattern.match(range_header)
if range_match:
range_start = int(range_match.group(1))
if range_match.group(2):
range_end = int(range_match.group(2))
log.info(f"music_file in range {absolute_file_path}")
log.info(f"music_file {range_start} {range_end} {absolute_file_path}")
headers = {
"Content-Range": f"bytes {range_start}-{range_end}/{file_size}",
"Accept-Ranges": "bytes",
}
mime_type, _ = mimetypes.guess_type(file_path)
if mime_type is None:
mime_type = "application/octet-stream"
return StreamingResponse(
file_iterator(absolute_file_path, range_start, range_end),
headers=headers,
status_code=206 if range_header else 200,
media_type=mime_type,
)
@app.options("/music/{file_path:path}")
async def music_options():
headers = {
"Accept-Ranges": "bytes",
}
return Response(headers=headers)

View File

@@ -53,15 +53,17 @@ $(function(){
.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('✔️ 随机播放');
if (value === did) {
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('✔️ 随机播放');
}
}
}
});
@@ -72,6 +74,7 @@ $(function(){
localStorage.setItem('cur_did', did);
window.did = did;
console.log('cur_did', did);
location.reload();
})
});

View File

@@ -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?version=1721662254">
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1723807100">
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script src="/static/jquery-3.7.1.min.js?version=1721662254"></script>
<script src="/static/jquery-3.7.1.min.js?version=1723807100"></script>
<script>
var vConsole = new window.VConsole();

View File

@@ -3,9 +3,9 @@
<head>
<meta name="viewport" content="width=device-width">
<title>小爱音箱操控面板</title>
<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="/static/jquery-3.7.1.min.js?version=1723807100"></script>
<script src="/static/app.js?version=1723807100"></script>
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1723807100">
<!--
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>

View File

@@ -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?version=1721662254">
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1723807100">
<!--
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
<script>

View File

@@ -3,9 +3,9 @@
<head>
<meta name="viewport" content="width=device-width">
<title>小爱音箱操控面板</title>
<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="/static/jquery-3.7.1.min.js?version=1723807100"></script>
<script src="/static/setting.js?version=1723807100"></script>
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1723807100">
<!--
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
@@ -127,9 +127,24 @@ var vConsole = new window.VConsole();
<option value="false">false</option>
</select>
<label for="enable_gate">开启网关(重启生效):</label>
<select id="enable_gate">
<option value="true">true</option>
<option value="false" selected>false</option>
</select>
<label for="use_music_api">触屏版兼容模式:</label>
<select id="use_music_api">
<option value="true">true</option>
<option value="false" selected>false</option>
</select>
<label for="public_port">外网访问端口(0表示跟监听端口一致):</label>
<input id="public_port" type="number" value="0"></input>
<label for="delay_sec">下一首歌延迟播放秒数:</label>
<input id="delay_sec" type="number" value="3"></input>
<label for="stop_tts_msg">停止提示音:</label>
<input id="stop_tts_msg" type="text" value="收到,再见"></input>
<label for="keywords_playlocal">播放本地歌曲口令:</label>

View File

@@ -68,9 +68,8 @@ $(function(){
// 初始化显示
for (const key in data) {
if (data.hasOwnProperty(key)) {
const $element = $("#" + key);
if ($element.length && data[key] !== '') {
if ($element.length) {
if (data[key] === true) {
$element.val('true');
} else if (data[key] === false) {
@@ -79,7 +78,6 @@ $(function(){
$element.val(data[key]);
}
}
}
}
autoSelectOne();

View File

@@ -1,8 +1,10 @@
#!/usr/bin/env python3
from __future__ import annotations
import asyncio
import copy
import difflib
import logging
import mimetypes
import os
import random
@@ -139,9 +141,7 @@ def _append_files_result(result, root, joinpath, files, support_extension):
result[dir_name].append(os.path.join(joinpath, file))
def traverse_music_directory(
directory, depth=10, exclude_dirs=None, support_extension=None
):
def traverse_music_directory(directory, depth, exclude_dirs, support_extension):
result = {}
for root, dirs, files in os.walk(directory, followlinks=True):
# 忽略排除的目录
@@ -193,23 +193,20 @@ async def _get_web_music_duration(session, url, start=0, end=500):
headers = {"Range": f"bytes={start}-{end}"}
async with session.get(url, headers=headers) as response:
array_buffer = await response.read()
with tempfile.NamedTemporaryFile(delete=False) as tmp:
with tempfile.NamedTemporaryFile() as tmp:
tmp.write(array_buffer)
name = tmp.name
try:
if is_mp3(url):
m = mutagen.mp3.MP3(name)
else:
m = mutagen.File(name)
duration = m.info.length
except Exception:
pass
os.remove(name)
try:
if is_mp3(url):
m = mutagen.mp3.MP3(tmp)
else:
m = mutagen.File(tmp)
duration = m.info.length
except Exception as e:
logging.error(f"Error _get_web_music_duration: {e}")
return duration
async def get_web_music_duration(url, start=0, end=500):
async def get_web_music_duration(url):
duration = 0
try:
parsed_url = urlparse(url)
@@ -232,24 +229,25 @@ async def get_web_music_duration(url, start=0, end=500):
duration = await _get_web_music_duration(session, url, start=0, end=500)
if duration <= 0:
duration = await _get_web_music_duration(
session, url, start=0, end=1000
session, url, start=0, end=3000
)
except Exception:
pass
except Exception as e:
logging.error(f"Error get_web_music_duration: {e}")
return duration, url
# 获取文件播放时长
def get_local_music_duration(filename):
async def get_local_music_duration(filename):
loop = asyncio.get_event_loop()
duration = 0
try:
if is_mp3(filename):
m = mutagen.mp3.MP3(filename)
m = await loop.run_in_executor(None, mutagen.mp3.MP3, filename)
else:
m = mutagen.File(filename)
m = await loop.run_in_executor(None, mutagen.File, filename)
duration = m.info.length
except Exception:
pass
except Exception as e:
logging.error(f"Error getting local music {filename} duration: {e}")
return duration

View File

@@ -2,6 +2,7 @@
import asyncio
import json
import logging
import math
import os
import random
import re
@@ -61,6 +62,7 @@ class XiaoMusic:
self._all_radio = {} # 电台列表
self.music_list = {} # 播放列表 key 为目录名, value 为 play_list
self.devices = {} # key 为 did
self.running_task = []
# 初始化配置
self.init_config()
@@ -83,15 +85,11 @@ class XiaoMusic:
debug_config = deepcopy_data_no_sensitive_info(self.config)
self.log.info(f"Startup OK. {debug_config}")
if self.conf_path == self.music_path:
if self.config.conf_path == self.music_path:
self.log.warning("配置文件目录和音乐目录建议设置为不同的目录")
def init_config(self):
self.music_path = self.config.music_path
self.conf_path = self.config.conf_path
# 兼容旧配置空的情况
if not self.conf_path:
self.conf_path = "conf"
self.download_path = self.config.download_path
if not self.download_path:
self.download_path = self.music_path
@@ -312,10 +310,10 @@ class XiaoMusic:
def get_filename(self, name):
if name not in self.all_music:
self.log.debug(f"get_filename not in. name:{name}")
self.log.info(f"get_filename not in. name:{name}")
return ""
filename = self.all_music[name]
self.log.debug(f"try get_filename. filename:{filename}")
self.log.info(f"try get_filename. filename:{filename}")
if os.path.exists(filename):
return filename
return ""
@@ -346,6 +344,7 @@ class XiaoMusic:
async def get_music_sec_url(self, name):
sec = 0
url = self.get_music_url(name)
self.log.info(f"get_music_sec_url. name:{name} url:{url}")
if self.is_web_radio_music(name):
self.log.info("电台不会有播放时长")
return 0, url
@@ -353,11 +352,13 @@ class XiaoMusic:
if self.is_web_music(name):
origin_url = url
duration, url = await get_web_music_duration(url)
sec = int(duration)
sec = math.ceil(duration)
self.log.info(f"网络歌曲 {name} : {origin_url} {url} 的时长 {sec}")
else:
filename = self.get_filename(name)
sec = int(get_local_music_duration(filename))
self.log.info(f"get_music_sec_url. name:{name} filename:{filename}")
duration = await get_local_music_duration(filename)
sec = math.ceil(duration)
self.log.info(f"本地歌曲 {name} : {filename} {url} 的时长 {sec}")
if sec <= 0:
@@ -367,7 +368,7 @@ class XiaoMusic:
def get_music_url(self, name):
if self.is_web_music(name):
url = self.all_music[name]
self.log.debug(f"get_music_url web music. name:{name}, url:{url}")
self.log.info(f"get_music_url web music. name:{name}, url:{url}")
return url
filename = self.get_filename(name)
@@ -385,7 +386,7 @@ class XiaoMusic:
filename = filename[len(self.config.music_path) :]
if filename.startswith("/"):
filename = filename[1:]
self.log.debug(f"get_music_url local music. name:{name}, filename:{filename}")
self.log.info(f"get_music_url local music. name:{name}, filename:{filename}")
encoded_name = urllib.parse.quote(filename)
return f"http://{self.hostname}:{self.public_port}/music/{encoded_name}"
@@ -507,6 +508,19 @@ class XiaoMusic:
except Exception as e:
self.log.exception(f"Execption {e}")
def append_running_task(self, task):
self.running_task.append(task)
async def cancel_all_tasks(self):
if len(self.running_task) == 0:
self.log.info("cancel_all_tasks no task")
return
for task in self.running_task:
self.log.info(f"cancel_all_tasks {task}")
task.cancel()
await asyncio.gather(*self.running_task, return_exceptions=True)
self.running_task = []
async def check_replay(self, did):
return await self.devices[did].check_replay()
@@ -718,16 +732,9 @@ class XiaoMusic:
def getconfig(self):
return self.config
# 获取设置文件
def getsettingfile(self):
if not os.path.exists(self.conf_path):
os.makedirs(self.conf_path)
filename = os.path.join(self.conf_path, "setting.json")
return filename
def try_init_setting(self):
try:
filename = self.getsettingfile()
filename = self.config.getsettingfile()
with open(filename) as f:
data = json.loads(f.read())
self.update_config_from_setting(data)
@@ -749,8 +756,7 @@ class XiaoMusic:
# 配置文件落地
def do_saveconfig(self, data):
# 默认暂时配置保存到 music 目录下
filename = self.getsettingfile()
filename = self.config.getsettingfile()
with open(filename, "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
@@ -853,7 +859,7 @@ class XiaoMusicDevice:
async def _play(self, name="", search_key=""):
if search_key == "" and name == "":
if self.check_play_next():
await self.play_next()
await self._play_next()
return
else:
name = self.cur_music
@@ -886,7 +892,7 @@ class XiaoMusicDevice:
or (name not in self._play_list)
):
name = self.get_next_music()
self.log.info(f"play_next. name:{name}, cur_music:{self.cur_music}")
self.log.info(f"_play_next. name:{name}, cur_music:{self.cur_music}")
if name == "":
await self.do_tts("本地没有歌曲")
return
@@ -897,7 +903,7 @@ class XiaoMusicDevice:
self._last_cmd = "playlocal"
if name == "":
if self.check_play_next():
await self.play_next()
await self._play_next()
return
else:
name = self.cur_music
@@ -912,6 +918,9 @@ class XiaoMusicDevice:
await self._playmusic(name)
async def _playmusic(self, name):
# 取消组内所有的下一首歌曲的定时器
self.cancel_group_next_timer()
self._playing = True
self.cur_music = name
self.log.info(f"cur_music {self.cur_music}")
@@ -926,11 +935,13 @@ class XiaoMusicDevice:
await self._play_next()
return
self.log.info("已经开始播放了")
self.log.info(f"{name}已经开始播放了")
# 取消组内所有的下一首歌曲的定时器
self.cancel_group_next_timer()
# 设置下一首歌曲的播放定时器
if sec <= 1:
self.log.info(f"{name}】不会设置下一首歌的定时器")
return
sec = sec + self.config.delay_sec
await self.set_next_music_timeout(sec)
async def do_tts(self, value):
@@ -939,7 +950,7 @@ class XiaoMusicDevice:
self.log.info("do_tts no value")
return
await self.group_force_stop_xiaoai()
# await self.group_force_stop_xiaoai()
await self.text_to_speech(value)
# 最大等8秒
@@ -1081,14 +1092,17 @@ class XiaoMusicDevice:
def check_play_next(self):
# 当前歌曲不在当前播放列表
if self.cur_music not in self._play_list:
self.log.info(f"当前歌曲 {self.cur_music} 不在当前播放列表")
return True
# 当前没我在播放的歌曲
if self.cur_music == "":
self.log.info("当前没我在播放的歌曲")
return True
else:
# 当前播放的歌曲不存在了
if not self.xiaomusic.is_music_exist(self.cur_music):
self.log.info(f"当前播放的歌曲 {self.cur_music} 不存在了")
return True
return False
@@ -1127,23 +1141,19 @@ class XiaoMusicDevice:
# 设置下一首歌曲的播放定时器
async def set_next_music_timeout(self, sec):
if sec <= 0:
return
if self._next_timer:
self._next_timer.cancel()
self.log.info("旧定时器已取消")
self.cancel_next_timer()
self._timeout = sec
async def _do_next():
await asyncio.sleep(self._timeout)
try:
await self.play_next()
self.log.info("定时器时间到了")
self._next_timer = None
await self._play_next()
except Exception as e:
self.log.error(f"Execption {e}")
self._next_timer = asyncio.ensure_future(_do_next())
self._next_timer = asyncio.create_task(_do_next())
self.log.info(f"{sec} 秒后将会播放下一首歌曲")
async def set_volume(self, volume: int):
@@ -1183,10 +1193,8 @@ class XiaoMusicDevice:
self._playing = False
if arg1 != "notts":
await self.do_tts(self.config.stop_tts_msg)
if self._next_timer:
self._next_timer.cancel()
self._next_timer = None
self.log.info("定时器已取消")
# 取消组内所有的下一首歌曲的定时器
self.cancel_group_next_timer()
await self.group_force_stop_xiaoai()
self.log.info("stop now")
@@ -1211,13 +1219,14 @@ class XiaoMusicDevice:
except Exception as e:
self.log.exception(f"Execption {e}")
self._stop_timer = asyncio.ensure_future(_do_stop())
self._stop_timer = asyncio.create_task(_do_stop())
await self.do_tts(f"收到,{minute}分钟后将关机")
def cancel_next_timer(self):
if self._next_timer:
self._next_timer.cancel()
self.log.info("下一曲定时器已取消")
self.log.info(f"下一曲定时器已取消 {self.device_id}")
self._next_timer = None
def cancel_group_next_timer(self):
devices = self.xiaomusic.get_group_devices(self.group_name)
@@ -1232,10 +1241,12 @@ class XiaoMusicDevice:
self.log.info("in cancel_all_timer")
if self._next_timer:
self._next_timer.cancel()
self._next_timer = None
self.log.info("cancel_all_timer _next_timer.cancel")
if self._stop_timer:
self._stop_timer.cancel()
self._stop_timer = None
self.log.info("cancel_all_timer _stop_timer.cancel")
@classmethod