mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-08 15:08:12 +08:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dbc68d6b56 | ||
|
|
5dabf66e7c | ||
|
|
d6e4478eb6 | ||
|
|
23ef4719ba | ||
|
|
d799a85ab9 | ||
|
|
4ad6bcc636 | ||
|
|
d2473ec7e8 | ||
|
|
28797edc7c | ||
|
|
be1a643071 | ||
|
|
ee6b9778ac | ||
|
|
881c34bcb5 | ||
|
|
c22fc99235 | ||
|
|
0874efe58b |
54
pdm.lock
generated
54
pdm.lock
generated
@@ -5,7 +5,7 @@
|
|||||||
groups = ["default", "lint"]
|
groups = ["default", "lint"]
|
||||||
strategy = ["cross_platform"]
|
strategy = ["cross_platform"]
|
||||||
lock_version = "4.4.1"
|
lock_version = "4.4.1"
|
||||||
content_hash = "sha256:fa83f8134ccb4a432304dead5fe1303899418558634abaa0824e8d9fdfb1f490"
|
content_hash = "sha256:38bae754be83ffca7d688fc4e1daf0964709d202d651c6c865ff56c1b8332caa"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "aiohttp"
|
name = "aiohttp"
|
||||||
@@ -620,8 +620,8 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "requests"
|
name = "requests"
|
||||||
version = "2.31.0"
|
version = "2.32.3"
|
||||||
requires_python = ">=3.7"
|
requires_python = ">=3.8"
|
||||||
summary = "Python HTTP for Humans."
|
summary = "Python HTTP for Humans."
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"certifi>=2017.4.17",
|
"certifi>=2017.4.17",
|
||||||
@@ -630,8 +630,8 @@ dependencies = [
|
|||||||
"urllib3<3,>=1.21.1",
|
"urllib3<3,>=1.21.1",
|
||||||
]
|
]
|
||||||
files = [
|
files = [
|
||||||
{file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"},
|
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
|
||||||
{file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"},
|
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -650,27 +650,27 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.4.8"
|
version = "0.4.9"
|
||||||
requires_python = ">=3.7"
|
requires_python = ">=3.7"
|
||||||
summary = "An extremely fast Python linter and code formatter, written in Rust."
|
summary = "An extremely fast Python linter and code formatter, written in Rust."
|
||||||
files = [
|
files = [
|
||||||
{file = "ruff-0.4.8-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:7663a6d78f6adb0eab270fa9cf1ff2d28618ca3a652b60f2a234d92b9ec89066"},
|
{file = "ruff-0.4.9-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991"},
|
||||||
{file = "ruff-0.4.8-py3-none-macosx_11_0_arm64.whl", hash = "sha256:eeceb78da8afb6de0ddada93112869852d04f1cd0f6b80fe464fd4e35c330913"},
|
{file = "ruff-0.4.9-py3-none-macosx_11_0_arm64.whl", hash = "sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aad360893e92486662ef3be0a339c5ca3c1b109e0134fcd37d534d4be9fb8de3"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:284c2e3f3396fb05f5f803c9fffb53ebbe09a3ebe7dda2929ed8d73ded736deb"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7354f921e3fbe04d2a62d46707e569f9315e1a613307f7311a935743c51a764"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:72584676164e15a68a15778fd1b17c28a519e7a0622161eb2debdcdabdc71883"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9678d5c9b43315f323af2233a04d747409d1e3aa6789620083a82d1066a35199"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704977a658131651a22b5ebeb28b717ef42ac6ee3b11e91dc87b633b5d83142b"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893"},
|
||||||
{file = "ruff-0.4.8-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05f8d6f0c3cce5026cecd83b7a143dcad503045857bc49662f736437380ad45"},
|
{file = "ruff-0.4.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:6ea874950daca5697309d976c9afba830d3bf0ed66887481d6bca1673fc5b66a"},
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fc95aac2943ddf360376be9aa3107c8cf9640083940a8c5bd824be692d2216dc"},
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_i686.whl", hash = "sha256:384154a1c3f4bf537bac69f33720957ee49ac8d484bfc91720cc94172026ceed"},
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_i686.whl", hash = "sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84"},
|
||||||
{file = "ruff-0.4.8-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:e9d5ce97cacc99878aa0d084c626a15cd21e6b3d53fd6f9112b7fc485918e1fa"},
|
{file = "ruff-0.4.9-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db"},
|
||||||
{file = "ruff-0.4.8-py3-none-win32.whl", hash = "sha256:6d795d7639212c2dfd01991259460101c22aabf420d9b943f153ab9d9706e6a9"},
|
{file = "ruff-0.4.9-py3-none-win32.whl", hash = "sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521"},
|
||||||
{file = "ruff-0.4.8-py3-none-win_amd64.whl", hash = "sha256:e14a3a095d07560a9d6769a72f781d73259655919d9b396c650fc98a8157555d"},
|
{file = "ruff-0.4.9-py3-none-win_amd64.whl", hash = "sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52"},
|
||||||
{file = "ruff-0.4.8-py3-none-win_arm64.whl", hash = "sha256:14019a06dbe29b608f6b7cbcec300e3170a8d86efaddb7b23405cb7f7dcaf780"},
|
{file = "ruff-0.4.9-py3-none-win_arm64.whl", hash = "sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198"},
|
||||||
{file = "ruff-0.4.8.tar.gz", hash = "sha256:16d717b1d57b2e2fd68bd0bf80fb43931b79d05a7131aa477d66fc40fbd86268"},
|
{file = "ruff-0.4.9.tar.gz", hash = "sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3"},
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -819,7 +819,7 @@ files = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "yt-dlp"
|
name = "yt-dlp"
|
||||||
version = "2024.5.16.232713.dev0"
|
version = "2024.6.17.232743.dev0"
|
||||||
requires_python = ">=3.8"
|
requires_python = ">=3.8"
|
||||||
summary = "A feature-rich command-line audio/video downloader"
|
summary = "A feature-rich command-line audio/video downloader"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
@@ -828,11 +828,11 @@ dependencies = [
|
|||||||
"certifi",
|
"certifi",
|
||||||
"mutagen",
|
"mutagen",
|
||||||
"pycryptodomex",
|
"pycryptodomex",
|
||||||
"requests<3,>=2.31.0",
|
"requests<3,>=2.32.2",
|
||||||
"urllib3<3,>=1.26.17",
|
"urllib3<3,>=1.26.17",
|
||||||
"websockets>=12.0",
|
"websockets>=12.0",
|
||||||
]
|
]
|
||||||
files = [
|
files = [
|
||||||
{file = "yt_dlp-2024.5.16.232713.dev0-py3-none-any.whl", hash = "sha256:42d3c27ab77583ff67ee2ddc94e376ea2a76a561ed8b1836ee04fd1cd23ad88c"},
|
{file = "yt_dlp-2024.6.17.232743.dev0-py3-none-any.whl", hash = "sha256:dd6e7e194b96e778691f58a0cb6b42956cf956b22f6bb1a12bdef5ab3ac0c9ad"},
|
||||||
{file = "yt_dlp-2024.5.16.232713.dev0.tar.gz", hash = "sha256:d431187fa703c9f52225080ae56471272679e44d9363f97b7b3187d37a5e6480"},
|
{file = "yt_dlp-2024.6.17.232743.dev0.tar.gz", hash = "sha256:2f6f44eff755a7b051cdcd3c4375771033dbeb64d6164351022efdc67cce0c52"},
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,12 +1,11 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "xiaomusic"
|
name = "xiaomusic"
|
||||||
version = "0.1.45"
|
version = "0.1.52"
|
||||||
description = "Play Music with xiaomi AI speaker"
|
description = "Play Music with xiaomi AI speaker"
|
||||||
authors = [
|
authors = [
|
||||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rich>=13.6.0",
|
|
||||||
"requests>=2.31.0",
|
"requests>=2.31.0",
|
||||||
"aiohttp>=3.8.6",
|
"aiohttp>=3.8.6",
|
||||||
"miservice-fork>=2.5.0",
|
"miservice-fork>=2.5.0",
|
||||||
@@ -29,7 +28,7 @@ lint = [
|
|||||||
"ruff>=0.4.8",
|
"ruff>=0.4.8",
|
||||||
]
|
]
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
select = [
|
lint.select = [
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"C4", # flake8-comprehensions
|
"C4", # flake8-comprehensions
|
||||||
"E", # pycodestyle - Error
|
"E", # pycodestyle - Error
|
||||||
@@ -38,13 +37,13 @@ select = [
|
|||||||
"W", # pycodestyle - Warning
|
"W", # pycodestyle - Warning
|
||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
]
|
]
|
||||||
ignore = [
|
lint.ignore = [
|
||||||
"E501", # line-too-long
|
"E501", # line-too-long
|
||||||
"W191", # tab-indentation
|
"W191", # tab-indentation
|
||||||
]
|
]
|
||||||
include = ["**/*.py", "**/*.pyi", "**/pyproject.toml"]
|
include = ["**/*.py", "**/*.pyi", "**/pyproject.toml"]
|
||||||
|
|
||||||
[tool.ruff.pydocstyle]
|
[tool.ruff.lint.pydocstyle]
|
||||||
convention = "google"
|
convention = "google"
|
||||||
|
|
||||||
[tool.pdm.scripts]
|
[tool.pdm.scripts]
|
||||||
|
|||||||
@@ -368,9 +368,9 @@ pycryptodomex==3.19.0 \
|
|||||||
pygments==2.16.1 \
|
pygments==2.16.1 \
|
||||||
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
|
--hash=sha256:13fc09fa63bc8d8671a6d247e1eb303c4b343eaee81d861f3404db2935653692 \
|
||||||
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
|
--hash=sha256:1daff0494820c69bc8941e407aa20f577374ee88364ee10a98fdbe0aece96e29
|
||||||
requests==2.31.0 \
|
requests==2.32.3 \
|
||||||
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
|
--hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
|
||||||
--hash=sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1
|
--hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
|
||||||
rich==13.7.1 \
|
rich==13.7.1 \
|
||||||
--hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \
|
--hash=sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222 \
|
||||||
--hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432
|
--hash=sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432
|
||||||
@@ -469,6 +469,6 @@ yarl==1.9.2 \
|
|||||||
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
|
--hash=sha256:d4e2c6d555e77b37288eaf45b8f60f0737c9efa3452c6c44626a5455aeb250b9 \
|
||||||
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
|
--hash=sha256:e9fdc7ac0d42bc3ea78818557fab03af6181e076a2944f43c38684b4b6bed8e3 \
|
||||||
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560
|
--hash=sha256:ee4afac41415d52d53a9833ebae7e32b344be72835bbb589018c9e938045a560
|
||||||
yt-dlp==2024.5.16.232713.dev0 \
|
yt-dlp==2024.6.17.232743.dev0 \
|
||||||
--hash=sha256:42d3c27ab77583ff67ee2ddc94e376ea2a76a561ed8b1836ee04fd1cd23ad88c \
|
--hash=sha256:2f6f44eff755a7b051cdcd3c4375771033dbeb64d6164351022efdc67cce0c52 \
|
||||||
--hash=sha256:d431187fa703c9f52225080ae56471272679e44d9363f97b7b3187d37a5e6480
|
--hash=sha256:dd6e7e194b96e778691f58a0cb6b42956cf956b22f6bb1a12bdef5ab3ac0c9ad
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.1.45"
|
__version__ = "0.1.52"
|
||||||
|
|||||||
@@ -95,6 +95,7 @@ class Config:
|
|||||||
) # "bilisearch:" or "ytsearch:"
|
) # "bilisearch:" or "ytsearch:"
|
||||||
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
|
ffmpeg_location: str = os.getenv("XIAOMUSIC_FFMPEG_LOCATION", "./ffmpeg/bin")
|
||||||
active_cmd: str = os.getenv("XIAOMUSIC_ACTIVE_CMD", "play,random_play")
|
active_cmd: str = os.getenv("XIAOMUSIC_ACTIVE_CMD", "play,random_play")
|
||||||
|
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir")
|
||||||
|
|
||||||
def __post_init__(self) -> None:
|
def __post_init__(self) -> None:
|
||||||
if self.proxy:
|
if self.proxy:
|
||||||
|
|||||||
@@ -38,7 +38,8 @@ $(function(){
|
|||||||
$('#music_list').change(function() {
|
$('#music_list').change(function() {
|
||||||
const selectedValue = $(this).val();
|
const selectedValue = $(this).val();
|
||||||
$('#music_name').empty();
|
$('#music_name').empty();
|
||||||
$.each(data[selectedValue], function(index, item) {
|
const sorted_musics = data[selectedValue].sort(custom_sort_key);
|
||||||
|
$.each(sorted_musics, function(index, item) {
|
||||||
$('#music_name').append($('<option></option>').val(item).text(item));
|
$('#music_name').append($('<option></option>').val(item).text(item));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -163,4 +164,23 @@ $(function(){
|
|||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
get_playing_music();
|
get_playing_music();
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
|
function custom_sort_key(a, b) {
|
||||||
|
// 使用正则表达式提取数字前缀
|
||||||
|
const numericPrefixA = a.match(/^(\d+)/) ? parseInt(a.match(/^(\d+)/)[1], 10) : null;
|
||||||
|
const numericPrefixB = b.match(/^(\d+)/) ? parseInt(b.match(/^(\d+)/)[1], 10) : null;
|
||||||
|
|
||||||
|
// 如果两个键都有数字前缀,则按数字大小排序
|
||||||
|
if (numericPrefixA !== null && numericPrefixB !== null) {
|
||||||
|
return numericPrefixA - numericPrefixB;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果一个键有数字前缀而另一个没有,则有数字前缀的键排在前面
|
||||||
|
if (numericPrefixA !== null) return -1;
|
||||||
|
if (numericPrefixB !== null) return 1;
|
||||||
|
|
||||||
|
// 如果两个键都没有数字前缀,则按照常规字符串排序
|
||||||
|
return a.localeCompare(b);
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -64,3 +64,23 @@ def validate_proxy(proxy_str: str) -> bool:
|
|||||||
# 模糊搜索
|
# 模糊搜索
|
||||||
def fuzzyfinder(user_input, collection):
|
def fuzzyfinder(user_input, collection):
|
||||||
return difflib.get_close_matches(user_input, collection, 10, cutoff=0.1)
|
return difflib.get_close_matches(user_input, collection, 10, cutoff=0.1)
|
||||||
|
|
||||||
|
|
||||||
|
# 歌曲排序
|
||||||
|
def custom_sort_key(s):
|
||||||
|
# 使用正则表达式分别提取字符串的数字前缀和数字后缀
|
||||||
|
prefix_match = re.match(r"^(\d+)", s)
|
||||||
|
suffix_match = re.search(r"(\d+)$", s)
|
||||||
|
|
||||||
|
numeric_prefix = int(prefix_match.group(0)) if prefix_match else None
|
||||||
|
numeric_suffix = int(suffix_match.group(0)) if suffix_match else None
|
||||||
|
|
||||||
|
if numeric_prefix is not None:
|
||||||
|
# 如果前缀是数字,先按前缀数字排序,再按整个字符串排序
|
||||||
|
return (0, numeric_prefix, s)
|
||||||
|
elif numeric_suffix is not None:
|
||||||
|
# 如果后缀是数字,先按前缀字符排序,再按后缀数字排序
|
||||||
|
return (1, s[: suffix_match.start()], numeric_suffix)
|
||||||
|
else:
|
||||||
|
# 如果前缀和后缀都不是数字,按字典序排序
|
||||||
|
return (2, s)
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ from pathlib import Path
|
|||||||
import mutagen
|
import mutagen
|
||||||
from aiohttp import ClientSession, ClientTimeout
|
from aiohttp import ClientSession, ClientTimeout
|
||||||
from miservice import MiAccount, MiIOService, MiNAService, miio_command
|
from miservice import MiAccount, MiIOService, MiNAService, miio_command
|
||||||
from rich.logging import RichHandler
|
|
||||||
|
|
||||||
from xiaomusic import (
|
from xiaomusic import (
|
||||||
__version__,
|
__version__,
|
||||||
@@ -30,6 +29,7 @@ from xiaomusic.config import (
|
|||||||
)
|
)
|
||||||
from xiaomusic.httpserver import StartHTTPServer
|
from xiaomusic.httpserver import StartHTTPServer
|
||||||
from xiaomusic.utils import (
|
from xiaomusic.utils import (
|
||||||
|
custom_sort_key,
|
||||||
fuzzyfinder,
|
fuzzyfinder,
|
||||||
parse_cookie_string,
|
parse_cookie_string,
|
||||||
)
|
)
|
||||||
@@ -38,6 +38,7 @@ EOF = object()
|
|||||||
|
|
||||||
PLAY_TYPE_ONE = 0 # 单曲循环
|
PLAY_TYPE_ONE = 0 # 单曲循环
|
||||||
PLAY_TYPE_ALL = 1 # 全部循环
|
PLAY_TYPE_ALL = 1 # 全部循环
|
||||||
|
PLAY_TYPE_RND = 2 # 随机播放
|
||||||
|
|
||||||
|
|
||||||
class XiaoMusic:
|
class XiaoMusic:
|
||||||
@@ -62,11 +63,12 @@ class XiaoMusic:
|
|||||||
self.search_prefix = config.search_prefix
|
self.search_prefix = config.search_prefix
|
||||||
self.ffmpeg_location = config.ffmpeg_location
|
self.ffmpeg_location = config.ffmpeg_location
|
||||||
self.active_cmd = config.active_cmd.split(",")
|
self.active_cmd = config.active_cmd.split(",")
|
||||||
|
self.exclude_dirs = set(config.exclude_dirs.split(","))
|
||||||
|
|
||||||
# 下载对象
|
# 下载对象
|
||||||
self.download_proc = None
|
self.download_proc = None
|
||||||
# 单曲循环,全部循环
|
# 单曲循环,全部循环
|
||||||
self.play_type = PLAY_TYPE_ALL
|
self.play_type = PLAY_TYPE_RND
|
||||||
self.cur_music = ""
|
self.cur_music = ""
|
||||||
self._next_timer = None
|
self._next_timer = None
|
||||||
self._timeout = 0
|
self._timeout = 0
|
||||||
@@ -82,9 +84,8 @@ class XiaoMusic:
|
|||||||
|
|
||||||
# setup logger
|
# setup logger
|
||||||
logging.basicConfig(
|
logging.basicConfig(
|
||||||
format=f"[{__version__}]\t%(message)s",
|
format=f"%(asctime)s [{__version__}] [%(levelname)s] %(message)s",
|
||||||
datefmt="[%X]",
|
datefmt="[%X]",
|
||||||
handlers=[RichHandler(rich_tracebacks=True)],
|
|
||||||
)
|
)
|
||||||
self.log = logging.getLogger("xiaomusic")
|
self.log = logging.getLogger("xiaomusic")
|
||||||
self.log.setLevel(logging.DEBUG if config.verbose else logging.INFO)
|
self.log.setLevel(logging.DEBUG if config.verbose else logging.INFO)
|
||||||
@@ -199,13 +200,12 @@ class XiaoMusic:
|
|||||||
for i in range(retries):
|
for i in range(retries):
|
||||||
try:
|
try:
|
||||||
timeout = ClientTimeout(total=15)
|
timeout = ClientTimeout(total=15)
|
||||||
r = await session.get(
|
url = LATEST_ASK_API.format(
|
||||||
LATEST_ASK_API.format(
|
|
||||||
hardware=self.config.hardware,
|
hardware=self.config.hardware,
|
||||||
timestamp=str(int(time.time() * 1000)),
|
timestamp=str(int(time.time() * 1000)),
|
||||||
),
|
|
||||||
timeout=timeout,
|
|
||||||
)
|
)
|
||||||
|
self.log.debug(f"url:{url}")
|
||||||
|
r = await session.get(url, timeout=timeout)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning(
|
self.log.warning(
|
||||||
"Execption when get latest ask from xiaoai: %s", str(e)
|
"Execption when get latest ask from xiaoai: %s", str(e)
|
||||||
@@ -223,6 +223,7 @@ class XiaoMusic:
|
|||||||
return self._get_last_query(data)
|
return self._get_last_query(data)
|
||||||
|
|
||||||
def _get_last_query(self, data):
|
def _get_last_query(self, data):
|
||||||
|
self.log.debug(f"_get_last_query:{data}")
|
||||||
if d := data.get("data"):
|
if d := data.get("data"):
|
||||||
records = json.loads(d).get("records")
|
records = json.loads(d).get("records")
|
||||||
if not records:
|
if not records:
|
||||||
@@ -347,6 +348,7 @@ class XiaoMusic:
|
|||||||
self._all_music = {}
|
self._all_music = {}
|
||||||
all_music_by_dir = {}
|
all_music_by_dir = {}
|
||||||
for root, dirs, filenames in os.walk(self.music_path):
|
for root, dirs, filenames in os.walk(self.music_path):
|
||||||
|
dirs[:] = [d for d in dirs if d not in self.exclude_dirs]
|
||||||
self.log.debug("root:%s dirs:%s music_path:%s", root, dirs, self.music_path)
|
self.log.debug("root:%s dirs:%s music_path:%s", root, dirs, self.music_path)
|
||||||
dir_name = os.path.basename(root)
|
dir_name = os.path.basename(root)
|
||||||
if self.music_path == root:
|
if self.music_path == root:
|
||||||
@@ -375,7 +377,7 @@ class XiaoMusic:
|
|||||||
pass
|
pass
|
||||||
self._play_list = list(self._all_music.keys())
|
self._play_list = list(self._all_music.keys())
|
||||||
self._cur_play_list = "全部"
|
self._cur_play_list = "全部"
|
||||||
random.shuffle(self._play_list)
|
self._gen_play_list()
|
||||||
self.log.debug(self._all_music)
|
self.log.debug(self._all_music)
|
||||||
|
|
||||||
self._music_list = {}
|
self._music_list = {}
|
||||||
@@ -385,6 +387,14 @@ class XiaoMusic:
|
|||||||
self.log.debug("dir_name:%s, list:%s", dir_name, self._music_list[dir_name])
|
self.log.debug("dir_name:%s, list:%s", dir_name, self._music_list[dir_name])
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
# 歌曲排序或者打乱顺序
|
||||||
|
def _gen_play_list(self):
|
||||||
|
if self.play_type == PLAY_TYPE_RND:
|
||||||
|
random.shuffle(self._play_list)
|
||||||
|
else:
|
||||||
|
self._play_list.sort(key=custom_sort_key)
|
||||||
|
self.log.debug("play_list:%s", self._play_list)
|
||||||
|
|
||||||
# 把下载的音乐加入播放列表
|
# 把下载的音乐加入播放列表
|
||||||
def add_download_music(self, name):
|
def add_download_music(self, name):
|
||||||
self._all_music[name] = os.path.join(self.music_path, f"{name}.mp3")
|
self._all_music[name] = os.path.join(self.music_path, f"{name}.mp3")
|
||||||
@@ -523,17 +533,35 @@ class XiaoMusic:
|
|||||||
return ("stop", {})
|
return ("stop", {})
|
||||||
return (None, None)
|
return (None, None)
|
||||||
|
|
||||||
|
# 判断是否播放一下私募歌曲
|
||||||
|
def check_play_next(self):
|
||||||
|
# 当前没我在播放的歌曲
|
||||||
|
if self.cur_music == "":
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
filename = self.get_filename(self.cur_music)
|
||||||
|
# 当前播放的歌曲不存在了
|
||||||
|
if len(filename) <= 0:
|
||||||
|
return True
|
||||||
|
pass
|
||||||
|
return False
|
||||||
|
|
||||||
# 播放歌曲
|
# 播放歌曲
|
||||||
async def play(self, **kwargs):
|
async def play(self, **kwargs):
|
||||||
self._playing = True
|
self._playing = True
|
||||||
parts = kwargs["arg1"].split("|")
|
parts = kwargs["arg1"].split("|")
|
||||||
search_key = parts[0]
|
search_key = parts[0]
|
||||||
name = parts[1] if len(parts) > 1 else search_key
|
name = parts[1] if len(parts) > 1 else search_key
|
||||||
if search_key == "" and name == "":
|
|
||||||
await self.play_next()
|
|
||||||
return
|
|
||||||
if name == "":
|
if name == "":
|
||||||
name = search_key
|
name = search_key
|
||||||
|
|
||||||
|
if search_key == "" and name == "":
|
||||||
|
if self.check_play_next():
|
||||||
|
await self.play_next()
|
||||||
|
return
|
||||||
|
else:
|
||||||
|
name = self.cur_music
|
||||||
|
|
||||||
self.log.debug("play. search_key:%s name:%s", search_key, name)
|
self.log.debug("play. search_key:%s name:%s", search_key, name)
|
||||||
filename = self.get_filename(name)
|
filename = self.get_filename(name)
|
||||||
|
|
||||||
@@ -559,7 +587,11 @@ class XiaoMusic:
|
|||||||
self.log.info("下一首")
|
self.log.info("下一首")
|
||||||
name = self.cur_music
|
name = self.cur_music
|
||||||
self.log.debug("play_next. name:%s, cur_music:%s", name, self.cur_music)
|
self.log.debug("play_next. name:%s, cur_music:%s", name, self.cur_music)
|
||||||
if self.play_type == PLAY_TYPE_ALL or name == "":
|
if (
|
||||||
|
self.play_type == PLAY_TYPE_ALL
|
||||||
|
or self.play_type == PLAY_TYPE_RND
|
||||||
|
or name == ""
|
||||||
|
):
|
||||||
name = self.get_next_music()
|
name = self.get_next_music()
|
||||||
if name == "":
|
if name == "":
|
||||||
await self.do_tts("本地没有歌曲")
|
await self.do_tts("本地没有歌曲")
|
||||||
@@ -574,12 +606,13 @@ class XiaoMusic:
|
|||||||
# 全部循环
|
# 全部循环
|
||||||
async def set_play_type_all(self, **kwargs):
|
async def set_play_type_all(self, **kwargs):
|
||||||
self.play_type = PLAY_TYPE_ALL
|
self.play_type = PLAY_TYPE_ALL
|
||||||
|
self._gen_play_list()
|
||||||
await self.do_tts("已经设置为全部循环")
|
await self.do_tts("已经设置为全部循环")
|
||||||
|
|
||||||
# 随机播放
|
# 随机播放
|
||||||
async def random_play(self, **kwargs):
|
async def random_play(self, **kwargs):
|
||||||
self.play_type = PLAY_TYPE_ALL
|
self.play_type = PLAY_TYPE_RND
|
||||||
random.shuffle(self._play_list)
|
self._gen_play_list()
|
||||||
await self.do_tts("已经设置为随机播放")
|
await self.do_tts("已经设置为随机播放")
|
||||||
|
|
||||||
# 刷新列表
|
# 刷新列表
|
||||||
@@ -610,7 +643,7 @@ class XiaoMusic:
|
|||||||
return
|
return
|
||||||
self._play_list = self._music_list[list_name]
|
self._play_list = self._music_list[list_name]
|
||||||
self._cur_play_list = list_name
|
self._cur_play_list = list_name
|
||||||
random.shuffle(self._play_list)
|
self._gen_play_list()
|
||||||
self.log.info(f"开始播放列表{list_name}")
|
self.log.info(f"开始播放列表{list_name}")
|
||||||
|
|
||||||
music_name = ""
|
music_name = ""
|
||||||
@@ -625,7 +658,6 @@ class XiaoMusic:
|
|||||||
if self._next_timer:
|
if self._next_timer:
|
||||||
self._next_timer.cancel()
|
self._next_timer.cancel()
|
||||||
self.log.info("定时器已取消")
|
self.log.info("定时器已取消")
|
||||||
self.cur_music = ""
|
|
||||||
await self.force_stop_xiaoai()
|
await self.force_stop_xiaoai()
|
||||||
|
|
||||||
async def stop_after_minute(self, **kwargs):
|
async def stop_after_minute(self, **kwargs):
|
||||||
|
|||||||
Reference in New Issue
Block a user