mirror of
https://github.com/imsyy/SPlayer.git
synced 2025-11-25 19:37:35 +08:00
✨ feat: 优化随机播放问题 & 播放页字体抖动效果优化
This commit is contained in:
@@ -324,6 +324,7 @@ onBeforeUnmount(() => {
|
|||||||
padding: 10px 16px;
|
padding: 10px 16px;
|
||||||
transform: scale(0.86);
|
transform: scale(0.86);
|
||||||
transform-origin: left center;
|
transform-origin: left center;
|
||||||
|
will-change: filter, opacity, transform;
|
||||||
transition:
|
transition:
|
||||||
filter 0.35s,
|
filter 0.35s,
|
||||||
opacity 0.35s,
|
opacity 0.35s,
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { formatCategoryList } from "@/utils/format";
|
|||||||
|
|
||||||
interface ListState {
|
interface ListState {
|
||||||
playList: SongType[];
|
playList: SongType[];
|
||||||
|
originalPlayList: SongType[];
|
||||||
historyList: SongType[];
|
historyList: SongType[];
|
||||||
cloudPlayList: SongType[];
|
cloudPlayList: SongType[];
|
||||||
searchHistory: string[];
|
searchHistory: string[];
|
||||||
@@ -54,6 +55,8 @@ export const useDataStore = defineStore("data", {
|
|||||||
state: (): ListState => ({
|
state: (): ListState => ({
|
||||||
// 播放列表
|
// 播放列表
|
||||||
playList: [],
|
playList: [],
|
||||||
|
// 原始播放列表
|
||||||
|
originalPlayList: [],
|
||||||
// 播放历史
|
// 播放历史
|
||||||
historyList: [],
|
historyList: [],
|
||||||
// 搜索历史
|
// 搜索历史
|
||||||
@@ -157,6 +160,29 @@ export const useDataStore = defineStore("data", {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
// 保存原始播放列表
|
||||||
|
async setOriginalPlayList(data: SongType[]): Promise<void> {
|
||||||
|
const snapshot = cloneDeep(data);
|
||||||
|
this.originalPlayList = snapshot;
|
||||||
|
await musicDB.setItem("originalPlayList", snapshot);
|
||||||
|
},
|
||||||
|
// 获取原始播放列表
|
||||||
|
async getOriginalPlayList(): Promise<SongType[] | null> {
|
||||||
|
if (Array.isArray(this.originalPlayList) && this.originalPlayList.length > 0) {
|
||||||
|
return this.originalPlayList;
|
||||||
|
}
|
||||||
|
const data = (await musicDB.getItem("originalPlayList")) as SongType[] | null;
|
||||||
|
if (Array.isArray(data) && data.length > 0) {
|
||||||
|
this.originalPlayList = data;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
// 清除原始播放列表
|
||||||
|
async clearOriginalPlayList(): Promise<void> {
|
||||||
|
this.originalPlayList = [];
|
||||||
|
await musicDB.setItem("originalPlayList", []);
|
||||||
|
},
|
||||||
// 新增下一首播放歌曲
|
// 新增下一首播放歌曲
|
||||||
async setNextPlaySong(song: SongType, index: number): Promise<number> {
|
async setNextPlaySong(song: SongType, index: number): Promise<number> {
|
||||||
// 若为空,则直接添加
|
// 若为空,则直接添加
|
||||||
|
|||||||
@@ -40,6 +40,17 @@ class Player {
|
|||||||
// 初始化媒体会话
|
// 初始化媒体会话
|
||||||
this.initMediaSession();
|
this.initMediaSession();
|
||||||
}
|
}
|
||||||
|
/**
|
||||||
|
* 洗牌数组(Fisher-Yates)
|
||||||
|
*/
|
||||||
|
private shuffleArray<T>(arr: T[]): T[] {
|
||||||
|
const copy = arr.slice();
|
||||||
|
for (let i = copy.length - 1; i > 0; i--) {
|
||||||
|
const j = Math.floor(Math.random() * (i + 1));
|
||||||
|
[copy[i], copy[j]] = [copy[j], copy[i]];
|
||||||
|
}
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* 重置状态
|
* 重置状态
|
||||||
*/
|
*/
|
||||||
@@ -667,19 +678,15 @@ class Player {
|
|||||||
this.setSeek(0);
|
this.setSeek(0);
|
||||||
await this.play();
|
await this.play();
|
||||||
}
|
}
|
||||||
// 列表循环或处于心动模式
|
// 列表循环或处于心动模式或随机模式
|
||||||
if (playSongMode === "repeat" || playHeartbeatMode || playSong.type === "radio") {
|
if (
|
||||||
|
playSongMode === "repeat" ||
|
||||||
|
playSongMode === "shuffle" ||
|
||||||
|
playHeartbeatMode ||
|
||||||
|
playSong.type === "radio"
|
||||||
|
) {
|
||||||
statusStore.playIndex += type === "next" ? 1 : -1;
|
statusStore.playIndex += type === "next" ? 1 : -1;
|
||||||
}
|
}
|
||||||
// 随机播放
|
|
||||||
else if (playSongMode === "shuffle") {
|
|
||||||
let newIndex: number;
|
|
||||||
// 确保不会随机到同一首
|
|
||||||
do {
|
|
||||||
newIndex = Math.floor(Math.random() * playListLength);
|
|
||||||
} while (newIndex === statusStore.playIndex);
|
|
||||||
statusStore.playIndex = newIndex;
|
|
||||||
}
|
|
||||||
// 单曲循环
|
// 单曲循环
|
||||||
else if (playSongMode === "repeat-once") {
|
else if (playSongMode === "repeat-once") {
|
||||||
statusStore.lyricIndex = -1;
|
statusStore.lyricIndex = -1;
|
||||||
@@ -708,28 +715,65 @@ class Player {
|
|||||||
* 切换播放模式
|
* 切换播放模式
|
||||||
* @param mode 播放模式 repeat / repeat-once / shuffle
|
* @param mode 播放模式 repeat / repeat-once / shuffle
|
||||||
*/
|
*/
|
||||||
togglePlayMode(mode: PlayModeType | false) {
|
async togglePlayMode(mode: PlayModeType | false) {
|
||||||
const statusStore = useStatusStore();
|
const statusStore = useStatusStore();
|
||||||
|
const dataStore = useDataStore();
|
||||||
|
const musicStore = useMusicStore();
|
||||||
// 退出心动模式
|
// 退出心动模式
|
||||||
if (statusStore.playHeartbeatMode) this.toggleHeartMode(false);
|
if (statusStore.playHeartbeatMode) this.toggleHeartMode(false);
|
||||||
// 若传入了指定模式
|
// 计算目标模式
|
||||||
|
let targetMode: PlayModeType;
|
||||||
if (mode) {
|
if (mode) {
|
||||||
statusStore.playSongMode = mode;
|
targetMode = mode;
|
||||||
} else {
|
} else {
|
||||||
switch (statusStore.playSongMode) {
|
switch (statusStore.playSongMode) {
|
||||||
case "repeat":
|
case "repeat":
|
||||||
statusStore.playSongMode = "repeat-once";
|
targetMode = "repeat-once";
|
||||||
break;
|
break;
|
||||||
case "shuffle":
|
case "shuffle":
|
||||||
statusStore.playSongMode = "repeat";
|
targetMode = "repeat";
|
||||||
break;
|
break;
|
||||||
case "repeat-once":
|
case "repeat-once":
|
||||||
statusStore.playSongMode = "shuffle";
|
targetMode = "shuffle";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
statusStore.playSongMode = "repeat";
|
targetMode = "repeat";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 进入随机模式:保存原顺序并打乱当前歌单
|
||||||
|
if (targetMode === "shuffle" && statusStore.playSongMode !== "shuffle") {
|
||||||
|
const currentList = dataStore.playList;
|
||||||
|
if (currentList && currentList.length > 1) {
|
||||||
|
const currentSongId = musicStore.playSong?.id;
|
||||||
|
await dataStore.setOriginalPlayList(currentList);
|
||||||
|
const shuffled = this.shuffleArray(currentList);
|
||||||
|
await dataStore.setPlayList(shuffled);
|
||||||
|
if (currentSongId) {
|
||||||
|
const newIndex = shuffled.findIndex((s: any) => s?.id === currentSongId);
|
||||||
|
if (newIndex !== -1) useStatusStore().playIndex = newIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 离开随机模式:恢复到原顺序
|
||||||
|
if (
|
||||||
|
statusStore.playSongMode === "shuffle" &&
|
||||||
|
(targetMode === "repeat" || targetMode === "repeat-once")
|
||||||
|
) {
|
||||||
|
const original = await dataStore.getOriginalPlayList();
|
||||||
|
if (original && original.length) {
|
||||||
|
const currentSongId = musicStore.playSong?.id;
|
||||||
|
await dataStore.setPlayList(original);
|
||||||
|
if (currentSongId) {
|
||||||
|
const origIndex = original.findIndex((s: any) => s?.id === currentSongId);
|
||||||
|
useStatusStore().playIndex = origIndex !== -1 ? origIndex : 0;
|
||||||
|
} else {
|
||||||
|
useStatusStore().playIndex = 0;
|
||||||
|
}
|
||||||
|
await dataStore.clearOriginalPlayList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 应用模式
|
||||||
|
statusStore.playSongMode = targetMode;
|
||||||
this.playModeSyncIpc();
|
this.playModeSyncIpc();
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
"electron/main/utils.ts",
|
"electron/main/utils.ts",
|
||||||
"electron/main/index.d.ts",
|
"electron/main/index.d.ts",
|
||||||
"electron/preload/index.d.ts",
|
"electron/preload/index.d.ts",
|
||||||
"electron/preload/index.ts"
|
"electron/preload/index.ts",
|
||||||
, "dist/lastfm.ts" ],
|
"dist/lastfm.ts"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
"types": ["electron-vite/node"]
|
"types": ["electron-vite/node"]
|
||||||
|
|||||||
@@ -5,10 +5,12 @@
|
|||||||
"src/**/*",
|
"src/**/*",
|
||||||
"src/**/*.vue",
|
"src/**/*.vue",
|
||||||
"electron/main/index.d.ts",
|
"electron/main/index.d.ts",
|
||||||
"electron/preload/index.d.ts"
|
"electron/preload/index.d.ts",
|
||||||
, "dist/lastfm.ts" ],
|
"dist/lastfm.ts"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
"maxNodeModuleJsDepth": 2,
|
"maxNodeModuleJsDepth": 2,
|
||||||
"baseUrl": ".",
|
"baseUrl": ".",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|||||||
Reference in New Issue
Block a user