mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-07 15:02:55 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a4d702070 | ||
|
|
2c7a09b9d4 | ||
|
|
74837baaef | ||
|
|
def63b2407 | ||
|
|
93d2047c7a | ||
|
|
9a1b9d1949 | ||
|
|
88fa4318dc | ||
|
|
0bc4bc8b13 | ||
|
|
ca2ddcd89c | ||
|
|
78acc35a62 | ||
|
|
323a832a9e | ||
|
|
0c99f4d537 | ||
|
|
b2737f745d |
23
CHANGELOG.md
23
CHANGELOG.md
@@ -1,3 +1,26 @@
|
||||
## v0.3.49 (2024-11-28)
|
||||
|
||||
### Feat
|
||||
|
||||
- 临时文件目录支持配置 #99
|
||||
- 新增单曲播放和顺序播放功能 close #277
|
||||
- 设置播放类型支持配置语音提示词,定时任务支持设置播放类型
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复中文数字转换函数对'十、十一'等数字的处理 (#275)
|
||||
|
||||
## v0.3.48 (2024-11-20)
|
||||
|
||||
### Feat
|
||||
|
||||
- 支持替换默认口令,而不是追加 close #259
|
||||
- 新增自定义个歌单接口 #242
|
||||
|
||||
### Fix
|
||||
|
||||
- 锁定 PWA 应用旋转方向
|
||||
|
||||
## v0.3.47 (2024-11-14)
|
||||
|
||||
### Feat
|
||||
|
||||
94
pdm.lock
generated
94
pdm.lock
generated
@@ -5,7 +5,7 @@
|
||||
groups = ["default", "dev", "lint"]
|
||||
strategy = ["inherit_metadata"]
|
||||
lock_version = "4.5.0"
|
||||
content_hash = "sha256:10d18ad4e1cc30b6683ac4c5fcdf73ab7aa3e6a5910b94e5ded3183e108bbbe1"
|
||||
content_hash = "sha256:37be8846356b5717495cac7252d78b1554985d607e286cf38ab863e307e5e25e"
|
||||
|
||||
[[metadata.targets]]
|
||||
requires_python = "==3.10.12"
|
||||
@@ -39,23 +39,24 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
version = "3.10.10"
|
||||
requires_python = ">=3.8"
|
||||
version = "3.11.8"
|
||||
requires_python = ">=3.9"
|
||||
summary = "Async http client/server framework (asyncio)"
|
||||
groups = ["default"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
dependencies = [
|
||||
"aiohappyeyeballs>=2.3.0",
|
||||
"aiosignal>=1.1.2",
|
||||
"async-timeout<5.0,>=4.0; python_version < \"3.11\"",
|
||||
"async-timeout<6.0,>=4.0; python_version < \"3.11\"",
|
||||
"attrs>=17.3.0",
|
||||
"frozenlist>=1.1.1",
|
||||
"multidict<7.0,>=4.5",
|
||||
"yarl<2.0,>=1.12.0",
|
||||
"propcache>=0.2.0",
|
||||
"yarl<2.0,>=1.17.0",
|
||||
]
|
||||
files = [
|
||||
{file = "aiohttp-3.10.10-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab5a5a0c7a7991d90446a198689c0535be89bbd6b410a1f9a66688f0880ec026"},
|
||||
{file = "aiohttp-3.10.10.tar.gz", hash = "sha256:0631dd7c9f0822cc61c88586ca76d5b5ada26538097d0f1df510b082bad3411a"},
|
||||
{file = "aiohttp-3.11.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df9bf08eb93611b1d4d6245b6fecf88728e90eece00e00d554e1b0c445557d83"},
|
||||
{file = "aiohttp-3.11.8.tar.gz", hash = "sha256:7bc9d64a2350cbb29a9732334e1a0743cbb6844de1731cbdf5949b235653f3fd"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -108,20 +109,18 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "apscheduler"
|
||||
version = "3.10.4"
|
||||
requires_python = ">=3.6"
|
||||
version = "3.11.0"
|
||||
requires_python = ">=3.8"
|
||||
summary = "In-process task scheduler with Cron-like capabilities"
|
||||
groups = ["default"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
dependencies = [
|
||||
"importlib-metadata>=3.6.0; python_version < \"3.8\"",
|
||||
"pytz",
|
||||
"six>=1.4.0",
|
||||
"tzlocal!=3.*,>=2.0",
|
||||
"backports-zoneinfo; python_version < \"3.9\"",
|
||||
"tzlocal>=3.0",
|
||||
]
|
||||
files = [
|
||||
{file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"},
|
||||
{file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"},
|
||||
{file = "APScheduler-3.11.0-py3-none-any.whl", hash = "sha256:fc134ca32e50f5eadcc4938e3a4545ab19131435e851abb40b34d63d5141c6da"},
|
||||
{file = "apscheduler-3.11.0.tar.gz", hash = "sha256:4c622d250b0955a65d5d0eb91c33e6d43fd879834bf541e0a18661ae60460133"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -265,8 +264,8 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "commitizen"
|
||||
version = "3.30.0"
|
||||
requires_python = ">=3.8"
|
||||
version = "4.0.0"
|
||||
requires_python = ">=3.9"
|
||||
summary = "Python commitizen client tool"
|
||||
groups = ["dev"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
@@ -282,11 +281,11 @@ dependencies = [
|
||||
"questionary<3.0,>=2.0",
|
||||
"termcolor<3,>=1.1",
|
||||
"tomlkit<1.0.0,>=0.5.3",
|
||||
"typing-extensions<5.0.0,>=4.0.1; python_version < \"3.8\"",
|
||||
"typing-extensions<5.0.0,>=4.0.1; python_version < \"3.11\"",
|
||||
]
|
||||
files = [
|
||||
{file = "commitizen-3.30.0-py3-none-any.whl", hash = "sha256:8dc226a136aee61207e396101fcd89e73de67a57c06e066db982310863caaf65"},
|
||||
{file = "commitizen-3.30.0.tar.gz", hash = "sha256:ae67a47c1a700b4f35ac12de0c35c7ba96f152b9377d22b6226bb87372c527b0"},
|
||||
{file = "commitizen-4.0.0-py3-none-any.whl", hash = "sha256:52873ee589a64cf77fc55570dbd3f987c6ffcd33132d179eb625c4d06ae935f7"},
|
||||
{file = "commitizen-4.0.0.tar.gz", hash = "sha256:16aff27e01b43015eab1c74eabbca3e284b4988dd1b146a0963282db241dc2c0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -315,7 +314,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "fastapi"
|
||||
version = "0.115.4"
|
||||
version = "0.115.5"
|
||||
requires_python = ">=3.8"
|
||||
summary = "FastAPI framework, high performance, easy to learn, fast to code, ready for production"
|
||||
groups = ["default"]
|
||||
@@ -326,8 +325,8 @@ dependencies = [
|
||||
"typing-extensions>=4.8.0",
|
||||
]
|
||||
files = [
|
||||
{file = "fastapi-0.115.4-py3-none-any.whl", hash = "sha256:0b504a063ffb3cf96a5e27dc1bc32c80ca743a2528574f9cdc77daa2d31b4742"},
|
||||
{file = "fastapi-0.115.4.tar.gz", hash = "sha256:db653475586b091cb8b2fec2ac54a680ac6a158e07406e1abae31679e8826349"},
|
||||
{file = "fastapi-0.115.5-py3-none-any.whl", hash = "sha256:596b95adbe1474da47049e802f9a65ab2ffa9c2b07e7efee70eb8a66c9f2f796"},
|
||||
{file = "fastapi-0.115.5.tar.gz", hash = "sha256:0e7a4d0dc0d01c68df21887cce0945e72d3c48b9f4f79dfe7a7d53aa08fbb289"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -771,17 +770,6 @@ files = [
|
||||
{file = "python_multipart-0.0.17.tar.gz", hash = "sha256:41330d831cae6e2f22902704ead2826ea038d0419530eadff3ea80175aec5538"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytz"
|
||||
version = "2024.2"
|
||||
summary = "World timezone definitions, modern and historical"
|
||||
groups = ["default"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
files = [
|
||||
{file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"},
|
||||
{file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pyyaml"
|
||||
version = "6.0.1"
|
||||
@@ -868,26 +856,14 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.7.2"
|
||||
version = "0.8.0"
|
||||
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.7.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dba53ed84ac19ae4bfb4ea4bf0172550a2285fa27fbb13e3746f04c80f7fa088"},
|
||||
{file = "ruff-0.7.2.tar.gz", hash = "sha256:2b14e77293380e475b4e3a7a368e14549288ed2931fce259a6f99978669e844f"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "six"
|
||||
version = "1.16.0"
|
||||
requires_python = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
|
||||
summary = "Python 2 and 3 compatibility utilities"
|
||||
groups = ["default"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
files = [
|
||||
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
|
||||
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
|
||||
{file = "ruff-0.8.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87a8e86bae0dbd749c815211ca11e3a7bd559b9710746c559ed63106d382bd9c"},
|
||||
{file = "ruff-0.8.0.tar.gz", hash = "sha256:a7ccfe6331bf8c8dad715753e157457faf7351c2b69f62f32c165c2dbcbacd44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -904,7 +880,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "starlette"
|
||||
version = "0.41.2"
|
||||
version = "0.41.3"
|
||||
requires_python = ">=3.8"
|
||||
summary = "The little ASGI library that shines."
|
||||
groups = ["default"]
|
||||
@@ -914,8 +890,8 @@ dependencies = [
|
||||
"typing-extensions>=3.10.0; python_version < \"3.10\"",
|
||||
]
|
||||
files = [
|
||||
{file = "starlette-0.41.2-py3-none-any.whl", hash = "sha256:fbc189474b4731cf30fcef52f18a8d070e3f3b46c6a04c97579e85e6ffca942d"},
|
||||
{file = "starlette-0.41.2.tar.gz", hash = "sha256:9834fd799d1a87fd346deb76158668cfa0b0d56f85caefe8268e2d97c3468b62"},
|
||||
{file = "starlette-0.41.3-py3-none-any.whl", hash = "sha256:44cedb2b7c77a9de33a8b74b2b90e9f50d11fcf25d8270ea525ad71a25374ff7"},
|
||||
{file = "starlette-0.41.3.tar.gz", hash = "sha256:0e4ab3d16522a255be6b28260b938eae2482f98ce5cc934cb08dce8dc3ba5835"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -947,7 +923,7 @@ name = "typing-extensions"
|
||||
version = "4.12.2"
|
||||
requires_python = ">=3.8"
|
||||
summary = "Backported and Experimental Type Hints for Python 3.8+"
|
||||
groups = ["default"]
|
||||
groups = ["default", "dev"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
files = [
|
||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
||||
@@ -984,7 +960,7 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "uvicorn"
|
||||
version = "0.32.0"
|
||||
version = "0.32.1"
|
||||
requires_python = ">=3.8"
|
||||
summary = "The lightning-fast ASGI server."
|
||||
groups = ["default"]
|
||||
@@ -995,8 +971,8 @@ dependencies = [
|
||||
"typing-extensions>=4.0; python_version < \"3.11\"",
|
||||
]
|
||||
files = [
|
||||
{file = "uvicorn-0.32.0-py3-none-any.whl", hash = "sha256:60b8f3a5ac027dcd31448f411ced12b5ef452c646f76f02f8cc3f25d8d26fd82"},
|
||||
{file = "uvicorn-0.32.0.tar.gz", hash = "sha256:f78b36b143c16f54ccdb8190d0a26b5f1901fe5a3c777e1ab29f26391af8551e"},
|
||||
{file = "uvicorn-0.32.1-py3-none-any.whl", hash = "sha256:82ad92fd58da0d12af7482ecdb5f2470a04c9c9a53ced65b9bbb4a205377602e"},
|
||||
{file = "uvicorn-0.32.1.tar.gz", hash = "sha256:ee9519c246a72b1c084cea8d3b44ed6026e78a4a309cbedae9c37e4cb9fbb175"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1033,12 +1009,12 @@ files = [
|
||||
|
||||
[[package]]
|
||||
name = "yt-dlp"
|
||||
version = "2024.11.4"
|
||||
version = "2024.11.18"
|
||||
requires_python = ">=3.9"
|
||||
summary = "A feature-rich command-line audio/video downloader"
|
||||
groups = ["default"]
|
||||
marker = "python_full_version == \"3.10.12\""
|
||||
files = [
|
||||
{file = "yt_dlp-2024.11.4-py3-none-any.whl", hash = "sha256:589d51ed9f154624a45c1f0ceb3d68d0d1e2031460e8dbc62139be631c20b388"},
|
||||
{file = "yt_dlp-2024.11.4.tar.gz", hash = "sha256:ed204c1b61bc563e134447766d1ab343173540799e13ebb953e887ce7dcf6865"},
|
||||
{file = "yt_dlp-2024.11.18-py3-none-any.whl", hash = "sha256:b9741695911dc566498b5f115cdd6b1abbc5be61cb01fd98abe649990a41656c"},
|
||||
{file = "yt_dlp-2024.11.18.tar.gz", hash = "sha256:b8a4c23d3c9afd7e476bcdb87f38b6c0e8e12e3a239d7988f13acb434200f54d"},
|
||||
]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.3.47"
|
||||
version = "0.3.49"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
@@ -9,7 +9,7 @@ dependencies = [
|
||||
"aiohttp>=3.8.6",
|
||||
"miservice-fork>=2.7.0",
|
||||
"mutagen>=1.47.0",
|
||||
"yt-dlp>=2024.07.01",
|
||||
"yt-dlp>=2024.11.18",
|
||||
"uvicorn>=0.30.1",
|
||||
"fastapi>=0.115.4",
|
||||
"starlette>=0.37.2",
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.3.47"
|
||||
__version__ = "0.3.49"
|
||||
|
||||
@@ -6,22 +6,27 @@ import os
|
||||
from dataclasses import asdict, dataclass, field
|
||||
from typing import get_type_hints
|
||||
|
||||
from xiaomusic.const import (
|
||||
PLAY_TYPE_ALL,
|
||||
PLAY_TYPE_ONE,
|
||||
PLAY_TYPE_RND,
|
||||
PLAY_TYPE_SEQ,
|
||||
PLAY_TYPE_SIN,
|
||||
)
|
||||
from xiaomusic.utils import validate_proxy
|
||||
|
||||
|
||||
# 默认口令
|
||||
def default_key_word_dict():
|
||||
return {
|
||||
"播放歌曲": "play",
|
||||
"播放本地歌曲": "playlocal",
|
||||
"关机": "stop",
|
||||
"下一首": "play_next",
|
||||
"上一首": "play_prev",
|
||||
"单曲循环": "set_play_type_one",
|
||||
"全部循环": "set_play_type_all",
|
||||
"随机播放": "set_random_play",
|
||||
"随机播放": "set_play_type_rnd",
|
||||
"单曲播放": "set_play_type_sin",
|
||||
"顺序播放": "set_play_type_seq",
|
||||
"分钟后关机": "stop_after_minute",
|
||||
"播放列表": "play_music_list",
|
||||
"刷新列表": "gen_music_list",
|
||||
"加入收藏": "add_to_favorites",
|
||||
"收藏歌曲": "add_to_favorites",
|
||||
@@ -47,12 +52,13 @@ KEY_WORD_ARG_BEFORE_DICT = {
|
||||
def default_key_match_order():
|
||||
return [
|
||||
"分钟后关机",
|
||||
"播放歌曲",
|
||||
"下一首",
|
||||
"上一首",
|
||||
"单曲循环",
|
||||
"全部循环",
|
||||
"随机播放",
|
||||
"单曲播放",
|
||||
"顺序播放",
|
||||
"关机",
|
||||
"刷新列表",
|
||||
"播放列表第",
|
||||
@@ -82,9 +88,8 @@ class Config:
|
||||
miio_tts_command: str = os.getenv("MIIO_TTS_CMD", "")
|
||||
cookie: str = ""
|
||||
verbose: bool = os.getenv("XIAOMUSIC_VERBOSE", "").lower() == "true"
|
||||
music_path: str = os.getenv(
|
||||
"XIAOMUSIC_MUSIC_PATH", "music"
|
||||
) # 只能是music目录下的子目录
|
||||
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
|
||||
temp_path: str = os.getenv("XIAOMUSIC_TEMP_PATH", "music/tmp")
|
||||
download_path: str = os.getenv("XIAOMUSIC_DOWNLOAD_PATH", "music/download")
|
||||
conf_path: str = os.getenv("XIAOMUSIC_CONF_PATH", "conf")
|
||||
cache_dir: str = os.getenv("XIAOMUSIC_CACHE_DIR", "cache")
|
||||
@@ -98,7 +103,7 @@ class Config:
|
||||
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
|
||||
active_cmd: str = os.getenv(
|
||||
"XIAOMUSIC_ACTIVE_CMD",
|
||||
"play,set_random_play,playlocal,play_music_list,play_music_list_index,stop_after_minute,stop",
|
||||
"play,set_play_type_rnd,playlocal,play_music_list,play_music_list_index,stop_after_minute,stop",
|
||||
)
|
||||
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir,tmp")
|
||||
music_path_depth: int = int(os.getenv("XIAOMUSIC_MUSIC_PATH_DEPTH", "10"))
|
||||
@@ -166,6 +171,21 @@ class Config:
|
||||
get_ask_by_mina: bool = (
|
||||
os.getenv("XIAOMUSIC_GET_ASK_BY_MINA", "false").lower() == "true"
|
||||
)
|
||||
play_type_one_tts_msg: str = os.getenv(
|
||||
"XIAOMUSIC_PLAY_TYPE_ONE_TTS_MSG", "已经设置为单曲循环"
|
||||
)
|
||||
play_type_all_tts_msg: str = os.getenv(
|
||||
"XIAOMUSIC_PLAY_TYPE_ALL_TTS_MSG", "已经设置为全部循环"
|
||||
)
|
||||
play_type_rnd_tts_msg: str = os.getenv(
|
||||
"XIAOMUSIC_PLAY_TYPE_RND_TTS_MSG", "已经设置为随机播放"
|
||||
)
|
||||
play_type_sin_tts_msg: str = os.getenv(
|
||||
"XIAOMUSIC_PLAY_TYPE_SIN_TTS_MSG", "已经设置为单曲播放"
|
||||
)
|
||||
play_type_seq_tts_msg: str = os.getenv(
|
||||
"XIAOMUSIC_PLAY_TYPE_SEQ_TTS_MSG", "已经设置为顺序播放"
|
||||
)
|
||||
|
||||
def append_keyword(self, keys, action):
|
||||
for key in keys.split(","):
|
||||
@@ -188,6 +208,9 @@ class Config:
|
||||
self.append_keyword(self.keywords_stop, "stop")
|
||||
self.append_keyword(self.keywords_playlist, "play_music_list")
|
||||
self.append_user_keyword()
|
||||
self.key_match_order = [
|
||||
x for x in self.key_match_order if x in self.key_word_dict
|
||||
]
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.proxy:
|
||||
@@ -282,3 +305,22 @@ class Config:
|
||||
os.makedirs(self.conf_path)
|
||||
cookies_path = os.path.join(self.conf_path, "yt-dlp-cookie.txt")
|
||||
return cookies_path
|
||||
|
||||
@property
|
||||
def temp_dir(self):
|
||||
if not os.path.exists(self.temp_path):
|
||||
os.makedirs(self.temp_path)
|
||||
return self.temp_path
|
||||
|
||||
def get_play_type_tts(self, play_type):
|
||||
if play_type == PLAY_TYPE_ONE:
|
||||
return self.play_type_one_tts_msg
|
||||
if play_type == PLAY_TYPE_ALL:
|
||||
return self.play_type_all_tts_msg
|
||||
if play_type == PLAY_TYPE_RND:
|
||||
return self.play_type_rnd_tts_msg
|
||||
if play_type == PLAY_TYPE_SIN:
|
||||
return self.play_type_sin_tts_msg
|
||||
if play_type == PLAY_TYPE_SEQ:
|
||||
return self.play_type_seq_tts_msg
|
||||
return ""
|
||||
|
||||
@@ -13,12 +13,8 @@ COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={u
|
||||
PLAY_TYPE_ONE = 0 # 单曲循环
|
||||
PLAY_TYPE_ALL = 1 # 全部循环
|
||||
PLAY_TYPE_RND = 2 # 随机播放
|
||||
|
||||
PLAY_TYPE_TTS = {
|
||||
PLAY_TYPE_ONE: "已经设置为单曲循环",
|
||||
PLAY_TYPE_ALL: "已经设置为全部循环",
|
||||
PLAY_TYPE_RND: "已经设置为随机播放",
|
||||
}
|
||||
PLAY_TYPE_SIN = 3 # 单曲播放
|
||||
PLAY_TYPE_SEQ = 4 # 顺序播放
|
||||
|
||||
# 需要采用 mina 获取对话记录的设备型号
|
||||
GET_ASK_BY_MINA = {
|
||||
|
||||
@@ -63,6 +63,14 @@ class Crontab:
|
||||
|
||||
self.add_job(expression, job)
|
||||
|
||||
# 设置播放类型任务
|
||||
def add_job_set_play_type(self, expression, xiaomusic, did, arg1, **kwargs):
|
||||
async def job():
|
||||
play_type = int(arg1)
|
||||
await xiaomusic.set_play_type(did, play_type, False)
|
||||
|
||||
self.add_job(expression, job)
|
||||
|
||||
def add_job_cron(self, xiaomusic, cron):
|
||||
expression = cron["expression"] # cron 计划格式
|
||||
name = cron["name"] # stop, play, play_music_list, tts
|
||||
|
||||
@@ -468,6 +468,51 @@ async def upload_yt_dlp_cookie(file: UploadFile = File(...)):
|
||||
}
|
||||
|
||||
|
||||
class PlayListObj(BaseModel):
|
||||
name: str = "" # 歌单名
|
||||
|
||||
|
||||
# 新增歌单
|
||||
@app.post("/playlistadd")
|
||||
async def playlistadd(data: PlayListObj, Verifcation=Depends(verification)):
|
||||
ret = xiaomusic.play_list_add(data.name)
|
||||
if ret:
|
||||
return {"ret": "OK"}
|
||||
return {"ret": "Add failed, may be already exist."}
|
||||
|
||||
|
||||
# 移除歌单
|
||||
@app.post("/playlistdel")
|
||||
async def playlistdel(data: PlayListObj, Verifcation=Depends(verification)):
|
||||
ret = xiaomusic.play_list_del(data.name)
|
||||
if ret:
|
||||
return {"ret": "OK"}
|
||||
return {"ret": "Del failed, may be not exist."}
|
||||
|
||||
|
||||
class PlayListMusicObj(BaseModel):
|
||||
name: str = "" # 歌单名
|
||||
music_list: list[str] # 歌曲名列表
|
||||
|
||||
|
||||
# 歌单新增歌曲
|
||||
@app.post("/playlistaddmusic")
|
||||
async def playlistaddmusic(data: PlayListMusicObj, Verifcation=Depends(verification)):
|
||||
ret = xiaomusic.play_list_add_music(data.name, data.music_list)
|
||||
if ret:
|
||||
return {"ret": "OK"}
|
||||
return {"ret": "Add failed, may be playlist not exist."}
|
||||
|
||||
|
||||
# 歌单移除歌曲
|
||||
@app.post("/playlistdelmusic")
|
||||
async def playlistdelmusic(data: PlayListMusicObj, Verifcation=Depends(verification)):
|
||||
ret = xiaomusic.play_list_del_music(data.name, data.music_list)
|
||||
if ret:
|
||||
return {"ret": "OK"}
|
||||
return {"ret": "Del failed, may be playlist not exist."}
|
||||
|
||||
|
||||
async def file_iterator(file_path, start, end):
|
||||
async with aiofiles.open(file_path, mode="rb") as file:
|
||||
await file.seek(start)
|
||||
|
||||
@@ -4,17 +4,21 @@ $(function(){
|
||||
append_op_button_name("加入收藏");
|
||||
append_op_button_name("取消收藏");
|
||||
|
||||
const PLAY_TYPE_ONE = 0; // 单曲循环
|
||||
const PLAY_TYPE_ALL = 1; // 全部循环
|
||||
const PLAY_TYPE_RND = 2; // 随机播放
|
||||
append_op_button("play_type_all", "全部循环", "全部循环");
|
||||
append_op_button("play_type_one", "单曲循环", "单曲循环");
|
||||
append_op_button("play_type_rnd", "随机播放", "随机播放");
|
||||
|
||||
append_op_button_name("上一首");
|
||||
append_op_button_name("关机");
|
||||
append_op_button_name("下一首");
|
||||
|
||||
const PLAY_TYPE_ONE = 0; // 单曲循环
|
||||
const PLAY_TYPE_ALL = 1; // 全部循环
|
||||
const PLAY_TYPE_RND = 2; // 随机播放
|
||||
const PLAY_TYPE_SIN = 3; // 单曲播放
|
||||
const PLAY_TYPE_SEQ = 4; // 顺序播放
|
||||
append_op_button("play_type_all", "全部循环", "全部循环");
|
||||
append_op_button("play_type_one", "单曲循环", "单曲循环");
|
||||
append_op_button("play_type_rnd", "随机播放", "随机播放");
|
||||
append_op_button("play_type_sin", "单曲播放", "单曲播放");
|
||||
append_op_button("play_type_seq", "顺序播放", "顺序播放");
|
||||
|
||||
append_op_button_name("刷新列表");
|
||||
|
||||
$container.append($("<hr>"));
|
||||
@@ -71,6 +75,12 @@ $(function(){
|
||||
} else if (cur_device.play_type == PLAY_TYPE_RND) {
|
||||
$("#play_type_rnd").css('background-color', '#b1a8f3');
|
||||
$("#play_type_rnd").text('✔️ 随机播放');
|
||||
} else if (cur_device.play_type == PLAY_TYPE_SIN) {
|
||||
$("#play_type_sin").css('background-color', '#b1a8f3');
|
||||
$("#play_type_sin").text('✔️ 单曲播放');
|
||||
} else if (cur_device.play_type == PLAY_TYPE_SEQ) {
|
||||
$("#play_type_seq").css('background-color', '#b1a8f3');
|
||||
$("#play_type_seq").text('✔️ 顺序播放');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,7 +308,7 @@ $(function(){
|
||||
if (cmd == "刷新列表") {
|
||||
check_status_refresh_music_list(3); // 最多重试3次
|
||||
}
|
||||
if (["全部循环", "单曲循环", "随机播放"].includes(cmd)) {
|
||||
if (["全部循环", "单曲循环", "随机播放", "单曲播放", "顺序播放"].includes(cmd)) {
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>Debug For XiaoMusic</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1731543339">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1732797036">
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script src="./jquery-3.7.1.min.js?version=1731543339"></script>
|
||||
<script src="./jquery-3.7.1.min.js?version=1732797036"></script>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>歌曲下载工具</title>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1731543339">
|
||||
<script src="./jquery-3.7.1.min.js?version=1731543339"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1732797036">
|
||||
<script src="./jquery-3.7.1.min.js?version=1732797036"></script>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="./jquery-3.7.1.min.js?version=1731543339"></script>
|
||||
<script src="./app.js?version=1731543339"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1731543339">
|
||||
<script src="./jquery-3.7.1.min.js?version=1732797036"></script>
|
||||
<script src="./app.js?version=1732797036"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1732797036">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>M3U to JSON Converter</title>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1731543339">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1732797036">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="./jquery-3.7.1.min.js?version=1731543339"></script>
|
||||
<script src="./setting.js?version=1731543339"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1731543339">
|
||||
<script src="./jquery-3.7.1.min.js?version=1732797036"></script>
|
||||
<script src="./setting.js?version=1732797036"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1732797036">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
@@ -71,10 +71,12 @@ var vConsole = new window.VConsole();
|
||||
<label for="conf_path">配置文件目录:</label>
|
||||
<input id="conf_path" type="text"></input>
|
||||
|
||||
|
||||
<label for="cache_dir">缓存文件目录:</label>
|
||||
<input id="cache_dir" type="text"></input>
|
||||
|
||||
<label for="temp_path">临时文件目录:</label>
|
||||
<input id="temp_path" type="text" value="music/tmp"></input>
|
||||
|
||||
<label for="ffmpeg_location">ffmpeg路径:</label>
|
||||
<input id="ffmpeg_location" type="text" value="./ffmpeg/bin"></input>
|
||||
|
||||
@@ -85,7 +87,7 @@ var vConsole = new window.VConsole();
|
||||
<input id="active_cmd" type="text" value="play,random_play,playlocal,play_music_list,stop"></input>
|
||||
|
||||
<label for="exclude_dirs">忽略目录(逗号分割):</label>
|
||||
<input id="exclude_dirs" type="text" value="@eaDir"></input>
|
||||
<input id="exclude_dirs" type="text" value="@eaDir,tmp"></input>
|
||||
|
||||
<label for="music_path_depth">目录深度:</label>
|
||||
<input id="music_path_depth" type="number" value="10"></input>
|
||||
@@ -170,6 +172,17 @@ var vConsole = new window.VConsole();
|
||||
|
||||
<label for="stop_tts_msg">停止提示音:</label>
|
||||
<input id="stop_tts_msg" type="text" value="收到,再见"></input>
|
||||
<label for="play_type_one_tts_msg">单曲循环提示音:</label>
|
||||
<input id="play_type_one_tts_msg" type="text" value="已经设置为单曲循环"></input>
|
||||
<label for="play_type_all_tts_msg">全部循环提示音:</label>
|
||||
<input id="play_type_all_tts_msg" type="text" value="已经设置为全部循环"></input>
|
||||
<label for="play_type_rnd_tts_msg">随机播放提示音:</label>
|
||||
<input id="play_type_rnd_tts_msg" type="text" value="已经设置为随机播放"></input>
|
||||
<label for="play_type_sin_tts_msg">单曲播放提示音:</label>
|
||||
<input id="play_type_sin_tts_msg" type="text" value="已经设置为单曲播放"></input>
|
||||
<label for="play_type_seq_tts_msg">顺序播放提示音:</label>
|
||||
<input id="play_type_seq_tts_msg" type="text" value="已经设置为顺序播放"></input>
|
||||
|
||||
<label for="keywords_playlocal">播放本地歌曲口令:</label>
|
||||
<input id="keywords_playlocal" type="text" value="播放本地歌曲,本地播放歌曲"></input>
|
||||
<label for="keywords_play">播放歌曲口令:</label>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
"short_name": "小爱音箱",
|
||||
"theme_color": "#FFFFFF",
|
||||
"description": "XiaoMusic: 无限听歌,解放小爱音箱!",
|
||||
"orientation": "any",
|
||||
"orientation": "natural",
|
||||
"background_color": "#FFFFFF",
|
||||
"prefer_related_applications": false,
|
||||
"display_override": [
|
||||
|
||||
@@ -407,14 +407,6 @@ def no_padding(info):
|
||||
return 0
|
||||
|
||||
|
||||
def get_temp_dir(music_path: str):
|
||||
# 指定临时文件的目录为 music_path 目录下的 tmp 文件夹
|
||||
temp_dir = os.path.join(music_path, "tmp")
|
||||
if not os.path.exists(temp_dir):
|
||||
os.makedirs(temp_dir) # 确保目录存在
|
||||
return temp_dir
|
||||
|
||||
|
||||
def remove_id3_tags(input_file: str, config) -> str:
|
||||
audio = MP3(input_file, ID3=ID3)
|
||||
|
||||
@@ -426,7 +418,7 @@ def remove_id3_tags(input_file: str, config) -> str:
|
||||
return None
|
||||
|
||||
music_path = config.music_path
|
||||
temp_dir = get_temp_dir(music_path)
|
||||
temp_dir = config.temp_dir
|
||||
|
||||
# 构造新文件的路径
|
||||
out_file_name = os.path.splitext(os.path.basename(input_file))[0]
|
||||
@@ -459,7 +451,7 @@ def remove_id3_tags(input_file: str, config) -> str:
|
||||
|
||||
def convert_file_to_mp3(input_file: str, config) -> str:
|
||||
music_path = config.music_path
|
||||
temp_dir = get_temp_dir(music_path)
|
||||
temp_dir = config.temp_dir
|
||||
|
||||
out_file_name = os.path.splitext(os.path.basename(input_file))[0]
|
||||
out_file_path = os.path.join(temp_dir, f"{out_file_name}.mp3")
|
||||
@@ -526,6 +518,13 @@ def chinese_to_number(chinese):
|
||||
result = 0
|
||||
unit = 1
|
||||
num = 0
|
||||
# 处理特殊情况:以"十"开头时,在前面加"一"
|
||||
if chinese.startswith("十"):
|
||||
chinese = "一" + chinese
|
||||
|
||||
# 如果只有一个字符且是单位,直接返回其值
|
||||
if len(chinese) == 1 and chinese_to_arabic[chinese] >= 10:
|
||||
return chinese_to_arabic[chinese]
|
||||
for char in reversed(chinese):
|
||||
if char in chinese_to_arabic:
|
||||
val = chinese_to_arabic[char]
|
||||
@@ -536,8 +535,8 @@ def chinese_to_number(chinese):
|
||||
unit *= val
|
||||
else:
|
||||
num += val * unit
|
||||
result += num
|
||||
num = 0
|
||||
result += num
|
||||
|
||||
return result
|
||||
|
||||
|
||||
|
||||
@@ -31,7 +31,8 @@ from xiaomusic.const import (
|
||||
PLAY_TYPE_ALL,
|
||||
PLAY_TYPE_ONE,
|
||||
PLAY_TYPE_RND,
|
||||
PLAY_TYPE_TTS,
|
||||
PLAY_TYPE_SEQ,
|
||||
PLAY_TYPE_SIN,
|
||||
SUPPORT_MUSIC_TYPE,
|
||||
)
|
||||
from xiaomusic.crontab import Crontab
|
||||
@@ -75,6 +76,7 @@ class XiaoMusic:
|
||||
self.all_music_tags = {} # 歌曲额外信息
|
||||
self._tag_generation_task = False
|
||||
self._extra_index_search = {}
|
||||
self.custom_play_list = None
|
||||
|
||||
# 初始化配置
|
||||
self.init_config()
|
||||
@@ -623,7 +625,6 @@ class XiaoMusic:
|
||||
self.music_list["所有歌曲"] = [
|
||||
name for name in self.all_music.keys() if name not in self._all_radio
|
||||
]
|
||||
self._append_custom_play_list()
|
||||
|
||||
# 网络歌单
|
||||
try:
|
||||
@@ -641,9 +642,11 @@ class XiaoMusic:
|
||||
for _, play_list in self.music_list.items():
|
||||
play_list.sort(key=custom_sort_key)
|
||||
|
||||
# 刷新自定义歌单
|
||||
self.refresh_custom_play_list()
|
||||
|
||||
# 更新每个设备的歌单
|
||||
for device in self.devices.values():
|
||||
device.update_playlist()
|
||||
self.update_all_playlist()
|
||||
|
||||
# 重建索引
|
||||
self._extra_index_search = {}
|
||||
@@ -655,13 +658,11 @@ class XiaoMusic:
|
||||
# all_music 更新,重建 tag
|
||||
self.try_gen_all_music_tag()
|
||||
|
||||
def _append_custom_play_list(self):
|
||||
if not self.config.custom_play_list_json:
|
||||
return
|
||||
|
||||
def refresh_custom_play_list(self):
|
||||
try:
|
||||
custom_play_list = json.loads(self.config.custom_play_list_json)
|
||||
self.music_list["收藏"] = list(custom_play_list["收藏"])
|
||||
custom_play_list = self.get_custom_play_list()
|
||||
for k, v in custom_play_list.items():
|
||||
self.music_list[k] = list(v)
|
||||
except Exception as e:
|
||||
self.log.exception(f"Execption {e}")
|
||||
|
||||
@@ -885,15 +886,26 @@ class XiaoMusic:
|
||||
|
||||
# 设置为单曲循环
|
||||
async def set_play_type_one(self, did="", **kwargs):
|
||||
await self.devices[did].set_play_type(PLAY_TYPE_ONE)
|
||||
await self.set_play_type(did, PLAY_TYPE_ONE)
|
||||
|
||||
# 设置为全部循环
|
||||
async def set_play_type_all(self, did="", **kwargs):
|
||||
await self.devices[did].set_play_type(PLAY_TYPE_ALL)
|
||||
await self.set_play_type(did, PLAY_TYPE_ALL)
|
||||
|
||||
# 设置为随机播放
|
||||
async def set_random_play(self, did="", **kwargs):
|
||||
await self.devices[did].set_play_type(PLAY_TYPE_RND)
|
||||
async def set_play_type_rnd(self, did="", **kwargs):
|
||||
await self.set_play_type(did, PLAY_TYPE_RND)
|
||||
|
||||
# 设置为单曲播放
|
||||
async def set_play_type_sin(self, did="", **kwargs):
|
||||
await self.set_play_type(did, PLAY_TYPE_SIN)
|
||||
|
||||
# 设置为顺序播放
|
||||
async def set_play_type_seq(self, did="", **kwargs):
|
||||
await self.set_play_type(did, PLAY_TYPE_SEQ)
|
||||
|
||||
async def set_play_type(self, did="", play_type=PLAY_TYPE_RND, dotts=True):
|
||||
await self.devices[did].set_play_type(play_type, dotts)
|
||||
|
||||
# 设置为刷新列表
|
||||
async def gen_music_list(self, **kwargs):
|
||||
@@ -1007,12 +1019,7 @@ class XiaoMusic:
|
||||
if not name:
|
||||
return
|
||||
|
||||
favorites = self.music_list.get("收藏", [])
|
||||
if name in favorites:
|
||||
return
|
||||
|
||||
favorites.append(name)
|
||||
self.save_favorites(favorites)
|
||||
self.play_list_add_music("收藏", name)
|
||||
|
||||
# 从收藏列表中移除
|
||||
async def del_from_favorites(self, did="", arg1="", **kwargs):
|
||||
@@ -1020,27 +1027,69 @@ class XiaoMusic:
|
||||
if not name:
|
||||
return
|
||||
|
||||
favorites = self.music_list.get("收藏", [])
|
||||
if name not in favorites:
|
||||
return
|
||||
self.play_list_del_music("收藏", name)
|
||||
|
||||
favorites.remove(name)
|
||||
self.save_favorites(favorites)
|
||||
# 更新每个设备的歌单
|
||||
def update_all_playlist(self):
|
||||
for device in self.devices.values():
|
||||
device.update_playlist()
|
||||
|
||||
def save_favorites(self, favorites):
|
||||
self.music_list["收藏"] = favorites
|
||||
custom_play_list = {}
|
||||
if self.config.custom_play_list_json:
|
||||
custom_play_list = json.loads(self.config.custom_play_list_json)
|
||||
custom_play_list["收藏"] = favorites
|
||||
def get_custom_play_list(self):
|
||||
if self.custom_play_list is None:
|
||||
self.custom_play_list = {}
|
||||
if self.config.custom_play_list_json:
|
||||
self.custom_play_list = json.loads(self.config.custom_play_list_json)
|
||||
return self.custom_play_list
|
||||
|
||||
def save_custom_play_list(self):
|
||||
custom_play_list = self.get_custom_play_list()
|
||||
self.refresh_custom_play_list()
|
||||
self.config.custom_play_list_json = json.dumps(
|
||||
custom_play_list, ensure_ascii=False
|
||||
)
|
||||
self.save_cur_config()
|
||||
|
||||
# 更新每个设备的歌单
|
||||
for device in self.devices.values():
|
||||
device.update_playlist()
|
||||
# 新增歌单
|
||||
def play_list_add(self, name):
|
||||
custom_play_list = self.get_custom_play_list()
|
||||
if name in custom_play_list:
|
||||
return False
|
||||
custom_play_list[name] = []
|
||||
self.save_custom_play_list()
|
||||
return True
|
||||
|
||||
# 移除歌单
|
||||
def play_list_del(self, name):
|
||||
custom_play_list = self.get_custom_play_list()
|
||||
if name not in custom_play_list:
|
||||
return False
|
||||
custom_play_list.pop(name)
|
||||
self.save_custom_play_list()
|
||||
return True
|
||||
|
||||
# 歌单新增歌曲
|
||||
def play_list_add_music(self, name, music_list):
|
||||
custom_play_list = self.get_custom_play_list()
|
||||
if name not in custom_play_list:
|
||||
return False
|
||||
play_list = custom_play_list[name]
|
||||
for music_name in music_list:
|
||||
if (music_name in self.all_music) and (music_name not in play_list):
|
||||
play_list.append(music_name)
|
||||
self.save_custom_play_list()
|
||||
return True
|
||||
|
||||
# 歌单移除歌曲
|
||||
def play_list_del_music(self, name, music_list):
|
||||
custom_play_list = self.get_custom_play_list()
|
||||
if name not in custom_play_list:
|
||||
return False
|
||||
play_list = custom_play_list[name]
|
||||
for music_name in music_list:
|
||||
if music_name in play_list:
|
||||
play_list.pop(music_name)
|
||||
self.save_custom_play_list()
|
||||
return True
|
||||
|
||||
# 获取音量
|
||||
async def get_volume(self, did="", **kwargs):
|
||||
@@ -1308,6 +1357,7 @@ class XiaoMusicDevice:
|
||||
if (
|
||||
self.device.play_type == PLAY_TYPE_ALL
|
||||
or self.device.play_type == PLAY_TYPE_RND
|
||||
or self.device.play_type == PLAY_TYPE_SEQ
|
||||
or name == ""
|
||||
or (
|
||||
(name not in self._play_list) and self.device.play_type != PLAY_TYPE_ONE
|
||||
@@ -1394,6 +1444,10 @@ class XiaoMusicDevice:
|
||||
self.log.info(f"【{name}】已经开始播放了")
|
||||
await self.xiaomusic.analytics.send_play_event(name, sec)
|
||||
|
||||
if self.device.play_type == PLAY_TYPE_SIN:
|
||||
self.log.info(f"【{name}】单曲播放时不会设置下一首歌的定时器")
|
||||
return
|
||||
|
||||
# 设置下一首歌曲的播放定时器
|
||||
if sec <= 1:
|
||||
self.log.info(f"【{name}】不会设置下一首歌的定时器")
|
||||
@@ -1546,6 +1600,12 @@ class XiaoMusicDevice:
|
||||
else:
|
||||
if direction == "next":
|
||||
new_index = index + 1
|
||||
if (
|
||||
self.device.play_type == PLAY_TYPE_SEQ
|
||||
and new_index >= play_list_len
|
||||
):
|
||||
self.log.info("顺序播放结束")
|
||||
return ""
|
||||
if new_index >= play_list_len:
|
||||
new_index = 0
|
||||
elif direction == "prev":
|
||||
@@ -1721,11 +1781,12 @@ class XiaoMusicDevice:
|
||||
self.log.info("get_volume. volume:%d", volume)
|
||||
return volume
|
||||
|
||||
async def set_play_type(self, play_type):
|
||||
async def set_play_type(self, play_type, dotts=True):
|
||||
self.device.play_type = play_type
|
||||
self.xiaomusic.save_cur_config()
|
||||
tts = PLAY_TYPE_TTS[play_type]
|
||||
await self.do_tts(tts)
|
||||
if dotts:
|
||||
tts = self.config.get_play_type_tts(play_type)
|
||||
await self.do_tts(tts)
|
||||
self.update_playlist()
|
||||
|
||||
async def play_music_list(self, list_name, music_name):
|
||||
|
||||
Reference in New Issue
Block a user