mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-13 15:58:13 +08:00
Compare commits
25 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
aa2992b5d7 | ||
|
|
7fcd3eeae5 | ||
|
|
30194272d9 | ||
|
|
1b71301b06 | ||
|
|
13bbff8d67 | ||
|
|
ae3507b811 | ||
|
|
bdfb0a4127 | ||
|
|
3d0a38cbb8 | ||
|
|
f469f63d97 | ||
|
|
6544bb2ff1 | ||
|
|
668237401e | ||
|
|
139ebf37c4 | ||
|
|
7146d61fcb | ||
|
|
6033c1a6fc | ||
|
|
e77a4fc10d | ||
|
|
bf2909d35a | ||
|
|
b3255a17ce | ||
|
|
a3140ff23a | ||
|
|
becfdbf338 | ||
|
|
8b74b664f0 | ||
|
|
0daba20885 | ||
|
|
8ac39af8cd | ||
|
|
d6fb62eb8e | ||
|
|
24ac876632 | ||
|
|
fcdb7bf035 |
64
.github/workflows/ci.yml
vendored
64
.github/workflows/ci.yml
vendored
@@ -6,6 +6,9 @@ on:
|
|||||||
- "*"
|
- "*"
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
TEST_TAG: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-image:
|
build-image:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -14,21 +17,70 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v3
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v3
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v3
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v4
|
# We have to build each platform separately because when using multi-arch
|
||||||
|
# builds, only one platform is being loaded into the cache. This would
|
||||||
|
# prevent us from testing the other platforms.
|
||||||
|
- name: Build Docker image (linux/amd64)
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
|
platforms: linux/amd64
|
||||||
context: .
|
context: .
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.TEST_TAG }}-linux-amd64
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||||
|
|
||||||
|
- name: Build Docker image (linux/arm64)
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
platforms: linux/arm64
|
||||||
|
context: .
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.TEST_TAG }}-linux-arm64
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||||
|
|
||||||
|
- name: Build Docker image (linux/arm/v7)
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
|
platforms: linux/arm/v7
|
||||||
|
context: .
|
||||||
|
push: false
|
||||||
|
load: true
|
||||||
|
tags: ${{ env.TEST_TAG }}-linux-arm-v7
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||||
|
|
||||||
|
# We test all the images on amd64 host here. This uses QEMU to emulate
|
||||||
|
# the other platforms.
|
||||||
|
- run: docker run --rm ${TEST_TAG}-linux-amd64 -h
|
||||||
|
- run: docker run --rm ${TEST_TAG}-linux-arm64 -h
|
||||||
|
- run: docker run --rm ${TEST_TAG}-linux-arm-v7 -h
|
||||||
|
|
||||||
|
# This will only push the previously built images.
|
||||||
|
- name: Publish to Docker Hub
|
||||||
|
uses: docker/build-push-action@v6
|
||||||
|
with:
|
||||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||||
|
context: .
|
||||||
push: true
|
push: true
|
||||||
tags: ${{ secrets.DOCKERHUB_USERNAME }}/xiaomusic:${{ github.ref_name }}
|
tags: ${{ env.TEST_TAG }}
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache-new
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||||
|
|
||||||
- name: Docker Hub Description
|
- name: Docker Hub Description
|
||||||
uses: peter-evans/dockerhub-description@v4
|
uses: peter-evans/dockerhub-description@v4
|
||||||
with:
|
with:
|
||||||
|
|||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,3 +1,33 @@
|
|||||||
|
## v0.3.42 (2024-10-24)
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- 尝试修复缺少 libtiff.so.6 文件的问题 #244
|
||||||
|
- 修复默认主题播放歌曲输入框空的情况
|
||||||
|
- 尝试修复停止后自动播放的问题
|
||||||
|
|
||||||
|
## v0.3.41 (2024-10-17)
|
||||||
|
|
||||||
|
### Feat
|
||||||
|
|
||||||
|
- 设置默认时区为东八区 closed #236
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- 修复获取标签信息报错问题
|
||||||
|
- remove_id3_tags return None if no id3 tag (#238)
|
||||||
|
- bug in del_music (#237)
|
||||||
|
|
||||||
|
## v0.3.40 (2024-10-16)
|
||||||
|
|
||||||
|
### Feat
|
||||||
|
|
||||||
|
- 默认主题的播放列表上显示歌曲数量
|
||||||
|
|
||||||
|
### Fix
|
||||||
|
|
||||||
|
- 修复播放卡顿问题(谷歌统计地址无法访问的情况)
|
||||||
|
|
||||||
## v0.3.39 (2024-10-15)
|
## v0.3.39 (2024-10-15)
|
||||||
|
|
||||||
### Feat
|
### Feat
|
||||||
|
|||||||
@@ -12,6 +12,13 @@ COPY install_dependencies.sh .
|
|||||||
RUN bash install_dependencies.sh
|
RUN bash install_dependencies.sh
|
||||||
|
|
||||||
FROM python:3.10-slim
|
FROM python:3.10-slim
|
||||||
|
|
||||||
|
RUN apt-get update && apt-get install -y \
|
||||||
|
libtiff6 \
|
||||||
|
libopenjp2-7 \
|
||||||
|
libxcb1 \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
COPY --from=builder /app/.venv /app/.venv
|
COPY --from=builder /app/.venv /app/.venv
|
||||||
COPY --from=builder /app/ffmpeg /app/ffmpeg
|
COPY --from=builder /app/ffmpeg /app/ffmpeg
|
||||||
@@ -23,5 +30,6 @@ ENV XIAOMUSIC_PORT=8090
|
|||||||
VOLUME /app/conf
|
VOLUME /app/conf
|
||||||
VOLUME /app/music
|
VOLUME /app/music
|
||||||
EXPOSE 8090
|
EXPOSE 8090
|
||||||
|
ENV TZ=Asia/Shanghai
|
||||||
ENV PATH=/app/.venv/bin:$PATH
|
ENV PATH=/app/.venv/bin:$PATH
|
||||||
ENTRYPOINT [".venv/bin/python3","xiaomusic.py"]
|
ENTRYPOINT [".venv/bin/python3","xiaomusic.py"]
|
||||||
|
|||||||
36
README.md
36
README.md
@@ -24,6 +24,12 @@
|
|||||||
docker run -p 8090:8090 -v /xiaomusic/music:/app/music -v /xiaomusic/conf:/app/conf hanxi/xiaomusic
|
docker run -p 8090:8090 -v /xiaomusic/music:/app/music -v /xiaomusic/conf:/app/conf hanxi/xiaomusic
|
||||||
```
|
```
|
||||||
|
|
||||||
|
🔥 国内:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run -p 8090:8090 -v /xiaomusic/music:/app/music -v /xiaomusic/conf:/app/conf m.daocloud.io/docker.io/hanxi/xiaomusic
|
||||||
|
```
|
||||||
|
|
||||||
对应的 docker compose 配置如下:
|
对应的 docker compose 配置如下:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -39,6 +45,21 @@ services:
|
|||||||
- /xiaomusic/conf:/app/conf
|
- /xiaomusic/conf:/app/conf
|
||||||
```
|
```
|
||||||
|
|
||||||
|
🔥 国内:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
services:
|
||||||
|
xiaomusic:
|
||||||
|
image: m.daocloud.io/docker.io/hanxi/xiaomusic
|
||||||
|
container_name: xiaomusic
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- 8090:8090
|
||||||
|
volumes:
|
||||||
|
- /xiaomusic/music:/app/music
|
||||||
|
- /xiaomusic/conf:/app/conf
|
||||||
|
```
|
||||||
|
|
||||||
其中 conf 目录为配置文件存放目录,music 目录为音乐存放目录,建议分开配置为不同的目录。
|
其中 conf 目录为配置文件存放目录,music 目录为音乐存放目录,建议分开配置为不同的目录。
|
||||||
|
|
||||||
> [!NOTE]
|
> [!NOTE]
|
||||||
@@ -98,8 +119,6 @@ services:
|
|||||||
> [!TIP]
|
> [!TIP]
|
||||||
> 隐藏玩法: 对小爱同学说播放歌曲小猪佩奇的故事,会先下载小猪佩奇的故事,然后再播放小猪佩奇的故事。
|
> 隐藏玩法: 对小爱同学说播放歌曲小猪佩奇的故事,会先下载小猪佩奇的故事,然后再播放小猪佩奇的故事。
|
||||||
|
|
||||||
更多功能见 [📝 文档汇总](https://github.com/hanxi/xiaomusic/issues/211)
|
|
||||||
|
|
||||||
## 🛠️ pip 方式安装运行
|
## 🛠️ pip 方式安装运行
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
@@ -281,22 +300,13 @@ docker build -t xiaomusic .
|
|||||||
- [微信小程序: XIAO晓音](https://github.com/F-loat/xiaoplayer)
|
- [微信小程序: XIAO晓音](https://github.com/F-loat/xiaoplayer)
|
||||||
- [pure 主题 xiaomusicUI](https://github.com/52fisher/xiaomusicUI)
|
- [pure 主题 xiaomusicUI](https://github.com/52fisher/xiaomusicUI)
|
||||||
- [移动端的播放器主题](https://github.com/52fisher/XMusicPlayer)
|
- [移动端的播放器主题](https://github.com/52fisher/XMusicPlayer)
|
||||||
|
- [一个第三方的主题](https://github.com/DarrenWen/xiaomusicui)
|
||||||
- 所有帮忙调试和测试的朋友
|
- 所有帮忙调试和测试的朋友
|
||||||
- 所有反馈问题和建议的朋友
|
- 所有反馈问题和建议的朋友
|
||||||
|
|
||||||
### 👉 其他教程
|
### 👉 其他教程
|
||||||
|
|
||||||
> [!NOTE]
|
更多功能见 [📝 文档汇总](https://github.com/hanxi/xiaomusic/issues/211)
|
||||||
> 下面教程可能比较旧,只供参考
|
|
||||||
|
|
||||||
- [NAS部署教程](https://post.m.smzdm.com/p/avpe7n99/)
|
|
||||||
- [群晖部署教程](https://post.m.smzdm.com/p/a7px7dol/)
|
|
||||||
- [QNAS部署教程](https://post.smzdm.com/p/a5xz5x63/)
|
|
||||||
- [视频教程](https://www.bilibili.com/video/BV1ZZpweHEtT/)
|
|
||||||
- [TechHive](https://mp.weixin.qq.com/s/4a41muFtPaFKtHeZYu795w)
|
|
||||||
- [弹个AI](https://mp.weixin.qq.com/s/sIsKxB7Y8b83AhnvaWiMog)
|
|
||||||
- [简单免费!教你用绿联NAS联动小爱音箱,私人音乐库也能语音点播](https://post.m.smzdm.com/p/a8pldgg7/)
|
|
||||||
- [飞牛教程](https://mp.weixin.qq.com/s?t=pages/image_detail&__biz=MzkxODc1NDMwOA==&mid=2247483725&idx=1&sn=2d615f14733b9bf989557fa766b4e1fc)
|
|
||||||
|
|
||||||
## 🚨 免责声明
|
## 🚨 免责声明
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "xiaomusic"
|
name = "xiaomusic"
|
||||||
version = "0.3.39"
|
version = "0.3.42"
|
||||||
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"},
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.3.39"
|
__version__ = "0.3.42"
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ class Analytics:
|
|||||||
self.gtag = None
|
self.gtag = None
|
||||||
self.current_date = None
|
self.current_date = None
|
||||||
self.log = log
|
self.log = log
|
||||||
|
self.task = None
|
||||||
self.init()
|
self.init()
|
||||||
|
|
||||||
def init(self):
|
def init(self):
|
||||||
@@ -27,16 +28,19 @@ class Analytics:
|
|||||||
self.gtag = gtag
|
self.gtag = gtag
|
||||||
self.log.info("analytics init ok")
|
self.log.info("analytics init ok")
|
||||||
|
|
||||||
async def run_with_timeout(self, func, *args, **kwargs):
|
async def run_with_cancel(self, func, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
return await asyncio.wait_for(func(*args, **kwargs), 3)
|
if self.task:
|
||||||
except asyncio.TimeoutError as e:
|
self.log.warning(f"analytics run_with_cancel old : {self.task}")
|
||||||
self.log.warning(f"analytics run_with_timeout failed {e}")
|
self.task.cancel()
|
||||||
|
self.task = asyncio.create_task(func(*args, **kwargs))
|
||||||
|
except Exception as e:
|
||||||
|
self.log.warning(f"analytics run_with_cancel failed {e}")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
async def send_startup_event(self):
|
async def send_startup_event(self):
|
||||||
try:
|
try:
|
||||||
await self.run_with_timeout(self._send_startup_event)
|
await self.run_with_cancel(self._send_startup_event)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning(f"analytics send_startup_event failed {e}")
|
self.log.warning(f"analytics send_startup_event failed {e}")
|
||||||
self.init()
|
self.init()
|
||||||
@@ -49,7 +53,7 @@ class Analytics:
|
|||||||
|
|
||||||
async def send_daily_event(self):
|
async def send_daily_event(self):
|
||||||
try:
|
try:
|
||||||
await self.run_with_timeout(self._send_daily_event)
|
await self.run_with_cancel(self._send_daily_event)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning(f"analytics send_daily_event failed {e}")
|
self.log.warning(f"analytics send_daily_event failed {e}")
|
||||||
self.init()
|
self.init()
|
||||||
@@ -68,7 +72,7 @@ class Analytics:
|
|||||||
|
|
||||||
async def send_play_event(self, name, sec):
|
async def send_play_event(self, name, sec):
|
||||||
try:
|
try:
|
||||||
await self.run_with_timeout(self._send_play_event, name, sec)
|
await self.run_with_cancel(self._send_play_event, name, sec)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.warning(f"analytics send_play_event failed {e}")
|
self.log.warning(f"analytics send_play_event failed {e}")
|
||||||
self.init()
|
self.init()
|
||||||
|
|||||||
@@ -316,9 +316,9 @@ class MusicItem(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
@app.post("/delmusic")
|
@app.post("/delmusic")
|
||||||
def delmusic(data: MusicItem, Verifcation=Depends(verification)):
|
async def delmusic(data: MusicItem, Verifcation=Depends(verification)):
|
||||||
log.info(data)
|
log.info(data)
|
||||||
xiaomusic.del_music(data.name)
|
await xiaomusic.del_music(data.name)
|
||||||
return "success"
|
return "success"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -122,7 +122,8 @@ $(function(){
|
|||||||
$.get("/musiclist", function(data, status) {
|
$.get("/musiclist", function(data, status) {
|
||||||
console.log(data, status);
|
console.log(data, status);
|
||||||
$.each(data, function(key, value) {
|
$.each(data, function(key, value) {
|
||||||
$('#music_list').append($('<option></option>').val(key).text(key));
|
let cnt = value.length;
|
||||||
|
$('#music_list').append($('<option></option>').val(key).text(`${key} (${cnt})`));
|
||||||
});
|
});
|
||||||
|
|
||||||
$('#music_list').change(function() {
|
$('#music_list').change(function() {
|
||||||
@@ -250,7 +251,13 @@ $(function(){
|
|||||||
|
|
||||||
$("#play").on("click", () => {
|
$("#play").on("click", () => {
|
||||||
var search_key = $("#music-name").val();
|
var search_key = $("#music-name").val();
|
||||||
|
if (search_key == null) {
|
||||||
|
search_key = "";
|
||||||
|
}
|
||||||
var filename = $("#music-filename").val();
|
var filename = $("#music-filename").val();
|
||||||
|
if (filename == null) {
|
||||||
|
filename = "";
|
||||||
|
}
|
||||||
let cmd = "播放歌曲" + search_key + "|" + filename;
|
let cmd = "播放歌曲" + search_key + "|" + filename;
|
||||||
sendcmd(cmd);
|
sendcmd(cmd);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,9 +6,9 @@
|
|||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>Debug For XiaoMusic</title>
|
<title>Debug For XiaoMusic</title>
|
||||||
|
|
||||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1729000721">
|
<link rel="stylesheet" type="text/css" href="./style.css?version=1729738799">
|
||||||
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
<script src="https://unpkg.com/vconsole@latest/dist/vconsole.min.js"></script>
|
||||||
<script src="./jquery-3.7.1.min.js?version=1729000721"></script>
|
<script src="./jquery-3.7.1.min.js?version=1729738799"></script>
|
||||||
|
|
||||||
<!-- Google tag (gtag.js) -->
|
<!-- Google tag (gtag.js) -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>歌曲下载工具</title>
|
<title>歌曲下载工具</title>
|
||||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1729000721">
|
<link rel="stylesheet" type="text/css" href="./style.css?version=1729738799">
|
||||||
<script src="./jquery-3.7.1.min.js?version=1729000721"></script>
|
<script src="./jquery-3.7.1.min.js?version=1729738799"></script>
|
||||||
|
|
||||||
<!-- Google tag (gtag.js) -->
|
<!-- Google tag (gtag.js) -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>小爱音箱操控面板</title>
|
<title>小爱音箱操控面板</title>
|
||||||
<script src="./jquery-3.7.1.min.js?version=1729000721"></script>
|
<script src="./jquery-3.7.1.min.js?version=1729738799"></script>
|
||||||
<script src="./app.js?version=1729000721"></script>
|
<script src="./app.js?version=1729738799"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1729000721">
|
<link rel="stylesheet" type="text/css" href="./style.css?version=1729738799">
|
||||||
|
|
||||||
<!-- Google tag (gtag.js) -->
|
<!-- Google tag (gtag.js) -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>M3U to JSON Converter</title>
|
<title>M3U to JSON Converter</title>
|
||||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1729000721">
|
<link rel="stylesheet" type="text/css" href="./style.css?version=1729738799">
|
||||||
|
|
||||||
<!-- Google tag (gtag.js) -->
|
<!-- Google tag (gtag.js) -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
<link rel="icon" href="/favicon.ico">
|
<link rel="icon" href="/favicon.ico">
|
||||||
<meta name="viewport" content="width=device-width">
|
<meta name="viewport" content="width=device-width">
|
||||||
<title>小爱音箱操控面板</title>
|
<title>小爱音箱操控面板</title>
|
||||||
<script src="./jquery-3.7.1.min.js?version=1729000721"></script>
|
<script src="./jquery-3.7.1.min.js?version=1729738799"></script>
|
||||||
<script src="./setting.js?version=1729000721"></script>
|
<script src="./setting.js?version=1729738799"></script>
|
||||||
<link rel="stylesheet" type="text/css" href="./style.css?version=1729000721">
|
<link rel="stylesheet" type="text/css" href="./style.css?version=1729738799">
|
||||||
|
|
||||||
<!-- Google tag (gtag.js) -->
|
<!-- Google tag (gtag.js) -->
|
||||||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
<script async src="https://www.googletagmanager.com/gtag/js?id=G-Z09NC1K7ZW"></script>
|
||||||
@@ -59,7 +59,7 @@ var vConsole = new window.VConsole();
|
|||||||
<option value="false">false</option>
|
<option value="false">false</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="group_list">设备分组配置:</label>
|
<label for="group_list">设备分组配置:<a href="https://github.com/hanxi/xiaomusic/issues/65#issuecomment-2215736529" target="_blank">文档</a></label>
|
||||||
<input id="group_list" type="text" placeholder="did1:组名1,did2:组名1,did3:组名2"></input>
|
<input id="group_list" type="text" placeholder="did1:组名1,did2:组名1,did3:组名2"></input>
|
||||||
|
|
||||||
<label for="music_path">音乐目录:</label>
|
<label for="music_path">音乐目录:</label>
|
||||||
@@ -111,7 +111,7 @@ var vConsole = new window.VConsole();
|
|||||||
<option value="false" selected>false</option>
|
<option value="false" selected>false</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<label for="miio_tts_command">MiIO sst 指令:</label>
|
<label for="miio_tts_command">MiIO tts 指令(解决部分型号没有提示音的问题):</label>
|
||||||
<input id="miio_tts_command" type="text" placeholder="如:5 或者 5-3"></input>
|
<input id="miio_tts_command" type="text" placeholder="如:5 或者 5-3"></input>
|
||||||
|
|
||||||
<label for="disable_httpauth">关闭控制台密码验证:</label>
|
<label for="disable_httpauth">关闭控制台密码验证:</label>
|
||||||
|
|||||||
@@ -416,6 +416,15 @@ def get_temp_dir(music_path: str):
|
|||||||
|
|
||||||
|
|
||||||
def remove_id3_tags(input_file: str, config) -> str:
|
def remove_id3_tags(input_file: str, config) -> str:
|
||||||
|
audio = MP3(input_file, ID3=ID3)
|
||||||
|
|
||||||
|
# 检查是否存在ID3 v2.3或v2.4标签
|
||||||
|
if not (
|
||||||
|
audio.tags
|
||||||
|
and (audio.tags.version == (2, 3, 0) or audio.tags.version == (2, 4, 0))
|
||||||
|
):
|
||||||
|
return None
|
||||||
|
|
||||||
music_path = config.music_path
|
music_path = config.music_path
|
||||||
temp_dir = get_temp_dir(music_path)
|
temp_dir = get_temp_dir(music_path)
|
||||||
|
|
||||||
@@ -436,12 +445,7 @@ def remove_id3_tags(input_file: str, config) -> str:
|
|||||||
log.info(f"File {out_file_path} already exists. Skipping remove_id3_tags.")
|
log.info(f"File {out_file_path} already exists. Skipping remove_id3_tags.")
|
||||||
return relative_path
|
return relative_path
|
||||||
|
|
||||||
audio = MP3(input_file, ID3=ID3)
|
# 开始去除(不再需要检查)
|
||||||
|
|
||||||
# 检查是否存在ID3 v2.3或v2.4标签
|
|
||||||
if audio.tags and (
|
|
||||||
audio.tags.version == (2, 3, 0) or audio.tags.version == (2, 4, 0)
|
|
||||||
):
|
|
||||||
# 拷贝文件
|
# 拷贝文件
|
||||||
shutil.copy(input_file, out_file_path)
|
shutil.copy(input_file, out_file_path)
|
||||||
outaudio = MP3(out_file_path, ID3=ID3)
|
outaudio = MP3(out_file_path, ID3=ID3)
|
||||||
@@ -452,8 +456,6 @@ def remove_id3_tags(input_file: str, config) -> str:
|
|||||||
log.info(f"File {out_file_path} remove_id3_tags ok.")
|
log.info(f"File {out_file_path} remove_id3_tags ok.")
|
||||||
return relative_path
|
return relative_path
|
||||||
|
|
||||||
return relative_path
|
|
||||||
|
|
||||||
|
|
||||||
def convert_file_to_mp3(input_file: str, config) -> str:
|
def convert_file_to_mp3(input_file: str, config) -> str:
|
||||||
music_path = config.music_path
|
music_path = config.music_path
|
||||||
@@ -591,7 +593,7 @@ def _to_utf8(v):
|
|||||||
return ts
|
return ts
|
||||||
return old_ts
|
return old_ts
|
||||||
elif isinstance(v, list):
|
elif isinstance(v, list):
|
||||||
return "".join(v)
|
return "".join(str(item) for item in v)
|
||||||
return str(v)
|
return str(v)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -892,7 +892,7 @@ class XiaoMusic:
|
|||||||
self.log.info("gen_music_list ok")
|
self.log.info("gen_music_list ok")
|
||||||
|
|
||||||
# 删除歌曲
|
# 删除歌曲
|
||||||
def del_music(self, name):
|
async def del_music(self, name):
|
||||||
filename = self.get_filename(name)
|
filename = self.get_filename(name)
|
||||||
if filename == "":
|
if filename == "":
|
||||||
self.log.info(f"${name} not exist")
|
self.log.info(f"${name} not exist")
|
||||||
@@ -1187,7 +1187,6 @@ class XiaoMusicDevice:
|
|||||||
|
|
||||||
self._download_proc = None # 下载对象
|
self._download_proc = None # 下载对象
|
||||||
self._next_timer = None
|
self._next_timer = None
|
||||||
self._timeout = 0
|
|
||||||
self._playing = False
|
self._playing = False
|
||||||
# 播放进度
|
# 播放进度
|
||||||
self._start_time = 0
|
self._start_time = 0
|
||||||
@@ -1677,14 +1676,17 @@ class XiaoMusicDevice:
|
|||||||
# 设置下一首歌曲的播放定时器
|
# 设置下一首歌曲的播放定时器
|
||||||
async def set_next_music_timeout(self, sec):
|
async def set_next_music_timeout(self, sec):
|
||||||
self.cancel_next_timer()
|
self.cancel_next_timer()
|
||||||
self._timeout = sec
|
|
||||||
|
|
||||||
async def _do_next():
|
async def _do_next():
|
||||||
await asyncio.sleep(self._timeout)
|
await asyncio.sleep(sec)
|
||||||
try:
|
try:
|
||||||
self.log.info("定时器时间到了")
|
self.log.info("定时器时间到了")
|
||||||
|
if self._next_timer:
|
||||||
self._next_timer = None
|
self._next_timer = None
|
||||||
await self._play_next()
|
await self._play_next()
|
||||||
|
else:
|
||||||
|
self.log.info("定时器时间到了但是不见了")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.log.error(f"Execption {e}")
|
self.log.error(f"Execption {e}")
|
||||||
|
|
||||||
@@ -1760,13 +1762,17 @@ class XiaoMusicDevice:
|
|||||||
await self.do_tts(f"收到,{minute}分钟后将关机")
|
await self.do_tts(f"收到,{minute}分钟后将关机")
|
||||||
|
|
||||||
def cancel_next_timer(self):
|
def cancel_next_timer(self):
|
||||||
|
self.log.info("cancel_next_timer")
|
||||||
if self._next_timer:
|
if self._next_timer:
|
||||||
self._next_timer.cancel()
|
self._next_timer.cancel()
|
||||||
self.log.info(f"下一曲定时器已取消 {self.device_id}")
|
self.log.info(f"下一曲定时器已取消 {self.device_id}")
|
||||||
self._next_timer = None
|
self._next_timer = None
|
||||||
|
else:
|
||||||
|
self.log.info("下一曲定时器不见了")
|
||||||
|
|
||||||
def cancel_group_next_timer(self):
|
def cancel_group_next_timer(self):
|
||||||
devices = self.xiaomusic.get_group_devices(self.group_name)
|
devices = self.xiaomusic.get_group_devices(self.group_name)
|
||||||
|
self.log.info(f"cancel_group_next_timer {devices}")
|
||||||
for device in devices.values():
|
for device in devices.values():
|
||||||
device.cancel_next_timer()
|
device.cancel_next_timer()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user