feat: 新增播放上一首歌曲功能 #90
This commit is contained in:
parent
d7385405d9
commit
d71f99de53
@ -16,6 +16,7 @@ def default_key_word_dict():
|
|||||||
"播放本地歌曲": "playlocal",
|
"播放本地歌曲": "playlocal",
|
||||||
"关机": "stop",
|
"关机": "stop",
|
||||||
"下一首": "play_next",
|
"下一首": "play_next",
|
||||||
|
"上一首": "play_prev",
|
||||||
"单曲循环": "set_play_type_one",
|
"单曲循环": "set_play_type_one",
|
||||||
"全部循环": "set_play_type_all",
|
"全部循环": "set_play_type_all",
|
||||||
"随机播放": "set_random_play",
|
"随机播放": "set_random_play",
|
||||||
@ -46,6 +47,7 @@ def default_key_match_order():
|
|||||||
"分钟后关机",
|
"分钟后关机",
|
||||||
"播放歌曲",
|
"播放歌曲",
|
||||||
"下一首",
|
"下一首",
|
||||||
|
"上一首",
|
||||||
"单曲循环",
|
"单曲循环",
|
||||||
"全部循环",
|
"全部循环",
|
||||||
"随机播放",
|
"随机播放",
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
$(function(){
|
$(function(){
|
||||||
$container=$("#cmds");
|
$container=$("#cmds");
|
||||||
|
|
||||||
|
append_op_button_name("加入收藏");
|
||||||
|
append_op_button_name("取消收藏");
|
||||||
|
|
||||||
const PLAY_TYPE_ONE = 0; // 单曲循环
|
const PLAY_TYPE_ONE = 0; // 单曲循环
|
||||||
const PLAY_TYPE_ALL = 1; // 全部循环
|
const PLAY_TYPE_ALL = 1; // 全部循环
|
||||||
const PLAY_TYPE_RND = 2; // 随机播放
|
const PLAY_TYPE_RND = 2; // 随机播放
|
||||||
@ -8,12 +11,11 @@ $(function(){
|
|||||||
append_op_button("play_type_one", "单曲循环", "单曲循环");
|
append_op_button("play_type_one", "单曲循环", "单曲循环");
|
||||||
append_op_button("play_type_rnd", "随机播放", "随机播放");
|
append_op_button("play_type_rnd", "随机播放", "随机播放");
|
||||||
|
|
||||||
append_op_button_name("刷新列表");
|
append_op_button_name("上一首");
|
||||||
append_op_button_name("下一首");
|
|
||||||
append_op_button_name("关机");
|
append_op_button_name("关机");
|
||||||
|
append_op_button_name("下一首");
|
||||||
|
|
||||||
append_op_button_name("加入收藏");
|
append_op_button_name("刷新列表");
|
||||||
append_op_button_name("取消收藏");
|
|
||||||
|
|
||||||
$container.append($("<hr>"));
|
$container.append($("<hr>"));
|
||||||
|
|
||||||
@ -100,8 +102,7 @@ $(function(){
|
|||||||
const selectedValue = $(this).val();
|
const selectedValue = $(this).val();
|
||||||
localStorage.setItem('cur_playlist', selectedValue);
|
localStorage.setItem('cur_playlist', selectedValue);
|
||||||
$('#music_name').empty();
|
$('#music_name').empty();
|
||||||
const sorted_musics = data[selectedValue].sort(custom_sort_key);
|
$.each(data[selectedValue], function(index, item) {
|
||||||
$.each(sorted_musics, function(index, item) {
|
|
||||||
$('#music_name').append($('<option></option>').val(item).text(item));
|
$('#music_name').append($('<option></option>').val(item).text(item));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -273,23 +274,4 @@ $(function(){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function custom_sort_key(a, b) {
|
|
||||||
// 使用正则表达式提取数字前缀
|
|
||||||
const numericPrefixA = a.match(/^(\d+)/) ? parseInt(a.match(/^(\d+)/)[1], 10) : null;
|
|
||||||
const numericPrefixB = b.match(/^(\d+)/) ? parseInt(b.match(/^(\d+)/)[1], 10) : null;
|
|
||||||
|
|
||||||
// 如果两个键都有数字前缀,则按数字大小排序
|
|
||||||
if (numericPrefixA !== null && numericPrefixB !== null) {
|
|
||||||
return numericPrefixA - numericPrefixB;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果一个键有数字前缀而另一个没有,则有数字前缀的键排在前面
|
|
||||||
if (numericPrefixA !== null) return -1;
|
|
||||||
if (numericPrefixB !== null) return 1;
|
|
||||||
|
|
||||||
// 如果两个键都没有数字前缀,则按照常规字符串排序
|
|
||||||
return a.localeCompare(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import copy
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
import math
|
import math
|
||||||
@ -721,6 +722,9 @@ class XiaoMusic:
|
|||||||
async def play_next(self, did="", **kwargs):
|
async def play_next(self, did="", **kwargs):
|
||||||
return await self.devices[did].play_next()
|
return await self.devices[did].play_next()
|
||||||
|
|
||||||
|
async def play_prev(self, did="", **kwargs):
|
||||||
|
return await self.devices[did].play_prev()
|
||||||
|
|
||||||
# 停止
|
# 停止
|
||||||
async def stop(self, did="", arg1="", **kwargs):
|
async def stop(self, did="", arg1="", **kwargs):
|
||||||
return await self.devices[did].stop(arg1=arg1)
|
return await self.devices[did].stop(arg1=arg1)
|
||||||
@ -797,7 +801,7 @@ class XiaoMusic:
|
|||||||
|
|
||||||
# 正在播放中的音乐
|
# 正在播放中的音乐
|
||||||
def playingmusic(self, did):
|
def playingmusic(self, did):
|
||||||
cur_music = self.devices[did].cur_music
|
cur_music = self.devices[did].get_cur_music()
|
||||||
self.log.debug(f"playingmusic. cur_music:{cur_music}")
|
self.log.debug(f"playingmusic. cur_music:{cur_music}")
|
||||||
return cur_music
|
return cur_music
|
||||||
|
|
||||||
@ -841,7 +845,6 @@ class XiaoMusic:
|
|||||||
def save_cur_config(self):
|
def save_cur_config(self):
|
||||||
for did in self.config.devices.keys():
|
for did in self.config.devices.keys():
|
||||||
deviceobj = self.devices.get(did)
|
deviceobj = self.devices.get(did)
|
||||||
self.log.info(deviceobj.device)
|
|
||||||
if deviceobj is not None:
|
if deviceobj is not None:
|
||||||
self.config.devices[did] = deviceobj.device
|
self.config.devices[did] = deviceobj.device
|
||||||
data = asdict(self.config)
|
data = asdict(self.config)
|
||||||
@ -917,7 +920,6 @@ class XiaoMusicDevice:
|
|||||||
self.ffmpeg_location = self.config.ffmpeg_location
|
self.ffmpeg_location = self.config.ffmpeg_location
|
||||||
|
|
||||||
self._download_proc = None # 下载对象
|
self._download_proc = None # 下载对象
|
||||||
self.cur_music = self.device.cur_music
|
|
||||||
self._next_timer = None
|
self._next_timer = None
|
||||||
self._timeout = 0
|
self._timeout = 0
|
||||||
self._playing = False
|
self._playing = False
|
||||||
@ -926,12 +928,21 @@ class XiaoMusicDevice:
|
|||||||
self._last_cmd = None
|
self._last_cmd = None
|
||||||
self.update_playlist()
|
self.update_playlist()
|
||||||
|
|
||||||
|
def get_cur_music(self):
|
||||||
|
return self.device.cur_music
|
||||||
|
|
||||||
# 初始化播放列表
|
# 初始化播放列表
|
||||||
def update_playlist(self):
|
def update_playlist(self):
|
||||||
self._cur_play_list = self.device.cur_playlist
|
if self.device.cur_playlist not in self.xiaomusic.music_list:
|
||||||
if self._cur_play_list not in self.xiaomusic.music_list:
|
self.device.cur_playlist = "全部"
|
||||||
self._cur_play_list = "全部"
|
|
||||||
self._play_list = self.xiaomusic.music_list.get(self._cur_play_list)
|
list_name = self.device.cur_playlist
|
||||||
|
self._play_list = copy.copy(self.xiaomusic.music_list[list_name])
|
||||||
|
if self.device.play_type == PLAY_TYPE_RND:
|
||||||
|
random.shuffle(self._play_list)
|
||||||
|
self.log.info(f"随机打乱 {list_name} {self._play_list}")
|
||||||
|
else:
|
||||||
|
self.log.info(f"没打乱 {list_name} {self._play_list}")
|
||||||
|
|
||||||
# 播放歌曲
|
# 播放歌曲
|
||||||
async def play(self, name="", search_key=""):
|
async def play(self, name="", search_key=""):
|
||||||
@ -944,7 +955,7 @@ class XiaoMusicDevice:
|
|||||||
await self._play_next()
|
await self._play_next()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
name = self.cur_music
|
name = self.get_cur_music()
|
||||||
self.log.info(f"play. search_key:{search_key} name:{name}")
|
self.log.info(f"play. search_key:{search_key} name:{name}")
|
||||||
|
|
||||||
# 本地歌曲不存在时下载
|
# 本地歌曲不存在时下载
|
||||||
@ -966,7 +977,7 @@ class XiaoMusicDevice:
|
|||||||
|
|
||||||
async def _play_next(self):
|
async def _play_next(self):
|
||||||
self.log.info("开始播放下一首")
|
self.log.info("开始播放下一首")
|
||||||
name = self.cur_music
|
name = self.get_cur_music()
|
||||||
if (
|
if (
|
||||||
self.device.play_type == PLAY_TYPE_ALL
|
self.device.play_type == PLAY_TYPE_ALL
|
||||||
or self.device.play_type == PLAY_TYPE_RND
|
or self.device.play_type == PLAY_TYPE_RND
|
||||||
@ -974,7 +985,27 @@ class XiaoMusicDevice:
|
|||||||
or (name not in self._play_list)
|
or (name not in self._play_list)
|
||||||
):
|
):
|
||||||
name = self.get_next_music()
|
name = self.get_next_music()
|
||||||
self.log.info(f"_play_next. name:{name}, cur_music:{self.cur_music}")
|
self.log.info(f"_play_next. name:{name}, cur_music:{self.get_cur_music()}")
|
||||||
|
if name == "":
|
||||||
|
await self.do_tts("本地没有歌曲")
|
||||||
|
return
|
||||||
|
await self._play(name)
|
||||||
|
|
||||||
|
# 上一首
|
||||||
|
async def play_prev(self):
|
||||||
|
return await self._play_prev()
|
||||||
|
|
||||||
|
async def _play_prev(self):
|
||||||
|
self.log.info("开始播放上一首")
|
||||||
|
name = self.get_cur_music()
|
||||||
|
if (
|
||||||
|
self.device.play_type == PLAY_TYPE_ALL
|
||||||
|
or self.device.play_type == PLAY_TYPE_RND
|
||||||
|
or name == ""
|
||||||
|
or (name not in self._play_list)
|
||||||
|
):
|
||||||
|
name = self.get_prev_music()
|
||||||
|
self.log.info(f"_play_prev. name:{name}, cur_music:{self.get_cur_music()}")
|
||||||
if name == "":
|
if name == "":
|
||||||
await self.do_tts("本地没有歌曲")
|
await self.do_tts("本地没有歌曲")
|
||||||
return
|
return
|
||||||
@ -988,7 +1019,7 @@ class XiaoMusicDevice:
|
|||||||
await self._play_next()
|
await self._play_next()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
name = self.cur_music
|
name = self.get_cur_music()
|
||||||
|
|
||||||
self.log.info(f"playlocal. name:{name}")
|
self.log.info(f"playlocal. name:{name}")
|
||||||
|
|
||||||
@ -1004,10 +1035,9 @@ class XiaoMusicDevice:
|
|||||||
self.cancel_group_next_timer()
|
self.cancel_group_next_timer()
|
||||||
|
|
||||||
self._playing = True
|
self._playing = True
|
||||||
self.cur_music = name
|
|
||||||
self.device.cur_music = name
|
self.device.cur_music = name
|
||||||
|
|
||||||
self.log.info(f"cur_music {self.cur_music}")
|
self.log.info(f"cur_music {self.get_cur_music()}")
|
||||||
sec, url = await self.xiaomusic.get_music_sec_url(name)
|
sec, url = await self.xiaomusic.get_music_sec_url(name)
|
||||||
await self.group_force_stop_xiaoai()
|
await self.group_force_stop_xiaoai()
|
||||||
self.log.info(f"播放 {url}")
|
self.log.info(f"播放 {url}")
|
||||||
@ -1041,7 +1071,7 @@ class XiaoMusicDevice:
|
|||||||
# 最大等8秒
|
# 最大等8秒
|
||||||
sec = min(8, int(len(value) / 3))
|
sec = min(8, int(len(value) / 3))
|
||||||
await asyncio.sleep(sec)
|
await asyncio.sleep(sec)
|
||||||
self.log.info(f"do_tts ok. cur_music:{self.cur_music}")
|
self.log.info(f"do_tts ok. cur_music:{self.get_cur_music()}")
|
||||||
await self.check_replay()
|
await self.check_replay()
|
||||||
|
|
||||||
async def force_stop_xiaoai(self, device_id):
|
async def force_stop_xiaoai(self, device_id):
|
||||||
@ -1143,51 +1173,62 @@ class XiaoMusicDevice:
|
|||||||
self.log.info(f"add_download_music add_music {name}")
|
self.log.info(f"add_download_music add_music {name}")
|
||||||
self.log.debug(self._play_list)
|
self.log.debug(self._play_list)
|
||||||
|
|
||||||
# 获取下一首
|
def get_music(self, direction="next"):
|
||||||
def get_next_music(self):
|
|
||||||
play_list_len = len(self._play_list)
|
play_list_len = len(self._play_list)
|
||||||
if play_list_len == 0:
|
if play_list_len == 0:
|
||||||
self.log.warning("当前播放列表没有歌曲")
|
self.log.warning("当前播放列表没有歌曲")
|
||||||
return ""
|
return ""
|
||||||
index = 0
|
index = 0
|
||||||
try:
|
try:
|
||||||
index = self._play_list.index(self.cur_music)
|
index = self._play_list.index(self.get_cur_music())
|
||||||
except ValueError:
|
except ValueError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if play_list_len == 1:
|
if play_list_len == 1:
|
||||||
next_index = index # 当只有一首歌曲时保持当前索引不变
|
new_index = index # 当只有一首歌曲时保持当前索引不变
|
||||||
else:
|
else:
|
||||||
# 顺序往后找1个
|
if direction == "next":
|
||||||
next_index = index + 1
|
new_index = index + 1
|
||||||
if next_index >= play_list_len:
|
if new_index >= play_list_len:
|
||||||
next_index = 0
|
new_index = 0
|
||||||
# 排除当前歌曲随机找1个
|
elif direction == "prev":
|
||||||
if self.device.play_type == PLAY_TYPE_RND:
|
new_index = index - 1
|
||||||
indices = list(range(play_list_len))
|
if new_index < 0:
|
||||||
indices.remove(index)
|
new_index = play_list_len - 1
|
||||||
next_index = random.choice(indices)
|
else:
|
||||||
name = self._play_list[next_index]
|
self.log.error("无效的方向参数")
|
||||||
|
return ""
|
||||||
|
|
||||||
|
name = self._play_list[new_index]
|
||||||
if not self.xiaomusic.is_music_exist(name):
|
if not self.xiaomusic.is_music_exist(name):
|
||||||
self._play_list.pop(next_index)
|
self._play_list.pop(new_index)
|
||||||
self.log.info(f"pop not exist music:{name}")
|
self.log.info(f"pop not exist music: {name}")
|
||||||
return self.get_next_music()
|
return self.get_music(direction)
|
||||||
return name
|
return name
|
||||||
|
|
||||||
|
# 获取下一首
|
||||||
|
def get_next_music(self):
|
||||||
|
return self.get_music(direction="next")
|
||||||
|
|
||||||
|
# 获取上一首
|
||||||
|
def get_prev_music(self):
|
||||||
|
return self.get_music(direction="prev")
|
||||||
|
|
||||||
# 判断是否播放下一首歌曲
|
# 判断是否播放下一首歌曲
|
||||||
def check_play_next(self):
|
def check_play_next(self):
|
||||||
# 当前歌曲不在当前播放列表
|
# 当前歌曲不在当前播放列表
|
||||||
if self.cur_music not in self._play_list:
|
if self.get_cur_music() not in self._play_list:
|
||||||
self.log.info(f"当前歌曲 {self.cur_music} 不在当前播放列表")
|
self.log.info(f"当前歌曲 {self.get_cur_music()} 不在当前播放列表")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
# 当前没我在播放的歌曲
|
# 当前没我在播放的歌曲
|
||||||
if self.cur_music == "":
|
if self.get_cur_music() == "":
|
||||||
self.log.info("当前没我在播放的歌曲")
|
self.log.info("当前没我在播放的歌曲")
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
# 当前播放的歌曲不存在了
|
# 当前播放的歌曲不存在了
|
||||||
if not self.xiaomusic.is_music_exist(self.cur_music):
|
if not self.xiaomusic.is_music_exist(self.get_cur_music()):
|
||||||
self.log.info(f"当前播放的歌曲 {self.cur_music} 不存在了")
|
self.log.info(f"当前播放的歌曲 {self.get_cur_music()} 不存在了")
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@ -1289,12 +1330,12 @@ class XiaoMusicDevice:
|
|||||||
self.xiaomusic.save_cur_config()
|
self.xiaomusic.save_cur_config()
|
||||||
tts = PLAY_TYPE_TTS[play_type]
|
tts = PLAY_TYPE_TTS[play_type]
|
||||||
await self.do_tts(tts)
|
await self.do_tts(tts)
|
||||||
|
self.update_playlist()
|
||||||
|
|
||||||
async def play_music_list(self, list_name, music_name):
|
async def play_music_list(self, list_name, music_name):
|
||||||
self._last_cmd = "play_music_list"
|
self._last_cmd = "play_music_list"
|
||||||
self._cur_play_list = list_name
|
|
||||||
self.device.cur_playlist = list_name
|
self.device.cur_playlist = list_name
|
||||||
self._play_list = self.xiaomusic.music_list[list_name]
|
self.update_playlist()
|
||||||
self.log.info(f"开始播放列表{list_name}")
|
self.log.info(f"开始播放列表{list_name}")
|
||||||
await self._play(music_name)
|
await self._play(music_name)
|
||||||
|
|
||||||
@ -1344,7 +1385,7 @@ class XiaoMusicDevice:
|
|||||||
device.cancel_next_timer()
|
device.cancel_next_timer()
|
||||||
|
|
||||||
def get_cur_play_list(self):
|
def get_cur_play_list(self):
|
||||||
return self._cur_play_list
|
return self.device.cur_playlist
|
||||||
|
|
||||||
# 清空所有定时器
|
# 清空所有定时器
|
||||||
def cancel_all_timer(self):
|
def cancel_all_timer(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user