mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-07 15:02:55 +08:00
Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4efa0d879 | ||
|
|
2ebc0f11d2 | ||
|
|
180f28800e | ||
|
|
7f5692d6cd | ||
|
|
8d7b5337eb | ||
|
|
dcbf4330be | ||
|
|
2e53f20d80 | ||
|
|
2914ddcc36 | ||
|
|
442756e3cc | ||
|
|
b55a2a67c9 | ||
|
|
09545c7015 | ||
|
|
1f82efa2a1 | ||
|
|
e509052242 | ||
|
|
046cdade5a | ||
|
|
7f8e639b86 | ||
|
|
bfbd36f7f9 | ||
|
|
c5d623547c | ||
|
|
31c61675bf | ||
|
|
9900bd9ee9 | ||
|
|
8459494c61 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -25,7 +25,7 @@ share/python-wheels/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
*_bak/
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
|
||||
38
CHANGELOG.md
38
CHANGELOG.md
@@ -1,3 +1,41 @@
|
||||
## v0.3.36 (2024-09-19)
|
||||
|
||||
### Feat
|
||||
|
||||
- Pure 主题更新 (#178)
|
||||
- 支持配置获取对话记录间隔时间 #169
|
||||
- 允许在后台设置监听端口
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复开启继续播放时歌曲播放不完整问题 (#177)
|
||||
|
||||
## v0.3.35 (2024-09-18)
|
||||
|
||||
### Feat
|
||||
|
||||
- 允许跨域访问 #172
|
||||
|
||||
### Fix
|
||||
|
||||
- 修复 Pure 主题白屏无法打开的问题 (#176)
|
||||
|
||||
## v0.3.34 (2024-09-18)
|
||||
|
||||
### Feat
|
||||
|
||||
- 新增 pure 主题 vue + elementUI (#172)
|
||||
|
||||
### Fix
|
||||
|
||||
- 主页适配移动端
|
||||
- 修复网页播放点击后没有关闭旧声音的问题 #166
|
||||
- 修复单曲循环的情况下歌曲不在当前播放列表时失效的情况
|
||||
|
||||
### Refactor
|
||||
|
||||
- 优化代码:输入框处理抖动问题,网页播放修改实现方式 see #166
|
||||
|
||||
## v0.3.33 (2024-09-15)
|
||||
|
||||
### Feat
|
||||
|
||||
@@ -210,8 +210,6 @@ docker build -t xiaomusic .
|
||||
|
||||
采用新的设置页面之后,没有必须在启动前配置的环境变量了,除非是改默认的 8090 端口才需要配置环境变量。
|
||||
|
||||
后台的
|
||||
|
||||
## 网络歌单功能
|
||||
|
||||
可以配置一个 json 格式的歌单,支持电台和歌曲,也可以直接用别人分享的链接,同时配备了 m3u 文件格式转换工具,可以很方便的把 m3u 电台文件转换成网络歌单格式的 json 文件,具体用法见 <https://github.com/hanxi/xiaomusic/issues/78>
|
||||
@@ -261,9 +259,11 @@ docker build -t xiaomusic .
|
||||
- [PDM](https://pdm.fming.dev/latest/)
|
||||
- [xiaogpt](https://github.com/yihong0618/xiaogpt)
|
||||
- [MiService](https://github.com/yihong0618/MiService)
|
||||
- [实现原理](https://github.com/yihong0618/gitblog/issues/258)
|
||||
- [yt-dlp](https://github.com/yt-dlp/yt-dlp)
|
||||
- [awesome-xiaoai](https://github.com/zzz6519003/awesome-xiaoai)
|
||||
- [微信小程序: XIAO晓音](https://github.com/F-loat/xiaoplayer)
|
||||
- [pure 主题 xiaomusicUI](https://github.com/52fisher/xiaomusicUI)
|
||||
- 所有帮忙调试和测试的朋友
|
||||
- 所有反馈问题和建议的朋友
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.3.33"
|
||||
version = "0.3.36"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
|
||||
@@ -16,13 +16,12 @@ def get_html_files(directory):
|
||||
|
||||
def update_html_version(html_files, version):
|
||||
"""
|
||||
更新HTML文件中所有以 /static/ 开头的CSS和JS文件引用的版本号。
|
||||
更新HTML文件中所有以 ./ 开头的CSS和JS文件引用的版本号。
|
||||
|
||||
:param html_files: 需要更新的HTML文件路径的列表。
|
||||
:param version: 新的版本号字符串。
|
||||
"""
|
||||
pattern = re.compile(r'(/static/.*(css|js))\?version=[^"]*"')
|
||||
# pattern = re.compile(r'(/static/.*html)\?version=[^"]*"')
|
||||
pattern = re.compile(r'(\./.*(css|js))\?version=[^"]*"')
|
||||
|
||||
for html_file in html_files:
|
||||
if not html_file.exists():
|
||||
@@ -48,7 +47,7 @@ if __name__ == "__main__":
|
||||
t = str(int(time.time()))
|
||||
|
||||
# 指定目录
|
||||
html_directory = "xiaomusic/static" # 修改为实际的HTML文件目录路径
|
||||
html_directory = "xiaomusic/static/default" # 修改为实际的HTML文件目录路径
|
||||
|
||||
# 获取HTML文件列表
|
||||
html_files_to_update = get_html_files(html_directory)
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.3.33"
|
||||
__version__ = "0.3.36"
|
||||
|
||||
@@ -148,6 +148,7 @@ class Config:
|
||||
continue_play: bool = (
|
||||
os.getenv("XIAOMUSIC_CONTINUE_PLAY", "false").lower() == "true"
|
||||
)
|
||||
pull_ask_sec: int = int(os.getenv("XIAOMUSIC_PULL_ASK_SEC", "1"))
|
||||
|
||||
def append_keyword(self, keys, action):
|
||||
for key in keys.split(","):
|
||||
|
||||
@@ -13,6 +13,7 @@ from typing import Annotated
|
||||
|
||||
import aiofiles
|
||||
from fastapi import Depends, FastAPI, HTTPException, Request, status
|
||||
from fastapi.middleware.cors import CORSMiddleware
|
||||
from fastapi.responses import StreamingResponse
|
||||
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
@@ -75,6 +76,14 @@ app = FastAPI(
|
||||
version=__version__,
|
||||
)
|
||||
|
||||
app.add_middleware(
|
||||
CORSMiddleware,
|
||||
allow_origins=["*"], # 允许访问的源
|
||||
allow_credentials=False, # 支持 cookie
|
||||
allow_methods=["*"], # 允许使用的请求方法
|
||||
allow_headers=["*"], # 允许携带的 Headers
|
||||
)
|
||||
|
||||
|
||||
def reset_http_server():
|
||||
log.info(f"disable_httpauth:{config.disable_httpauth}")
|
||||
|
||||
@@ -147,8 +147,7 @@ $(function(){
|
||||
$.get(`/musicinfo?name=${music_name}`, function(data, status) {
|
||||
console.log(data);
|
||||
if (data.ret == "OK") {
|
||||
const music = new Audio(data.url);
|
||||
music.play();
|
||||
$('audio').attr('src',data.url);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -244,8 +243,15 @@ $(function(){
|
||||
});
|
||||
}
|
||||
|
||||
// 监听输入框的输入事件
|
||||
$("#music-name").on('input', function() {
|
||||
// 监听输入框的输入事件
|
||||
function debounce(func, delay) {
|
||||
let timeout;
|
||||
return function(...args) {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => func.apply(this, args), delay);
|
||||
};
|
||||
}
|
||||
$("#music-name").on('input', debounce(function() {
|
||||
var inputValue = $(this).val();
|
||||
// 发送Ajax请求
|
||||
$.ajax({
|
||||
@@ -264,7 +270,7 @@ $(function(){
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
},300));
|
||||
|
||||
function get_playing_music() {
|
||||
$.get(`/playingmusic?did=${did}`, function(data, status) {
|
||||
@@ -294,7 +300,4 @@ $(function(){
|
||||
var remainingSeconds =Math.floor(seconds % 60);
|
||||
return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
});
|
||||
@@ -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=1726415744">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1726700926">
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script src="/static/jquery-3.7.1.min.js?version=1726415744"></script>
|
||||
<script src="./jquery-3.7.1.min.js?version=1726700926"></script>
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
92
xiaomusic/static/default/index.html
Normal file
92
xiaomusic/static/default/index.html
Normal file
@@ -0,0 +1,92 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="./jquery-3.7.1.min.js?version=1726700926"></script>
|
||||
<script src="./app.js?version=1726700926"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1726700926">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments)};
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-Z09NC1K7ZW');
|
||||
</script>
|
||||
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
var vConsole = new window.VConsole();
|
||||
</script>
|
||||
-->
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱操控面板
|
||||
(<a id="version" href="https://github.com/hanxi/xiaomusic/blob/main/CHANGELOG.md">
|
||||
版本未知
|
||||
</a>)
|
||||
</h2>
|
||||
<hr>
|
||||
|
||||
<div class="rows">
|
||||
<select id="did">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div id="cmds">
|
||||
<a class="button" href="./setting.html">设置</a>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div style="margin: 20px;">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#8e43e7" style="height: 48px; width: 48px;"><path d="M550.826667 154.666667a47.786667 47.786667 0 0 0-19.84 4.48L298.666667 298.666667H186.453333A80 80 0 0 0 106.666667 378.453333v267.093334A80 80 0 0 0 186.453333 725.333333H298.666667l232.32 139.52a47.786667 47.786667 0 0 0 19.84 4.48A46.506667 46.506667 0 0 0 597.333333 822.826667V201.173333a46.506667 46.506667 0 0 0-46.506666-46.506666zM554.666667 822.826667c0 3.413333-3.84 3.84-3.84 3.84L320 688.853333l-9.6-6.186666H186.453333A37.12 37.12 0 0 1 149.333333 645.546667V378.453333A37.12 37.12 0 0 1 186.453333 341.333333h123.946667l10.24-6.186666 229.546667-137.6s3.84 0 3.84 3.84zM667.52 346.026667a21.333333 21.333333 0 0 0 0 30.293333 192 192 0 0 1 0 271.36 21.333333 21.333333 0 0 0 0 30.293333 21.333333 21.333333 0 0 0 30.293333 0 234.666667 234.666667 0 0 0 0-331.946666 21.333333 21.333333 0 0 0-30.293333 0z"></path><path d="M804.48 219.52a21.333333 21.333333 0 0 0-30.293333 30.293333 370.986667 370.986667 0 0 1 0 524.373334 21.333333 21.333333 0 0 0 0 30.293333 21.333333 21.333333 0 0 0 30.293333 0 414.08 414.08 0 0 0 0-584.96z"></path></svg>
|
||||
<input id="volume" type="range"></input>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<datalist id="autocomplete-list"></datalist>
|
||||
<input id="music-name" type="text" placeholder="请输入搜索关键词(如:MV高清版 周杰伦 七里香)" list="autocomplete-list"></input>
|
||||
<input id="music-filename" type="text" placeholder="请输入保存为的文件名称(如:周杰伦七里香)"></input>
|
||||
<div style="display: flex; align-items: center">
|
||||
<progress id="progress" value="0" max="100" style="width: 270px"></progress>
|
||||
<div id="play-time" style="margin-left: 10px">00:00/00:00</div>
|
||||
</div>
|
||||
<div>
|
||||
<button id="play">播放</button>
|
||||
<div id="playering-music" class="text"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<label for="music_list">播放列表:</label>
|
||||
<select id="music_list"></select>
|
||||
<label for="music_name">歌曲:</label>
|
||||
<select id="music_name"></select>
|
||||
<div>
|
||||
<button id="play_music_list">播放列表歌曲</button>
|
||||
<button id="del_music">删除选中歌曲</button>
|
||||
<button id="web_play">网页播放</button>
|
||||
</div>
|
||||
<div class="play_pannel">
|
||||
<audio autoplay controls src=""></audio>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<input id="music-url" type="text" value="https://lhttp.qtfm.cn/live/4915/64k.mp3"></input>
|
||||
<button id="playurl">播放链接</button>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
@@ -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=1726415744">
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1726700926">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 47 KiB |
@@ -3,9 +3,9 @@
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="/static/jquery-3.7.1.min.js?version=1726415744"></script>
|
||||
<script src="/static/setting.js?version=1726415744"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1726415744">
|
||||
<script src="./jquery-3.7.1.min.js?version=1726700926"></script>
|
||||
<script src="./setting.js?version=1726700926"></script>
|
||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1726700926">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
@@ -142,15 +142,21 @@ var vConsole = new window.VConsole();
|
||||
<option value="false" selected>false</option>
|
||||
</select>
|
||||
|
||||
<label for="continue_play">启用继续播放(可能导致兼容性问题及歌曲无法完整播放):</label>
|
||||
<label for="continue_play">启用继续播放(可能导致兼容性问题):</label>
|
||||
<select id="continue_play">
|
||||
<option value="true">true</option>
|
||||
<option value="false" selected>false</option>
|
||||
</select>
|
||||
|
||||
<label for="port">监听端口(修改后需要重启):</label>
|
||||
<input id="port" type="number" value="8090"></input>
|
||||
|
||||
<label for="public_port">外网访问端口(0表示跟监听端口一致):</label>
|
||||
<input id="public_port" type="number" value="0"></input>
|
||||
|
||||
<label for="pull_ask_sec">获取对话记录间隔(秒):</label>
|
||||
<input id="pull_ask_sec" type="number" value="1"></input>
|
||||
|
||||
<label for="delay_sec">下一首歌延迟播放秒数:</label>
|
||||
<input id="delay_sec" type="number" value="3"></input>
|
||||
|
||||
@@ -180,15 +186,15 @@ var vConsole = new window.VConsole();
|
||||
|
||||
<a class="button" href="/downloadlog" download="xiaomusic.txt">下载日志文件</a>
|
||||
<button onclick="location.href='/docs';">查看接口文档</button>
|
||||
<a class="button" href="/static/m3u.html" target="_blank">m3u文件转换</a>
|
||||
<a class="button" href="./m3u.html" target="_blank">m3u文件转换</a>
|
||||
<hr>
|
||||
|
||||
<a class="button" href="/static/debug.html" target="_blank">调试工具</a>
|
||||
<a class="button" href="./debug.html" target="_blank">调试工具</a>
|
||||
<a class="button" href="https://afdian.com/a/imhanxi" target="_blank">💰 爱发电</a>
|
||||
<a class="button" href="https://github.com/hanxi/xiaomusic" target="_blank">点个 Star ⭐</a>
|
||||
|
||||
<div class="rows">
|
||||
<img class="qrcode" src="/static/qrcode.png" alt="请涵曦喝奶茶🧋">
|
||||
<img class="qrcode" src="./qrcode.png" alt="请涵曦喝奶茶🧋">
|
||||
</div>
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
@@ -1,89 +1,61 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta name="viewport" content="width=device-width">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script src="/static/jquery-3.7.1.min.js?version=1726415744"></script>
|
||||
<script src="/static/app.js?version=1726415744"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/static/style.css?version=1726415744">
|
||||
<html lang="en">
|
||||
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments)};
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-Z09NC1K7ZW');
|
||||
</script>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>小爱音箱操控面板</title>
|
||||
|
||||
<!--
|
||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||
<script>
|
||||
var vConsole = new window.VConsole();
|
||||
</script>
|
||||
-->
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag(){dataLayer.push(arguments)};
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-Z09NC1K7ZW');
|
||||
</script>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<h2>小爱音箱操控面板
|
||||
(<a id="version" href="https://github.com/hanxi/xiaomusic/blob/main/CHANGELOG.md">
|
||||
版本未知
|
||||
</a>)
|
||||
</h2>
|
||||
<hr>
|
||||
</head>
|
||||
|
||||
<div class="rows">
|
||||
<select id="did">
|
||||
</select>
|
||||
<body>
|
||||
<div class="container_wrapper">
|
||||
<div class="logo">
|
||||
<img src="/static/xiaoai.png" alt="">
|
||||
</div>
|
||||
|
||||
<div id="cmds">
|
||||
<a class="button" href="/static/setting.html">设置</a>
|
||||
<div class="desc">
|
||||
<h1>谁家灯火夜通明</h1>
|
||||
<p class="call">小爱同学?</p>
|
||||
<p class="answer">哎,我在</p>
|
||||
</div>
|
||||
<hr>
|
||||
|
||||
<div style="margin: 20px;">
|
||||
<div style="display: flex; align-items: center;">
|
||||
<svg viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" fill="#8e43e7" style="height: 48px; width: 48px;"><path d="M550.826667 154.666667a47.786667 47.786667 0 0 0-19.84 4.48L298.666667 298.666667H186.453333A80 80 0 0 0 106.666667 378.453333v267.093334A80 80 0 0 0 186.453333 725.333333H298.666667l232.32 139.52a47.786667 47.786667 0 0 0 19.84 4.48A46.506667 46.506667 0 0 0 597.333333 822.826667V201.173333a46.506667 46.506667 0 0 0-46.506666-46.506666zM554.666667 822.826667c0 3.413333-3.84 3.84-3.84 3.84L320 688.853333l-9.6-6.186666H186.453333A37.12 37.12 0 0 1 149.333333 645.546667V378.453333A37.12 37.12 0 0 1 186.453333 341.333333h123.946667l10.24-6.186666 229.546667-137.6s3.84 0 3.84 3.84zM667.52 346.026667a21.333333 21.333333 0 0 0 0 30.293333 192 192 0 0 1 0 271.36 21.333333 21.333333 0 0 0 0 30.293333 21.333333 21.333333 0 0 0 30.293333 0 234.666667 234.666667 0 0 0 0-331.946666 21.333333 21.333333 0 0 0-30.293333 0z"></path><path d="M804.48 219.52a21.333333 21.333333 0 0 0-30.293333 30.293333 370.986667 370.986667 0 0 1 0 524.373334 21.333333 21.333333 0 0 0 0 30.293333 21.333333 21.333333 0 0 0 30.293333 0 414.08 414.08 0 0 0 0-584.96z"></path></svg>
|
||||
<input id="volume" type="range"></input>
|
||||
</div>
|
||||
</div>
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<datalist id="autocomplete-list"></datalist>
|
||||
<input id="music-name" type="text" placeholder="请输入搜索关键词(如:MV高清版 周杰伦 七里香)" list="autocomplete-list"></input>
|
||||
<input id="music-filename" type="text" placeholder="请输入保存为的文件名称(如:周杰伦七里香)"></input>
|
||||
<div style="display: flex; align-items: center">
|
||||
<progress id="progress" value="0" max="100" style="width: 270px"></progress>
|
||||
<div id="play-time" style="margin-left: 10px">00:00/00:00</div>
|
||||
</div>
|
||||
<div>
|
||||
<button id="play">播放</button>
|
||||
<div id="playering-music" class="text"></div>
|
||||
</div>
|
||||
<div class="options">
|
||||
<!-- 选择主题 /static/[theme] -->
|
||||
<a href="/static/default/index.html" class="href">默认主题</a>
|
||||
<a href="/static/pure/index.html" class="href">Pure主题</a>
|
||||
<a href="https://afdian.com/a/imhanxi" target="_blank">爱发电</a>
|
||||
<a href="https://github.com/hanxi/xiaomusic" target="_blank">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
<footer>
|
||||
power by <a href="https://github.com/hanxi/xiaomusic">XiaoMusic</a>
|
||||
</footer>
|
||||
<style>
|
||||
@font-face{ font-family: "得意黑 斜体"; font-weight: 400; src: url("//at.alicdn.com/wf/webfont/603VmyqiyGMz/gJk2ny0v51vn.woff2") format("woff2"), url("//at.alicdn.com/wf/webfont/603VmyqiyGMz/e2C1wSBHH86h.woff") format("woff"); font-display: swap;} @font-face{ font-family: "阿里妈妈数黑体 Bold"; font-weight: 700; src: url("//at.alicdn.com/wf/webfont/603VmyqiyGMz/4DWYdFK3dz5J.woff2") format("woff2"), url("//at.alicdn.com/wf/webfont/603VmyqiyGMz/V7EBEKlNSdxC.woff") format("woff"); font-display: swap;} body{ background-color: rgb(47, 44, 67); height: 100%; overflow: hidden;}
|
||||
.container_wrapper{display: flex; justify-content: space-around; align-items: center; flex-wrap: wrap; height: 90vh; cursor: default;}
|
||||
h1{ font-weight: bold; color: #a2a9af; max-width: 600px; font-family: '得意黑 斜体', 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 2.5em; border-bottom: 1px solid #a2a9af;}
|
||||
.container_wrapper .logo img{ width: 140px; height: auto; filter: drop-shadow(10px 10px 10px rgba(0, 0, 0, 0.5));}
|
||||
.desc{ text-align: center; color: #fff; margin: auto 30px; backdrop-filter: blur(5px);}
|
||||
.desc p{ font-size: 1.2em; margin: 0; padding: 0; font-family: '阿里妈妈数黑体 Bold'; font-weight: 800;}
|
||||
p.call{ letter-spacing: 0.4em; font-size: 2.2em; line-height: 1.5; font-style: normal;}
|
||||
p.answer{ letter-spacing: 0.23em; line-height: 1.5; font-style: normal; color: #a2a9af; margin-top: 10px;}
|
||||
.desc p::before, .desc p::after{ font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; font-size: 1.5em; color: #4c5870;}
|
||||
.desc p::before{ content: "“";} .desc p::after{ content: "”";}
|
||||
.options{ display: flex; flex-direction: column;}
|
||||
.options a{ color: #a2a9af; text-decoration: none; font-size: 1.1em; position: relative; display: inline; margin: 10px auto;}
|
||||
.options a::before{ content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 2px; background-color: #ebedec; transform-origin: bottom right; transform: scaleX(0); transition: transform 0.3s ease;}
|
||||
.options a:hover::before{ transform-origin: bottom left; transform: scaleX(1);} .options a:hover{ color:#ebedec;}
|
||||
footer{ display: flex; justify-content: center; color: #4c5870;} footer a{ color:inherit; text-decoration: none; margin: auto 10px;}
|
||||
</style>
|
||||
</body>
|
||||
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<label for="music_list">播放列表:</label>
|
||||
<select id="music_list"></select>
|
||||
<label for="music_name">歌曲:</label>
|
||||
<select id="music_name"></select>
|
||||
<div>
|
||||
<button id="play_music_list">播放列表歌曲</button>
|
||||
<button id="del_music">删除选中歌曲</button>
|
||||
<button id="web_play">网页播放</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="rows">
|
||||
<input id="music-url" type="text" value="https://lhttp.qtfm.cn/live/4915/64k.mp3"></input>
|
||||
<button id="playurl">播放链接</button>
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<p>Powered by <a href="https://github.com/hanxi/xiaomusic" target="_blank">xiaomusic</a></p>
|
||||
</footer>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
xiaomusic/static/pure/assets/guidance-BdU7g-Gp.png
Normal file
BIN
xiaomusic/static/pure/assets/guidance-BdU7g-Gp.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 224 KiB |
40
xiaomusic/static/pure/assets/index-C9BDvfvm.js
Normal file
40
xiaomusic/static/pure/assets/index-C9BDvfvm.js
Normal file
File diff suppressed because one or more lines are too long
1
xiaomusic/static/pure/assets/index-DUo8JY-R.css
Normal file
1
xiaomusic/static/pure/assets/index-DUo8JY-R.css
Normal file
File diff suppressed because one or more lines are too long
BIN
xiaomusic/static/pure/favicon.ico
Normal file
BIN
xiaomusic/static/pure/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.2 KiB |
26
xiaomusic/static/pure/index.html
Normal file
26
xiaomusic/static/pure/index.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<link rel="icon" href="/static/pure/favicon.ico">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>小爱音箱操控面板</title>
|
||||
<script type="module" crossorigin src="/static/pure/assets/index-C9BDvfvm.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/static/pure/assets/index-DUo8JY-R.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<!-- 作者的统计代码 -->
|
||||
<!-- Google tag (gtag.js) -->
|
||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||
<script>
|
||||
window.dataLayer = window.dataLayer || [];
|
||||
function gtag() { dataLayer.push(arguments) };
|
||||
gtag('js', new Date());
|
||||
gtag('config', 'G-Z09NC1K7ZW');
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
BIN
xiaomusic/static/xiaoai.png
Normal file
BIN
xiaomusic/static/xiaoai.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 528 KiB |
@@ -158,9 +158,9 @@ class XiaoMusic:
|
||||
async def poll_latest_ask(self):
|
||||
async with ClientSession() as session:
|
||||
while True:
|
||||
# self.log.debug(
|
||||
# f"Listening new message, timestamp: {self.last_timestamp}"
|
||||
# )
|
||||
self.log.debug(
|
||||
f"Listening new message, timestamp: {self.last_timestamp}"
|
||||
)
|
||||
session._cookie_jar = self.cookie_jar
|
||||
|
||||
# 拉取所有音箱的对话记录
|
||||
@@ -171,13 +171,17 @@ class XiaoMusic:
|
||||
await asyncio.gather(*tasks)
|
||||
|
||||
start = time.perf_counter()
|
||||
# self.log.debug(f"Polling_event, timestamp: {self.last_timestamp}")
|
||||
await self.polling_event.wait()
|
||||
if (d := time.perf_counter() - start) < 1:
|
||||
# sleep to avoid too many request
|
||||
# self.log.debug(f"Sleep {d}, timestamp: {self.last_timestamp}")
|
||||
await asyncio.sleep(1 - d)
|
||||
await self.analytics.send_daily_event()
|
||||
if self.config.pull_ask_sec <= 1:
|
||||
if (d := time.perf_counter() - start) < 1:
|
||||
await asyncio.sleep(1 - d)
|
||||
else:
|
||||
sleep_sec = 0
|
||||
while True:
|
||||
await asyncio.sleep(1)
|
||||
sleep_sec = sleep_sec + 1
|
||||
if sleep_sec >= self.config.pull_ask_sec:
|
||||
break
|
||||
|
||||
async def init_all_data(self, session):
|
||||
await self.login_miboy(session)
|
||||
@@ -520,8 +524,17 @@ class XiaoMusic:
|
||||
except Exception as e:
|
||||
self.log.exception(f"Execption {e}")
|
||||
|
||||
async def analytics_task_daily(self):
|
||||
while True:
|
||||
await self.analytics.send_daily_event()
|
||||
await asyncio.sleep(3600)
|
||||
|
||||
async def run_forever(self):
|
||||
await self.analytics.send_startup_event()
|
||||
analytics_task = asyncio.create_task(self.analytics_task_daily())
|
||||
assert (
|
||||
analytics_task is not None
|
||||
) # to keep the reference to task, do not remove this
|
||||
async with ClientSession() as session:
|
||||
self.session = session
|
||||
await self.init_all_data(session)
|
||||
@@ -536,6 +549,11 @@ class XiaoMusic:
|
||||
query = new_record.get("query", "").strip()
|
||||
did = new_record.get("did", "").strip()
|
||||
await self.do_check_cmd(did, query, False)
|
||||
answers = new_record.get("answers", [{}])
|
||||
if answers:
|
||||
answer = answers[0].get("tts", {}).get("text", "").strip()
|
||||
await self.reset_timer_when_answer(len(answer), did)
|
||||
self.log.debug(f"query:{query} did:{did} answer:{answer}")
|
||||
|
||||
# 匹配命令
|
||||
async def do_check_cmd(self, did="", query="", ctrl_panel=True, **kwargs):
|
||||
@@ -552,6 +570,10 @@ class XiaoMusic:
|
||||
except Exception as e:
|
||||
self.log.exception(f"Execption {e}")
|
||||
|
||||
# 重置计时器
|
||||
async def reset_timer_when_answer(self, answer_length, did):
|
||||
await self.devices[did].reset_timer_when_answer(answer_length)
|
||||
|
||||
def append_running_task(self, task):
|
||||
self.running_task.append(task)
|
||||
|
||||
@@ -938,6 +960,7 @@ class XiaoMusicDevice:
|
||||
# 播放进度
|
||||
self._start_time = 0
|
||||
self._duration = 0
|
||||
self._paused_time = 0
|
||||
|
||||
# 关机定时器
|
||||
self._stop_timer = None
|
||||
@@ -948,9 +971,9 @@ class XiaoMusicDevice:
|
||||
return self.device.cur_music
|
||||
|
||||
def get_offset_duration(self):
|
||||
if not self._playing:
|
||||
if not self.isplaying():
|
||||
return -1, -1
|
||||
offset = time.time() - self._start_time
|
||||
offset = time.time() - self._start_time - self._paused_time
|
||||
duration = self._duration
|
||||
return offset, duration
|
||||
|
||||
@@ -1005,7 +1028,9 @@ class XiaoMusicDevice:
|
||||
self.device.play_type == PLAY_TYPE_ALL
|
||||
or self.device.play_type == PLAY_TYPE_RND
|
||||
or name == ""
|
||||
or (name not in self._play_list)
|
||||
or (
|
||||
(name not in self._play_list) and self.device.play_type != PLAY_TYPE_ONE
|
||||
)
|
||||
):
|
||||
name = self.get_next_music()
|
||||
self.log.info(f"_play_next. name:{name}, cur_music:{self.get_cur_music()}")
|
||||
@@ -1082,6 +1107,7 @@ class XiaoMusicDevice:
|
||||
sec = sec + self.config.delay_sec
|
||||
self._start_time = time.time()
|
||||
self._duration = sec
|
||||
self._paused_time = 0
|
||||
await self.set_next_music_timeout(sec)
|
||||
self.xiaomusic.save_cur_config()
|
||||
|
||||
@@ -1333,6 +1359,19 @@ class XiaoMusicDevice:
|
||||
self.log.error(f"_get_audio_id {e}")
|
||||
return str(audio_id)
|
||||
|
||||
# 重置计时器
|
||||
async def reset_timer_when_answer(self, answer_length):
|
||||
if not (self.isplaying() and self.config.continue_play):
|
||||
return
|
||||
pause_time = answer_length / 5 + 1
|
||||
offset, duration = self.get_offset_duration()
|
||||
self._paused_time += pause_time
|
||||
new_time = duration - offset + pause_time
|
||||
await self.set_next_music_timeout(new_time)
|
||||
self.log.info(
|
||||
f"reset_timer 延长定时器. answer_length:{answer_length} pause_time:{pause_time}"
|
||||
)
|
||||
|
||||
# 设置下一首歌曲的播放定时器
|
||||
async def set_next_music_timeout(self, sec):
|
||||
self.cancel_next_timer()
|
||||
|
||||
Reference in New Issue
Block a user