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

Compare commits

..

11 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
14 changed files with 117 additions and 41 deletions

View File

@@ -1,3 +1,22 @@
## 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

View File

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

39
pdm.lock generated
View File

@@ -25,14 +25,27 @@ files = [
{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",
@@ -41,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]]
@@ -1094,7 +1107,7 @@ files = [
[[package]]
name = "uvicorn"
version = "0.30.3"
version = "0.30.4"
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
groups = ["default"]
@@ -1105,13 +1118,13 @@ dependencies = [
"typing-extensions>=4.0; python_version < \"3.11\"",
]
files = [
{file = "uvicorn-0.30.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
{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.3"
version = "0.30.4"
extras = ["standard"]
requires_python = ">=3.8"
summary = "The lightning-fast ASGI server."
@@ -1122,14 +1135,14 @@ dependencies = [
"httptools>=0.5.0",
"python-dotenv>=0.13",
"pyyaml>=5.1",
"uvicorn==0.30.3",
"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.3-py3-none-any.whl", hash = "sha256:94a3608da0e530cea8f69683aa4126364ac18e3826b6630d1a65f4638aade503"},
{file = "uvicorn-0.30.3.tar.gz", hash = "sha256:0d114d0831ff1adbf231d358cbf42f17333413042552a624ea6a9b4c33dcfd81"},
{file = "uvicorn-0.30.4-py3-none-any.whl", hash = "sha256:06b00e3087e58c6865c284143c0c42f810b32ff4f265ab19d08c566f74a08728"},
{file = "uvicorn-0.30.4.tar.gz", hash = "sha256:00db9a9e3711a5fa59866e2b02fac69d8dc70ce0814aaec9a66d1d9e5c832a30"},
]
[[package]]
@@ -1345,7 +1358,7 @@ files = [
[[package]]
name = "yt-dlp"
version = "2024.7.25"
version = "2024.8.1"
requires_python = ">=3.8"
summary = "A feature-rich command-line audio/video downloader"
groups = ["default"]
@@ -1361,6 +1374,6 @@ dependencies = [
"websockets>=12.0",
]
files = [
{file = "yt_dlp-2024.7.25-py3-none-any.whl", hash = "sha256:f44b5f33776b4f718900c670fe6e4698fb6fcd426455cd837cf25a1d6d4d9560"},
{file = "yt_dlp-2024.7.25.tar.gz", hash = "sha256:7587aa25e236cf7b14bdb9378bbffff51202d901b04202be0cf62cbb56d3b52c"},
{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.22"
version = "0.3.25"
description = "Play Music with xiaomi AI speaker"
authors = [
{name = "涵曦", email = "im.hanxi@gmail.com"},

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 +1 @@
__version__ = "0.3.22"
__version__ = "0.3.25"

View File

@@ -61,7 +61,9 @@ 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.join(absolute_path, file_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")

View File

@@ -315,7 +315,9 @@ 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.join(absolute_path, file_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")

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=1722471797">
<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=1722471797"></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=1722471797"></script>
<script src="/static/app.js?version=1722471797"></script>
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1722471797">
<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=1722471797">
<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=1722471797"></script>
<script src="/static/setting.js?version=1722471797"></script>
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1722471797">
<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>
@@ -133,6 +133,12 @@ var vConsole = new window.VConsole();
<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>

View File

@@ -141,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):
# 忽略排除的目录
@@ -247,10 +245,9 @@ async def get_local_music_duration(filename):
m = await loop.run_in_executor(None, mutagen.mp3.MP3, filename)
else:
m = await loop.run_in_executor(None, mutagen.File, filename)
if m and m.info:
duration = m.info.length
duration = m.info.length
except Exception as e:
logging.error(f"Error getting local music duration: {e}")
logging.error(f"Error getting local music {filename} duration: {e}")
return duration