mirror of
https://github.com/imsyy/SPlayer.git
synced 2025-11-25 03:14:57 +08:00
✨ feat: 新增副歌时间展示
This commit is contained in:
14
electron/server/port.ts
Normal file
14
electron/server/port.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import getPort from "get-port";
|
||||
|
||||
// 默认端口
|
||||
let webPort: number;
|
||||
let servePort: number;
|
||||
|
||||
const getSafePort = async () => {
|
||||
if (webPort && servePort) return { webPort, servePort };
|
||||
webPort = await getPort({ port: 14558 });
|
||||
servePort = await getPort({ port: 25884 });
|
||||
return { webPort, servePort };
|
||||
};
|
||||
|
||||
export default getSafePort;
|
||||
@@ -57,6 +57,7 @@
|
||||
"electron-updater": "^6.3.9",
|
||||
"file-saver": "^2.0.5",
|
||||
"font-list": "^1.5.1",
|
||||
"get-port": "^7.1.0",
|
||||
"github-markdown-css": "^5.8.1",
|
||||
"howler": "^2.2.4",
|
||||
"js-cookie": "^3.0.5",
|
||||
@@ -101,6 +102,7 @@
|
||||
"prettier": "^3.4.1",
|
||||
"sass": "^1.81.0",
|
||||
"terser": "^5.36.0",
|
||||
"typescript": "5.6.2",
|
||||
"unplugin-auto-import": "^0.18.6",
|
||||
"unplugin-vue-components": "^0.27.5",
|
||||
"vite": "^5.4.11",
|
||||
@@ -108,7 +110,6 @@
|
||||
"vite-plugin-wasm": "^3.3.0",
|
||||
"vue": "^3.5.13",
|
||||
"vue-router": "^4.5.0",
|
||||
"typescript": "5.6.2",
|
||||
"vue-tsc": "2.0.29"
|
||||
},
|
||||
"pnpm": {
|
||||
|
||||
9
pnpm-lock.yaml
generated
9
pnpm-lock.yaml
generated
@@ -84,6 +84,9 @@ importers:
|
||||
font-list:
|
||||
specifier: ^1.5.1
|
||||
version: 1.5.1
|
||||
get-port:
|
||||
specifier: ^7.1.0
|
||||
version: 7.1.0
|
||||
github-markdown-css:
|
||||
specifier: ^5.8.1
|
||||
version: 5.8.1
|
||||
@@ -2337,6 +2340,10 @@ packages:
|
||||
resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==}
|
||||
engines: {node: '>= 0.4'}
|
||||
|
||||
get-port@7.1.0:
|
||||
resolution: {integrity: sha512-QB9NKEeDg3xxVwCCwJQ9+xycaz6pBB6iQ76wiWMl1927n0Kir6alPiP+yuiICLLU4jpMe08dXfpebuQppFA2zw==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
get-stream@4.1.0:
|
||||
resolution: {integrity: sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -6478,6 +6485,8 @@ snapshots:
|
||||
has-symbols: 1.0.3
|
||||
hasown: 2.0.2
|
||||
|
||||
get-port@7.1.0: {}
|
||||
|
||||
get-stream@4.1.0:
|
||||
dependencies:
|
||||
pump: 3.0.2
|
||||
|
||||
@@ -114,10 +114,20 @@ export const matchSong = (
|
||||
* 歌曲动态封面
|
||||
* @param {number} id - 歌曲 id
|
||||
*/
|
||||
|
||||
export const songDynamicCover = (id: number) => {
|
||||
return request({
|
||||
url: "/song/dynamic/cover",
|
||||
params: { id },
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* 副歌时间
|
||||
* @param {number} id - 歌曲 id
|
||||
*/
|
||||
export const songChorus = (id: number) => {
|
||||
return request({
|
||||
url: "/song/chorus",
|
||||
params: { id },
|
||||
});
|
||||
};
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
:max="100"
|
||||
:tooltip="false"
|
||||
:keyboard="false"
|
||||
:marks="
|
||||
statusStore.chorus && statusStore.progress <= statusStore.chorus
|
||||
? { [statusStore.chorus]: '' }
|
||||
: undefined
|
||||
"
|
||||
class="player-slider"
|
||||
@dragstart="player.pause(false)"
|
||||
@dragend="sliderDragend"
|
||||
@@ -380,6 +385,7 @@ const changeVolume = (e: WheelEvent) => {
|
||||
height: 16px;
|
||||
top: -8px;
|
||||
left: 0;
|
||||
margin: 0;
|
||||
--n-rail-height: 3px;
|
||||
--n-handle-size: 14px;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ interface StatusState {
|
||||
lyricIndex: number;
|
||||
currentTime: number;
|
||||
duration: number;
|
||||
chorus: number;
|
||||
progress: number;
|
||||
currentTimeOffset: number;
|
||||
playUblock: boolean;
|
||||
@@ -65,6 +66,8 @@ export const useStatusStore = defineStore({
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
progress: 0,
|
||||
// 副歌时间
|
||||
chorus: 0,
|
||||
// 进度偏移
|
||||
currentTimeOffset: 0,
|
||||
// 封面主题
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Howl, Howler } from "howler";
|
||||
import { cloneDeep } from "lodash-es";
|
||||
import { useMusicStore, useStatusStore, useDataStore, useSettingStore } from "@/stores";
|
||||
import { parsedLyricsData, resetSongLyric, parseLocalLyric } from "./lyric";
|
||||
import { songUrl, unlockSongUrl, songLyric } from "@/api/song";
|
||||
import { songUrl, unlockSongUrl, songLyric, songChorus } from "@/api/song";
|
||||
import { getCoverColorData } from "@/utils/color";
|
||||
import { calculateProgress } from "./time";
|
||||
import { isElectron, isDev } from "./helper";
|
||||
@@ -52,6 +52,7 @@ class Player {
|
||||
currentTime: 0,
|
||||
duration: 0,
|
||||
progress: 0,
|
||||
chorus: 0,
|
||||
currentTimeOffset: 0,
|
||||
lyricIndex: -1,
|
||||
playStatus: false,
|
||||
@@ -113,12 +114,7 @@ class Player {
|
||||
// 歌词跨界处理
|
||||
const lyricIndex = index === -1 ? lyrics.length - 1 : index - 1;
|
||||
// 更新状态
|
||||
statusStore.$patch({
|
||||
currentTime,
|
||||
duration,
|
||||
progress,
|
||||
lyricIndex,
|
||||
});
|
||||
statusStore.$patch({ currentTime, duration, progress, lyricIndex });
|
||||
// 客户端事件
|
||||
if (isElectron) {
|
||||
// 歌词变化
|
||||
@@ -217,9 +213,11 @@ class Player {
|
||||
if (!settingStore.showSpectrums) this.toggleOutputDevice();
|
||||
// 自动播放
|
||||
if (autoPlay) this.play();
|
||||
// 获取歌词数据 - 非电台和本地
|
||||
if (type !== "radio" && !path) this.getLyricData(id);
|
||||
else resetSongLyric();
|
||||
// 获取歌曲附加信息 - 非电台和本地
|
||||
if (type !== "radio" && !path) {
|
||||
this.getLyricData(id);
|
||||
this.getChorus(id);
|
||||
} else resetSongLyric();
|
||||
// 定时获取状态
|
||||
if (!this.playerInterval) this.handlePlayStatus();
|
||||
// 新增播放历史
|
||||
@@ -402,6 +400,22 @@ class Player {
|
||||
const lyricRes = await songLyric(id);
|
||||
parsedLyricsData(lyricRes);
|
||||
}
|
||||
/**
|
||||
* 获取副歌时间
|
||||
* @param id 歌曲id
|
||||
*/
|
||||
private async getChorus(id: number) {
|
||||
const statusStore = useStatusStore();
|
||||
const result = await songChorus(id);
|
||||
if (result?.code !== 200 || result?.chorus?.length === 0) {
|
||||
statusStore.chorus = 0;
|
||||
return;
|
||||
}
|
||||
// 计算并保存
|
||||
const chorus = result?.chorus?.[0]?.startTime;
|
||||
const time = ((chorus / 1000 / statusStore.duration) * 100).toFixed(2);
|
||||
statusStore.chorus = Number(time);
|
||||
}
|
||||
/**
|
||||
* 播放错误
|
||||
* 在播放错误时,播放下一首
|
||||
@@ -590,8 +604,8 @@ class Player {
|
||||
const statusStore = useStatusStore();
|
||||
|
||||
// 播放器未加载完成
|
||||
if (this.player.state() !== "loaded"){
|
||||
return
|
||||
if (this.player.state() !== "loaded") {
|
||||
return;
|
||||
}
|
||||
|
||||
// 淡出
|
||||
@@ -880,7 +894,7 @@ class Player {
|
||||
const songIndex = await dataStore.setNextPlaySong(song, statusStore.playIndex);
|
||||
// 播放歌曲
|
||||
if (songIndex < 0) return;
|
||||
if (play) this.togglePlayIndex(songIndex,true);
|
||||
if (play) this.togglePlayIndex(songIndex, true);
|
||||
else window.$message.success("已添加至下一首播放");
|
||||
}
|
||||
/**
|
||||
@@ -888,7 +902,7 @@ class Player {
|
||||
* @param index 播放索引
|
||||
* @param play 是否立即播放
|
||||
*/
|
||||
async togglePlayIndex(index: number,play:boolean = false) {
|
||||
async togglePlayIndex(index: number, play: boolean = false) {
|
||||
const dataStore = useDataStore();
|
||||
const statusStore = useStatusStore();
|
||||
// 获取数据
|
||||
|
||||
Reference in New Issue
Block a user