Skip to content

Commit 39c35e8

Browse files
committed
🦄 refactor: 重构为毫秒单位
1 parent 772f655 commit 39c35e8

16 files changed

Lines changed: 147 additions & 1125 deletions

File tree

src/components/Player/CountDown.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ const props = defineProps<{
3636
// 是否显示
3737
const isShow = computed(() => {
3838
if (!settingStore.countDownShow) return false;
39-
// 计算实时时间 - 0.5是否小于开始 + 持续时间,小于则显示,否则不显示
40-
return props.seek + 0.5 < props.start + props.duration;
39+
// 计算实时时间 - 0.5s 是否小于开始 + 持续时间,小于则显示,否则不显示
40+
return props.seek + 500 < props.start + props.duration;
4141
});
4242
4343
// 计算每个点的透明度

src/components/Player/LyricMenu.vue

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<template>
22
<n-flex class="menu" justify="center" vertical>
3-
<div class="menu-icon" @click="changeOffset(-0.5)">
3+
<div class="menu-icon" @click="changeOffset(-500)">
44
<SvgIcon name="Replay5" />
55
</div>
66
<span class="time" @click="resetOffset()">
77
{{ currentTimeOffsetValue }}
88
</span>
9-
<div class="menu-icon" @click="changeOffset(0.5)">
9+
<div class="menu-icon" @click="changeOffset(500)">
1010
<SvgIcon name="Forward5" />
1111
</div>
1212
<div class="divider" />
@@ -29,16 +29,18 @@ const statusStore = useStatusStore();
2929
const currentSongId = computed(() => musicStore.playSong?.id as number | undefined);
3030
3131
/**
32-
* 当前进度偏移值
32+
* 当前进度偏移值(显示为秒,保留1位小数)
3333
*/
3434
const currentTimeOffsetValue = computed(() => {
3535
const currentTimeOffset = statusStore.getSongOffset(currentSongId.value);
36-
return currentTimeOffset > 0 ? `+${currentTimeOffset}` : currentTimeOffset;
36+
// 将毫秒转换为秒显示(保留1位小数)
37+
const offsetSeconds = (currentTimeOffset / 1000).toFixed(1);
38+
return currentTimeOffset > 0 ? `+${offsetSeconds}` : offsetSeconds;
3739
});
3840
3941
/**
4042
* 改变进度偏移
41-
* @param delta 偏移量
43+
* @param delta 偏移量(单位:毫秒)
4244
*/
4345
const changeOffset = (delta: number) => {
4446
statusStore.incSongOffset(currentSongId.value, delta);

src/components/Player/MainAMLyric.vue

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@
3636
import { LyricPlayer } from "@applemusic-like-lyrics/vue";
3737
import { LyricLine } from "@applemusic-like-lyrics/core";
3838
import { useMusicStore, useSettingStore, useStatusStore } from "@/stores";
39-
import { msToS } from "@/utils/time";
40-
import { getLyricLanguage } from "@/utils/lyric";
39+
import { getLyricLanguage } from "@/utils/format";
4140
import player from "@/utils/player";
4241
import LyricMenu from "./LyricMenu.vue";
4342
@@ -48,16 +47,13 @@ const settingStore = useSettingStore();
4847
const lyricPlayerRef = ref<any | null>(null);
4948
5049
// 实时播放进度
51-
const playSeek = ref<number>(
52-
Math.floor((player.getSeek() + statusStore.getSongOffset(musicStore.playSong?.id)) * 1000),
53-
);
50+
const playSeek = ref<number>(player.getSeek() + statusStore.getSongOffset(musicStore.playSong?.id));
5451
5552
// 实时更新播放进度
5653
const { pause: pauseSeek, resume: resumeSeek } = useRafFn(() => {
5754
const songId = musicStore.playSong?.id;
58-
const offsetSeconds = statusStore.getSongOffset(songId);
59-
const seekInSeconds = player.getSeek() + offsetSeconds;
60-
playSeek.value = Math.floor(seekInSeconds * 1000);
55+
const offsetTime = statusStore.getSongOffset(songId);
56+
playSeek.value = player.getSeek() + offsetTime;
6157
});
6258
6359
// 歌词主色
@@ -84,9 +80,9 @@ const amLyricsData = computed<LyricLine[]>(() => {
8480
// 进度跳转
8581
const jumpSeek = (line: any) => {
8682
if (!line?.line?.lyricLine?.startTime) return;
87-
const time = msToS(line.line.lyricLine.startTime);
88-
const offsetSeconds = statusStore.getSongOffset(musicStore.playSong?.id);
89-
player.setSeek(time - offsetSeconds);
83+
const time = line.line.lyricLine.startTime;
84+
const offsetMs = statusStore.getSongOffset(musicStore.playSong?.id);
85+
player.setSeek(time - offsetMs);
9086
player.play();
9187
};
9288

src/components/Player/MainLyric.vue

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<!-- 倒计时 -->
3535
<CountDown
3636
:start="0"
37-
:duration="(musicStore.songLyric.yrcData[0].startTime || 0) / 1000"
37+
:duration="musicStore.songLyric.yrcData[0].startTime || 0"
3838
:seek="playSeek"
3939
:playing="statusStore.playStatus"
4040
/>
@@ -50,15 +50,15 @@
5050
// on: statusStore.lyricIndex === index,
5151
// 当播放时间大于等于当前歌词的开始时间
5252
on:
53-
(playSeek >= item.startTime / 1000 && playSeek < item.endTime / 1000) ||
53+
(playSeek >= item.startTime && playSeek < item.endTime) ||
5454
statusStore.lyricIndex === index,
5555
'is-bg': item.isBG,
5656
'is-duet': item.isDuet,
5757
},
5858
]"
5959
:style="{
6060
filter: settingStore.lyricsBlur
61-
? (playSeek >= item.startTime / 1000 && playSeek < item.endTime / 1000) ||
61+
? (playSeek >= item.startTime && playSeek < item.endTime) ||
6262
statusStore.lyricIndex === index
6363
? 'blur(0)'
6464
: `blur(${Math.min(Math.abs(statusStore.lyricIndex - index) * 1.8, 10)}px)`
@@ -75,8 +75,8 @@
7575
'content-text': true,
7676
'content-long':
7777
settingStore.showYrcLongEffect &&
78-
(text.endTime - item.startTime) / 1000 >= 1.5 &&
79-
playSeek <= text.endTime / 1000,
78+
text.endTime - item.startTime >= 1500 &&
79+
playSeek <= text.endTime,
8080
'end-with-space': text.word.endsWith(' ') || text.startTime === 0,
8181
}"
8282
>
@@ -105,17 +105,14 @@
105105
v-if="
106106
settingStore.countDownShow &&
107107
item.startTime > 0 &&
108-
((musicStore.songLyric.yrcData[index + 1]?.startTime || 0) - item.endTime) /
109-
1000 >=
110-
10
108+
(musicStore.songLyric.yrcData[index + 1]?.startTime || 0) - item.endTime >= 10000
111109
"
112110
class="count-down-content"
113111
>
114112
<CountDown
115-
:start="item.endTime / 1000"
113+
:start="item.endTime"
116114
:duration="
117-
((musicStore.songLyric.yrcData[index + 1]?.startTime || 0) - item.endTime) /
118-
1000
115+
(musicStore.songLyric.yrcData[index + 1]?.startTime || 0) - item.endTime
119116
"
120117
:seek="playSeek"
121118
:playing="statusStore.playStatus"
@@ -130,7 +127,7 @@
130127
<!-- 倒计时 -->
131128
<CountDown
132129
:start="0"
133-
:duration="(musicStore.songLyric.lrcData[0].startTime || 0) / 1000"
130+
:duration="musicStore.songLyric.lrcData[0].startTime || 0"
134131
:seek="playSeek"
135132
:playing="statusStore.playStatus"
136133
/>
@@ -171,12 +168,11 @@
171168
</template>
172169

173170
<script setup lang="ts">
174-
// import type { LyricContentType } from "@/types/main";
175171
import { LyricWord } from "@applemusic-like-lyrics/lyric";
176172
import { NScrollbar } from "naive-ui";
177173
import { useMusicStore, useSettingStore, useStatusStore } from "@/stores";
178174
import player from "@/utils/player";
179-
import { getLyricLanguage } from "@/utils/lyric";
175+
import { getLyricLanguage } from "@/utils/format";
180176
import { isElectron } from "@/utils/env";
181177
import LyricMenu from "./LyricMenu.vue";
182178
@@ -238,14 +234,14 @@ const getYrcStyle = (wordData: LyricWord, lyricIndex: number) => {
238234
239235
// 判断当前行是否处于激活状态
240236
const isLineActive =
241-
(currentSeek >= currentLine.startTime / 1000 && currentSeek < currentLine.endTime / 1000) ||
237+
(currentSeek >= currentLine.startTime && currentSeek < currentLine.endTime) ||
242238
statusStore.lyricIndex === lyricIndex;
243239
244240
// 如果当前歌词行不是激活状态,返回固定样式,避免不必要的计算
245241
if (!isLineActive) {
246242
if (settingStore.showYrcAnimation) {
247243
// 判断单词是否已经唱过:已唱过保持填充状态(0%),未唱到保持未填充状态(100%)
248-
const hasPlayed = currentSeek >= wordData.endTime / 1000;
244+
const hasPlayed = currentSeek >= wordData.endTime;
249245
return {
250246
WebkitMaskPositionX: hasPlayed ? "0%" : "100%",
251247
};
@@ -257,30 +253,28 @@ const getYrcStyle = (wordData: LyricWord, lyricIndex: number) => {
257253
// 激活状态的样式计算
258254
if (settingStore.showYrcAnimation) {
259255
// 如果播放状态不是加载中,且当前单词的时间加上持续时间减去播放进度大于 0
260-
if (statusStore.playLoading === false && wordData.endTime / 1000 - currentSeek > 0) {
256+
if (statusStore.playLoading === false && wordData.endTime - currentSeek > 0) {
261257
return {
262258
transitionDuration: `0s, 0s, 0.35s`,
263259
transitionDelay: `0ms`,
264260
WebkitMaskPositionX: `${
265261
100 -
266262
Math.max(
267-
((currentSeek - wordData.startTime / 1000) /
268-
((wordData.endTime - wordData.startTime) / 1000)) *
269-
100,
263+
((currentSeek - wordData.startTime) / (wordData.endTime - wordData.startTime)) * 100,
270264
0,
271265
)
272266
}%`,
273267
};
274268
}
275269
// 预计算时间差,避免重复计算
276-
const timeDiff = wordData.startTime - currentSeek * 1000;
270+
const timeDiff = wordData.startTime - currentSeek;
277271
return {
278272
transitionDuration: `${wordData.endTime - wordData.startTime}ms, ${(wordData.endTime - wordData.startTime) * 0.8}ms, 0.35s`,
279273
transitionDelay: `${timeDiff}ms, ${timeDiff + (wordData.endTime - wordData.startTime) * 0.5}ms, 0ms`,
280274
};
281275
} else {
282276
// 无动画模式:根据单词时间判断透明度
283-
return statusStore.playLoading === false && wordData.startTime / 1000 >= currentSeek
277+
return statusStore.playLoading === false && wordData.startTime >= currentSeek
284278
? { opacity: 0 }
285279
: { opacity: 1 };
286280
}
@@ -290,8 +284,8 @@ const getYrcStyle = (wordData: LyricWord, lyricIndex: number) => {
290284
const jumpSeek = (time: number) => {
291285
if (!time) return;
292286
lrcMouseStatus.value = false;
293-
const offsetSeconds = statusStore.getSongOffset(musicStore.playSong?.id);
294-
player.setSeek(time / 1000 - offsetSeconds);
287+
const offsetMs = statusStore.getSongOffset(musicStore.playSong?.id);
288+
player.setSeek(time - offsetMs);
295289
player.play();
296290
};
297291

src/components/Player/MainPlayer.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@
161161
vertical
162162
>
163163
<div class="time">
164-
<n-text depth="2">{{ secondsToTime(statusStore.currentTime) }}</n-text>
165-
<n-text depth="2">{{ secondsToTime(statusStore.duration) }}</n-text>
164+
<n-text depth="2">{{ msToTime(statusStore.currentTime) }}</n-text>
165+
<n-text depth="2">{{ msToTime(statusStore.duration) }}</n-text>
166166
</div>
167167
<!-- 定时关闭 -->
168168
<n-tag
@@ -189,7 +189,7 @@
189189
<script setup lang="ts">
190190
import type { DropdownOption } from "naive-ui";
191191
import { useMusicStore, useStatusStore, useDataStore, useSettingStore } from "@/stores";
192-
import { secondsToTime, convertSecondsToTime } from "@/utils/time";
192+
import { msToTime, convertSecondsToTime } from "@/utils/time";
193193
import { renderIcon, coverLoaded } from "@/utils/helper";
194194
import { toLikeSong } from "@/utils/auth";
195195
import {

src/components/Player/PlayerControl.vue

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,9 @@
7676
</div>
7777
<!-- 进度条 -->
7878
<div class="slider">
79-
<span>{{ secondsToTime(statusStore.currentTime) }}</span>
79+
<span>{{ msToTime(statusStore.currentTime) }}</span>
8080
<PlayerSlider :show-tooltip="false" />
81-
<span>{{ secondsToTime(statusStore.duration) }}</span>
81+
<span>{{ msToTime(statusStore.duration) }}</span>
8282
</div>
8383
</div>
8484
<n-flex class="right" align="center" justify="end">
@@ -92,7 +92,7 @@
9292

9393
<script setup lang="ts">
9494
import { useMusicStore, useStatusStore, useDataStore } from "@/stores";
95-
import { secondsToTime } from "@/utils/time";
95+
import { msToTime } from "@/utils/time";
9696
import { openDownloadSong, openPlaylistAdd } from "@/utils/modal";
9797
import { toLikeSong } from "@/utils/auth";
9898
import player from "@/utils/player";

src/components/Player/PlayerSlider.vue

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@
1818

1919
<script setup lang="ts">
2020
import { useStatusStore } from "@/stores";
21+
import { msToTime } from "@/utils/time";
2122
import player from "@/utils/player";
22-
import { secondsToTime } from "@/utils/time";
2323
2424
withDefaults(defineProps<{ showTooltip?: boolean }>(), { showTooltip: true });
2525
@@ -66,7 +66,7 @@ const endDrag = () => {
6666
6767
// 格式化提示
6868
const formatTooltip = (value: number) => {
69-
return `${secondsToTime(value)} / ${secondsToTime(statusStore.duration)}`;
69+
return `${msToTime(value)} / ${msToTime(statusStore.duration)}`;
7070
};
7171
</script>
7272

src/stores/status.ts

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -175,28 +175,42 @@ export const useStatusStore = defineStore("status", {
175175
},
176176
},
177177
actions: {
178-
/** 获取指定歌曲的偏移(默认 0) */
178+
/**
179+
* 获取指定歌曲的偏移
180+
* 单位:毫秒
181+
*/
179182
getSongOffset(songId?: number): number {
180183
if (!songId) return 0;
181-
return this.currentTimeOffsetMap?.[songId] ?? 0;
184+
const offsetTime = this.currentTimeOffsetMap?.[songId] ?? 0;
185+
return Math.floor(offsetTime * 1000);
182186
},
183-
/** 设置指定歌曲的偏移 */
187+
/**
188+
* 设置指定歌曲的偏移
189+
* @param songId 歌曲 id
190+
* @param offset 偏移量(单位:毫秒)
191+
*/
184192
setSongOffset(songId?: number, offset: number = 0) {
185193
if (!songId) return;
186194
if (!this.currentTimeOffsetMap) this.currentTimeOffsetMap = {};
187-
const fixed = Number(offset.toFixed(2));
195+
// 将毫秒转换为秒存储(保留2位小数)
196+
const offsetSeconds = offset / 1000;
197+
const fixed = Number(offsetSeconds.toFixed(2));
188198
if (fixed === 0) {
189199
// 为 0 时移除记录,避免占用空间
190200
delete this.currentTimeOffsetMap[songId];
191201
} else {
192202
this.currentTimeOffsetMap[songId] = fixed;
193203
}
194204
},
195-
/** 调整指定歌曲的偏移(增量) */
196-
incSongOffset(songId?: number, delta: number = 0.5) {
205+
/**
206+
* 调整指定歌曲的偏移(增量)
207+
* @param songId 歌曲 id
208+
* @param delta 偏移增量(单位:毫秒,默认 500ms)
209+
*/
210+
incSongOffset(songId?: number, delta: number = 500) {
197211
if (!songId) return;
198212
const current = this.getSongOffset(songId);
199-
const next = Number((current + delta).toFixed(2));
213+
const next = current + delta;
200214
if (next === 0) {
201215
delete this.currentTimeOffsetMap[songId];
202216
} else {

src/utils/format.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,3 +267,17 @@ const getCoverSizeUrl = (url: string, size: number | null = null) => {
267267
return "/images/song.jpg?assest";
268268
}
269269
};
270+
271+
/**
272+
* 检测歌词语言
273+
* @param lyric 歌词内容
274+
* @returns 语言代码("ja" | "zh-CN" | "en")
275+
*/
276+
export const getLyricLanguage = (lyric: string): string => {
277+
// 判断日语 根据平假名和片假名
278+
if (/[\u3040-\u309f\u30a0-\u30ff]/.test(lyric)) return "ja";
279+
// 判断简体中文 根据中日韩统一表意文字基本区
280+
if (/[\u4e00-\u9fa5]/.test(lyric)) return "zh-CN";
281+
// 默认英语
282+
return "en";
283+
};

0 commit comments

Comments
 (0)