mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-06 14:52:50 +08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
836fde01b7 | ||
|
|
050ded6b2e | ||
|
|
b9e1abff6b | ||
|
|
f962fcaa99 | ||
|
|
eb35da595f | ||
|
|
26a8b2412f | ||
|
|
601bff4404 | ||
|
|
1fadc9a479 | ||
|
|
69e53569ca | ||
|
|
49a43fb997 | ||
|
|
5145ae399d | ||
|
|
612eb636be | ||
|
|
657af667ef | ||
|
|
9541071c3a | ||
|
|
dfc78b6af5 | ||
|
|
bea7b2d4eb | ||
|
|
ddb3e9e03b | ||
|
|
812965f054 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -163,3 +163,4 @@ cython_debug/
|
|||||||
|
|
||||||
ffmpeg
|
ffmpeg
|
||||||
music
|
music
|
||||||
|
test.sh
|
||||||
|
|||||||
@@ -140,7 +140,8 @@ services:
|
|||||||
- [xiaogpt](https://github.com/yihong0618/xiaogpt)
|
- [xiaogpt](https://github.com/yihong0618/xiaogpt)
|
||||||
- [MiService](https://github.com/yihong0618/MiService)
|
- [MiService](https://github.com/yihong0618/MiService)
|
||||||
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
|
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
|
||||||
|
- [NAS部署教程](https://post.m.smzdm.com/p/avpe7n99/)
|
||||||
|
- [群晖部署教程](https://post.m.smzdm.com/p/a7px7dol/)
|
||||||
|
|
||||||
## Star History
|
## Star History
|
||||||
|
|
||||||
|
|||||||
37
newversion.sh
Normal file → Executable file
37
newversion.sh
Normal file → Executable file
@@ -1,7 +1,34 @@
|
|||||||
version="$1"
|
#!/bin/bash
|
||||||
sed -i "s/version.*/version = \"$version\"/" ./pyproject.toml
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
version_file=./pyproject.toml
|
||||||
|
# 获取当前版本号
|
||||||
|
current_version=$(grep -oE "version = \"[0-9]+\.[0-9]+\.[0-9]+\"" $version_file | cut -d'"' -f2)
|
||||||
|
echo "当前版本号: "$current_version
|
||||||
|
|
||||||
|
# 将版本号分割成三部分
|
||||||
|
major=$(echo $current_version | cut -d'.' -f1)
|
||||||
|
minor=$(echo $current_version | cut -d'.' -f2)
|
||||||
|
patch=$(echo $current_version | cut -d'.' -f3)
|
||||||
|
|
||||||
|
echo "major: $major"
|
||||||
|
echo "minor: $minor"
|
||||||
|
echo "patch: $patch"
|
||||||
|
|
||||||
|
# 将补丁号加1
|
||||||
|
patch=$((patch + 1))
|
||||||
|
|
||||||
|
# 生成新版本号
|
||||||
|
new_version="$major.$minor.$patch"
|
||||||
|
|
||||||
|
# 将新版本号写入文件
|
||||||
|
sed -i "s/version.*/version = \"$new_version\"/g" $version_file
|
||||||
|
|
||||||
|
echo "新版本号:$new_version"
|
||||||
|
|
||||||
git diff
|
git diff
|
||||||
git add ./pyproject.toml
|
git add $version_file
|
||||||
git commit -m "new version v$version"
|
git commit -m "new version v$new_version"
|
||||||
git tag v$version
|
git tag v$new_version
|
||||||
git push -u origin main --tags
|
git push -u origin main --tags
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "xiaomusic"
|
name = "xiaomusic"
|
||||||
version = "0.1.16"
|
version = "0.1.23"
|
||||||
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"},
|
||||||
|
|||||||
@@ -22,12 +22,20 @@ def allcmds():
|
|||||||
return KEY_WORD_DICT
|
return KEY_WORD_DICT
|
||||||
|
|
||||||
|
|
||||||
@app.route("/getvolume")
|
@app.route("/getvolume", methods=["GET"])
|
||||||
def getvolume():
|
def getvolume():
|
||||||
return {
|
return {
|
||||||
"volume": xiaomusic.get_volume(),
|
"volume": xiaomusic.get_volume(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@app.route("/searchmusic", methods=["GET"])
|
||||||
|
def searchmusic():
|
||||||
|
name = request.args.get('name')
|
||||||
|
return xiaomusic.searchmusic(name)
|
||||||
|
|
||||||
|
@app.route("/playingmusic", methods=["GET"])
|
||||||
|
def playingmusic():
|
||||||
|
return xiaomusic.playingmusic()
|
||||||
|
|
||||||
@app.route("/", methods=["GET"])
|
@app.route("/", methods=["GET"])
|
||||||
def redirect_to_index():
|
def redirect_to_index():
|
||||||
|
|||||||
@@ -39,8 +39,9 @@ $(function(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
$("#play").on("click", () => {
|
$("#play").on("click", () => {
|
||||||
name = $("#music-name").val();
|
var search_key = $("#music-name").val();
|
||||||
let cmd = "播放歌曲"+name;
|
var filename=$("#music-filename").val();
|
||||||
|
let cmd = "播放歌曲"+search_key+"|"+filename;
|
||||||
sendcmd(cmd);
|
sendcmd(cmd);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -63,4 +64,39 @@ $(function(){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 监听输入框的输入事件
|
||||||
|
$("#music-name").on('input', function() {
|
||||||
|
var inputValue = $(this).val();
|
||||||
|
// 发送Ajax请求
|
||||||
|
$.ajax({
|
||||||
|
url: "searchmusic", // 服务器端处理脚本
|
||||||
|
type: "GET",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
name: inputValue
|
||||||
|
},
|
||||||
|
success: function(data) {
|
||||||
|
// 清空datalist
|
||||||
|
$("#autocomplete-list").empty();
|
||||||
|
// 添加新的option元素
|
||||||
|
$.each(data, function(i, item) {
|
||||||
|
$('<option>').val(item).appendTo("#autocomplete-list");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function get_playing_music() {
|
||||||
|
$.get("/playingmusic", function(data, status) {
|
||||||
|
console.log(data);
|
||||||
|
$("#playering-music").text(data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 每3秒获取下正在播放的音乐
|
||||||
|
get_playing_music();
|
||||||
|
setInterval(() => {
|
||||||
|
get_playing_music();
|
||||||
|
}, 3000);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -25,9 +25,37 @@
|
|||||||
}
|
}
|
||||||
input {
|
input {
|
||||||
margin: 10px;
|
margin: 10px;
|
||||||
width: 200px;
|
width: 300px;
|
||||||
height: 40px;
|
height: 40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.container{
|
||||||
|
width: 280px;
|
||||||
|
overflow: hidden;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
@keyframes text-scroll {
|
||||||
|
0% {
|
||||||
|
left: 100%;
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
left: 50%;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
left: 0%;
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
left: -50%;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
left: -100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.text {
|
||||||
|
font-weight: bold;
|
||||||
|
position: relative;
|
||||||
|
animation: text-scroll 10s linear infinite;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -44,8 +72,13 @@
|
|||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
<div>
|
<div>
|
||||||
<input id="music-name" type="text" placeholder="请输入歌曲名称"></input>
|
<datalist id="autocomplete-list"></datalist>
|
||||||
<button id="play">播放</button>
|
<input id="music-name" type="text" placeholder="请输入搜索关键词(如:MV高清版 周杰伦 七里香)" list="autocomplete-list"></input>
|
||||||
|
<input id="music-filename" type="text" placeholder="请输入保存为的文件名称(如:周杰伦七里香)"></input>
|
||||||
|
</div>
|
||||||
|
<button id="play">播放</button>
|
||||||
|
<div class="container">
|
||||||
|
<div id="playering-music" class="text"></div>
|
||||||
</div>
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import socket
|
|||||||
from http.cookies import SimpleCookie
|
from http.cookies import SimpleCookie
|
||||||
from typing import AsyncIterator
|
from typing import AsyncIterator
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
import difflib
|
||||||
|
|
||||||
from requests.utils import cookiejar_from_dict
|
from requests.utils import cookiejar_from_dict
|
||||||
|
|
||||||
@@ -61,3 +62,6 @@ def validate_proxy(proxy_str: str) -> bool:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
# 模糊搜索
|
||||||
|
def fuzzyfinder(user_input, collection):
|
||||||
|
return difflib.get_close_matches(user_input, collection, 10, cutoff=0.1)
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ from xiaomusic.config import (
|
|||||||
from xiaomusic.utils import (
|
from xiaomusic.utils import (
|
||||||
calculate_tts_elapse,
|
calculate_tts_elapse,
|
||||||
parse_cookie_string,
|
parse_cookie_string,
|
||||||
|
fuzzyfinder,
|
||||||
)
|
)
|
||||||
|
|
||||||
EOF = object()
|
EOF = object()
|
||||||
@@ -299,7 +300,7 @@ class XiaoMusic:
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
# 下载歌曲
|
# 下载歌曲
|
||||||
async def download(self, name):
|
async def download(self, search_key, name):
|
||||||
if self.download_proc:
|
if self.download_proc:
|
||||||
try:
|
try:
|
||||||
self.download_proc.kill()
|
self.download_proc.kill()
|
||||||
@@ -308,7 +309,7 @@ class XiaoMusic:
|
|||||||
|
|
||||||
sbp_args = (
|
sbp_args = (
|
||||||
"yt-dlp",
|
"yt-dlp",
|
||||||
f"{self.search_prefix}{name}",
|
f"{self.search_prefix}{search_key}",
|
||||||
"-x",
|
"-x",
|
||||||
"--audio-format",
|
"--audio-format",
|
||||||
"mp3",
|
"mp3",
|
||||||
@@ -325,11 +326,12 @@ class XiaoMusic:
|
|||||||
sbp_args += ("--proxy", f"{self.proxy}")
|
sbp_args += ("--proxy", f"{self.proxy}")
|
||||||
|
|
||||||
self.download_proc = await asyncio.create_subprocess_exec(*sbp_args)
|
self.download_proc = await asyncio.create_subprocess_exec(*sbp_args)
|
||||||
await self.do_tts(f"正在下载歌曲{name}")
|
await self.do_tts(f"正在下载歌曲{search_key}")
|
||||||
|
|
||||||
# 本地是否存在歌曲
|
# 本地是否存在歌曲
|
||||||
def get_filename(self, name):
|
def get_filename(self, name):
|
||||||
if name not in self._all_music:
|
if name not in self._all_music:
|
||||||
|
self.log.debug("get_filename not in. name:%s", name)
|
||||||
return ""
|
return ""
|
||||||
filename = self._all_music[name]
|
filename = self._all_music[name]
|
||||||
self.log.debug("try get_filename. filename:%s", filename)
|
self.log.debug("try get_filename. filename:%s", filename)
|
||||||
@@ -484,15 +486,20 @@ class XiaoMusic:
|
|||||||
|
|
||||||
# 播放歌曲
|
# 播放歌曲
|
||||||
async def play(self, **kwargs):
|
async def play(self, **kwargs):
|
||||||
name = kwargs["arg1"]
|
parts = kwargs["arg1"].split("|")
|
||||||
if name == "":
|
search_key = parts[0]
|
||||||
|
name = parts[1] if len(parts) > 1 else search_key
|
||||||
|
if search_key == "" and name == "":
|
||||||
await self.play_next()
|
await self.play_next()
|
||||||
return
|
return
|
||||||
|
if name == "":
|
||||||
|
name = search_key
|
||||||
|
self.log.debug("play. search_key:%s name:%s", search_key, name)
|
||||||
filename = self.get_filename(name)
|
filename = self.get_filename(name)
|
||||||
|
|
||||||
if len(filename) <= 0:
|
if len(filename) <= 0:
|
||||||
await self.download(name)
|
await self.download(search_key, name)
|
||||||
self.log.info("正在下载中 %s", name)
|
self.log.info("正在下载中 %s", search_key + ":" + name)
|
||||||
await self.download_proc.wait()
|
await self.download_proc.wait()
|
||||||
# 把文件插入到播放列表里
|
# 把文件插入到播放列表里
|
||||||
self.add_download_music(name)
|
self.add_download_music(name)
|
||||||
@@ -567,3 +574,14 @@ class XiaoMusic:
|
|||||||
|
|
||||||
def get_volume(self):
|
def get_volume(self):
|
||||||
return self._volume
|
return self._volume
|
||||||
|
|
||||||
|
# 搜索音乐
|
||||||
|
def searchmusic(self, name):
|
||||||
|
search_list = fuzzyfinder(name, self._play_list)
|
||||||
|
self.log.debug("searchmusic. name:%s search_list:%s", name, search_list)
|
||||||
|
return search_list
|
||||||
|
|
||||||
|
# 正在播放中的音乐
|
||||||
|
def playingmusic(self):
|
||||||
|
self.log.debug("playingmusic. cur_music:%s", self.cur_music)
|
||||||
|
return self.cur_music
|
||||||
|
|||||||
Reference in New Issue
Block a user