mirror of
https://github.com/hanxi/xiaomusic.git
synced 2025-12-07 15:02:55 +08:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad43a4f732 | ||
|
|
8699938b61 | ||
|
|
40bd099153 | ||
|
|
750923d5ca | ||
|
|
6d99b30e2d | ||
|
|
a155f16560 | ||
|
|
d4aa045487 | ||
|
|
8080dd9822 | ||
|
|
2eab8d8113 | ||
|
|
b51e56718a | ||
|
|
088d448e10 | ||
|
|
4a89b4bce5 | ||
|
|
b351b4bcd4 | ||
|
|
b2edaf48e4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -164,3 +164,4 @@ cython_debug/
|
||||
ffmpeg
|
||||
music
|
||||
test.sh
|
||||
conf
|
||||
|
||||
@@ -6,7 +6,6 @@ COPY install_dependencies.sh .
|
||||
RUN bash install_dependencies.sh
|
||||
|
||||
FROM python:3.10-slim
|
||||
|
||||
WORKDIR /app
|
||||
COPY --from=builder /app/.venv /app/.venv
|
||||
COPY --from=builder /app/ffmpeg /app/ffmpeg
|
||||
|
||||
13
README.md
13
README.md
@@ -186,6 +186,16 @@ services:
|
||||
- XIAOMUSIC_SEARCH
|
||||
- XIAOMUSIC_PROXY
|
||||
|
||||
## 更多其他可选配置
|
||||
|
||||
- XIAOMUSIC_ACTIVE_CMD 配置唤醒命令,具体见 <https://github.com/hanxi/xiaomusic/pull/43>
|
||||
- XIAOMUSIC_EXCLUDE_DIRS 配置歌曲目录里需要忽略的目录
|
||||
- XIAOMUSIC_MUSIC_PATH_DEPTH 配置歌曲目录搜索深度,具体见 <https://github.com/hanxi/xiaomusic/issues/76>
|
||||
- XIAOMUSIC_DISABLE_HTTPAUTH 配置成 false 表示开启密码访问web控制台,具体见 <https://github.com/hanxi/xiaomusic/issues/47>
|
||||
- XIAOMUSIC_HTTPAUTH_USERNAME 配置 web 控制台用户
|
||||
- XIAOMUSIC_HTTPAUTH_PASSWORD 配置 web 控制台密码
|
||||
- XIAOMUSIC_CONF_PATH 用来存放配置文件的目录,记得把目录映射到主机,默认情况会把配置存放在music目录,具体见 <https://github.com/hanxi/xiaomusic/issues/74>
|
||||
|
||||
## 讨论区
|
||||
|
||||
- [点击链接加入QQ频道【xiaomusic】](https://pd.qq.com/s/e2jybz0ss)
|
||||
@@ -206,3 +216,6 @@ services:
|
||||
## Star History
|
||||
|
||||
[](https://star-history.com/#hanxi/xiaomusic&Date)
|
||||
|
||||
## 赞赏
|
||||
谢谢就够了
|
||||
|
||||
14
pdm.lock
generated
14
pdm.lock
generated
@@ -5,7 +5,7 @@
|
||||
groups = ["default", "lint"]
|
||||
strategy = ["cross_platform"]
|
||||
lock_version = "4.4.1"
|
||||
content_hash = "sha256:38bae754be83ffca7d688fc4e1daf0964709d202d651c6c865ff56c1b8332caa"
|
||||
content_hash = "sha256:813253734c7d7835a76cd87fe8fe0329e02ad067f535aee6a9e11cb106569dd2"
|
||||
|
||||
[[package]]
|
||||
name = "aiohttp"
|
||||
@@ -356,6 +356,18 @@ files = [
|
||||
{file = "flask-3.0.3.tar.gz", hash = "sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flask-httpauth"
|
||||
version = "4.8.0"
|
||||
summary = "HTTP authentication for Flask routes"
|
||||
dependencies = [
|
||||
"flask",
|
||||
]
|
||||
files = [
|
||||
{file = "Flask-HTTPAuth-4.8.0.tar.gz", hash = "sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a"},
|
||||
{file = "Flask_HTTPAuth-4.8.0-py3-none-any.whl", hash = "sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flask"
|
||||
version = "3.0.3"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "xiaomusic"
|
||||
version = "0.1.54"
|
||||
version = "0.1.56"
|
||||
description = "Play Music with xiaomi AI speaker"
|
||||
authors = [
|
||||
{name = "涵曦", email = "im.hanxi@gmail.com"},
|
||||
@@ -13,6 +13,7 @@ dependencies = [
|
||||
"yt-dlp>=2024.04.09",
|
||||
"flask[async]>=3.0.1",
|
||||
"waitress>=3.0.0",
|
||||
"flask-HTTPAuth>=4.8.0",
|
||||
]
|
||||
requires-python = ">=3.10"
|
||||
readme = "README.md"
|
||||
|
||||
@@ -223,6 +223,9 @@ colorama==0.4.6; platform_system == "Windows" \
|
||||
flask==3.0.3 \
|
||||
--hash=sha256:34e815dfaa43340d1d15a5c3a02b8476004037eb4840b34910c6e21679d288f3 \
|
||||
--hash=sha256:ceb27b0af3823ea2737928a4d99d125a06175b8512c445cbd9a9ce200ef76842
|
||||
flask-HTTPAuth==4.8.0 \
|
||||
--hash=sha256:66568a05bc73942c65f1e2201ae746295816dc009edd84b482c44c758d75097a \
|
||||
--hash=sha256:a58fedd09989b9975448eef04806b096a3964a7feeebc0a78831ff55685b62b0
|
||||
frozenlist==1.4.0 \
|
||||
--hash=sha256:008eb8b31b3ea6896da16c38c1b136cb9fec9e249e77f6211d479db79a4eaf01 \
|
||||
--hash=sha256:09163bdf0b2907454042edb19f887c6d33806adc71fbd54afc14908bfdc22251 \
|
||||
|
||||
@@ -1 +1 @@
|
||||
__version__ = "0.1.54"
|
||||
__version__ = "0.1.56"
|
||||
|
||||
@@ -27,20 +27,6 @@ def main():
|
||||
dest="cookie",
|
||||
help="xiaomi cookie",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--use_command",
|
||||
dest="use_command",
|
||||
action="store_true",
|
||||
default=None,
|
||||
help="use command to tts",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--mute_xiaoai",
|
||||
dest="mute_xiaoai",
|
||||
action="store_true",
|
||||
default=None,
|
||||
help="try to mute xiaoai answer",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--verbose",
|
||||
dest="verbose",
|
||||
|
||||
@@ -9,28 +9,6 @@ from xiaomusic.utils import validate_proxy
|
||||
|
||||
LATEST_ASK_API = "https://userprofile.mina.mi.com/device_profile/v2/conversation?source=dialogu&hardware={hardware}×tamp={timestamp}&limit=2"
|
||||
COOKIE_TEMPLATE = "deviceId={device_id}; serviceToken={service_token}; userId={user_id}"
|
||||
HARDWARE_COMMAND_DICT = {
|
||||
# hardware: (tts_command, wakeup_command, volume_command)
|
||||
"LX06": ("5-1", "5-5", "2-1"),
|
||||
"L05B": ("5-3", "5-4", "2-1"),
|
||||
"S12": ("5-1", "5-5", "2-1"), # 第一代小爱,型号MDZ-25-DA
|
||||
"S12A": ("5-1", "5-5", "2-1"),
|
||||
"LX01": ("5-1", "5-5", "2-1"),
|
||||
"L06A": ("5-1", "5-5", "2-1"),
|
||||
"LX04": ("5-1", "5-4", "2-1"),
|
||||
"L05C": ("5-3", "5-4", "2-1"),
|
||||
"L17A": ("7-3", "7-4", "2-1"),
|
||||
"X08E": ("7-3", "7-4", "2-1"),
|
||||
"LX05A": ("5-1", "5-5", "2-1"), # 小爱红外版
|
||||
"LX5A": ("5-1", "5-5", "2-1"), # 小爱红外版
|
||||
"L07A": ("5-1", "5-5", "2-1"), # Redmi小爱音箱Play(l7a)
|
||||
"L15A": ("7-3", "7-4", "2-1"),
|
||||
"X6A": ("7-3", "7-4", "2-1"), # 小米智能家庭屏6
|
||||
"X10A": ("7-3", "7-4", "2-1"), # 小米智能家庭屏10
|
||||
# add more here
|
||||
}
|
||||
|
||||
DEFAULT_COMMAND = ("5-1", "5-5", "2-1")
|
||||
|
||||
KEY_WORD_DICT = {
|
||||
"播放歌曲": "play",
|
||||
@@ -73,6 +51,7 @@ KEY_MATCH_ORDER = [
|
||||
SUPPORT_MUSIC_TYPE = [
|
||||
".mp3",
|
||||
".flac",
|
||||
".wav",
|
||||
]
|
||||
|
||||
|
||||
@@ -82,9 +61,7 @@ class Config:
|
||||
account: str = os.getenv("MI_USER", "")
|
||||
password: str = os.getenv("MI_PASS", "")
|
||||
mi_did: str = os.getenv("MI_DID", "")
|
||||
mute_xiaoai: bool = True
|
||||
cookie: str = ""
|
||||
use_command: bool = False
|
||||
verbose: bool = os.getenv("XIAOMUSIC_VERBOSE", "").lower() == "true"
|
||||
music_path: str = os.getenv("XIAOMUSIC_MUSIC_PATH", "music")
|
||||
conf_path: str = os.getenv("XIAOMUSIC_CONF_PATH", None)
|
||||
@@ -98,23 +75,16 @@ class Config:
|
||||
active_cmd: str = os.getenv("XIAOMUSIC_ACTIVE_CMD", "play,random_play")
|
||||
exclude_dirs: str = os.getenv("XIAOMUSIC_EXCLUDE_DIRS", "@eaDir")
|
||||
music_path_depth: int = int(os.getenv("XIAOMUSIC_MUSIC_PATH_DEPTH", "10"))
|
||||
disable_httpauth: bool = (
|
||||
os.getenv("XIAOMUSIC_DISABLE_HTTPAUTH", "true").lower() == "true"
|
||||
)
|
||||
httpauth_username: str = os.getenv("XIAOMUSIC_HTTPAUTH_USERNAME", "admin")
|
||||
httpauth_password: str = os.getenv("XIAOMUSIC_HTTPAUTH_PASSWORD", "admin")
|
||||
|
||||
def __post_init__(self) -> None:
|
||||
if self.proxy:
|
||||
validate_proxy(self.proxy)
|
||||
|
||||
@property
|
||||
def tts_command(self) -> str:
|
||||
return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[0]
|
||||
|
||||
@property
|
||||
def wakeup_command(self) -> str:
|
||||
return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[1]
|
||||
|
||||
@property
|
||||
def volume_command(self) -> str:
|
||||
return HARDWARE_COMMAND_DICT.get(self.hardware, DEFAULT_COMMAND)[2]
|
||||
|
||||
@classmethod
|
||||
def from_options(cls, options: argparse.Namespace) -> Config:
|
||||
config = {}
|
||||
|
||||
@@ -3,6 +3,7 @@ import os
|
||||
from threading import Thread
|
||||
|
||||
from flask import Flask, request, send_from_directory
|
||||
from flask_httpauth import HTTPBasicAuth
|
||||
from waitress import serve
|
||||
|
||||
from xiaomusic import (
|
||||
@@ -12,12 +13,9 @@ from xiaomusic.config import (
|
||||
KEY_WORD_DICT,
|
||||
)
|
||||
|
||||
# 隐藏 flask 启动告警
|
||||
# https://gist.github.com/jerblack/735b9953ba1ab6234abb43174210d356
|
||||
# from flask import cli
|
||||
# cli.show_server_banner = lambda *_: None
|
||||
|
||||
app = Flask(__name__)
|
||||
auth = HTTPBasicAuth()
|
||||
|
||||
host = "0.0.0.0"
|
||||
port = 8090
|
||||
static_path = "music"
|
||||
@@ -25,7 +23,20 @@ xiaomusic = None
|
||||
log = None
|
||||
|
||||
|
||||
@auth.verify_password
|
||||
def verify_password(username, password):
|
||||
if xiaomusic.config.disable_httpauth:
|
||||
return True
|
||||
|
||||
if (
|
||||
xiaomusic.config.httpauth_username == username
|
||||
and xiaomusic.config.httpauth_password == password
|
||||
):
|
||||
return username
|
||||
|
||||
|
||||
@app.route("/allcmds")
|
||||
@auth.login_required
|
||||
def allcmds():
|
||||
return KEY_WORD_DICT
|
||||
|
||||
@@ -39,6 +50,7 @@ def getversion():
|
||||
|
||||
|
||||
@app.route("/getvolume", methods=["GET"])
|
||||
@auth.login_required
|
||||
def getvolume():
|
||||
volume = xiaomusic.get_volume_ret()
|
||||
return {
|
||||
@@ -47,22 +59,25 @@ def getvolume():
|
||||
|
||||
|
||||
@app.route("/searchmusic", methods=["GET"])
|
||||
@auth.login_required
|
||||
def searchmusic():
|
||||
name = request.args.get("name")
|
||||
return xiaomusic.searchmusic(name)
|
||||
|
||||
|
||||
@app.route("/playingmusic", methods=["GET"])
|
||||
@auth.login_required
|
||||
def playingmusic():
|
||||
return xiaomusic.playingmusic()
|
||||
|
||||
|
||||
@app.route("/", methods=["GET"])
|
||||
def redirect_to_index():
|
||||
def index():
|
||||
return send_from_directory("static", "index.html")
|
||||
|
||||
|
||||
@app.route("/cmd", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def do_cmd():
|
||||
data = request.get_json()
|
||||
cmd = data.get("cmd")
|
||||
@@ -74,6 +89,7 @@ async def do_cmd():
|
||||
|
||||
|
||||
@app.route("/getsetting", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def getsetting():
|
||||
config = xiaomusic.getconfig()
|
||||
log.debug(config)
|
||||
@@ -92,6 +108,7 @@ async def getsetting():
|
||||
|
||||
|
||||
@app.route("/savesetting", methods=["POST"])
|
||||
@auth.login_required
|
||||
async def savesetting():
|
||||
data = request.get_json()
|
||||
log.info(data)
|
||||
@@ -100,16 +117,19 @@ async def savesetting():
|
||||
|
||||
|
||||
@app.route("/musiclist", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def musiclist():
|
||||
return xiaomusic.get_music_list()
|
||||
|
||||
|
||||
@app.route("/curplaylist", methods=["GET"])
|
||||
@auth.login_required
|
||||
async def curplaylist():
|
||||
return xiaomusic.get_cur_play_list()
|
||||
|
||||
|
||||
@app.route("/delmusic", methods=["POST"])
|
||||
@auth.login_required
|
||||
def delmusic():
|
||||
data = request.get_json()
|
||||
log.info(data)
|
||||
|
||||
@@ -13,7 +13,7 @@ from pathlib import Path
|
||||
|
||||
import mutagen
|
||||
from aiohttp import ClientSession, ClientTimeout
|
||||
from miservice import MiAccount, MiIOService, MiNAService, miio_command
|
||||
from miservice import MiAccount, MiIOService, MiNAService
|
||||
|
||||
from xiaomusic import (
|
||||
__version__,
|
||||
@@ -253,42 +253,20 @@ class XiaoMusic:
|
||||
|
||||
async def do_tts(self, value):
|
||||
self.log.info("do_tts: %s", value)
|
||||
|
||||
if self.config.mute_xiaoai:
|
||||
await self.force_stop_xiaoai()
|
||||
else:
|
||||
# waiting for xiaoai speaker done
|
||||
await asyncio.sleep(8)
|
||||
|
||||
if not self.config.use_command:
|
||||
try:
|
||||
await self.mina_service.text_to_speech(self.device_id, value)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
await miio_command(
|
||||
self.miio_service,
|
||||
self.config.mi_did,
|
||||
f"{self.config.tts_command} {value}",
|
||||
)
|
||||
await self.force_stop_xiaoai()
|
||||
try:
|
||||
await self.mina_service.text_to_speech(self.device_id, value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def do_set_volume(self, value):
|
||||
value = int(value)
|
||||
self._volume = value
|
||||
self.log.info(f"声音设置为{value}")
|
||||
if not self.config.use_command:
|
||||
try:
|
||||
self.log.debug("do_set_volume not use_command value:%d", value)
|
||||
await self.mina_service.player_set_volume(self.device_id, value)
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
self.log.debug("do_set_volume use_command value:%d", value)
|
||||
await miio_command(
|
||||
self.miio_service,
|
||||
self.config.mi_did,
|
||||
f"{self.config.volume_command}=#{value}",
|
||||
)
|
||||
try:
|
||||
await self.mina_service.player_set_volume(self.device_id, value)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
async def force_stop_xiaoai(self):
|
||||
await self.mina_service.player_stop(self.device_id)
|
||||
@@ -379,7 +357,7 @@ class XiaoMusic:
|
||||
name,
|
||||
extension,
|
||||
)
|
||||
if extension not in SUPPORT_MUSIC_TYPE:
|
||||
if extension.lower() not in SUPPORT_MUSIC_TYPE:
|
||||
continue
|
||||
|
||||
# 歌曲名字相同会覆盖
|
||||
|
||||
Reference in New Issue
Block a user