diff --git a/src/i18n/lang/en-US/player.ts b/src/i18n/lang/en-US/player.ts
index 8ec5932..538a97a 100644
--- a/src/i18n/lang/en-US/player.ts
+++ b/src/i18n/lang/en-US/player.ts
@@ -58,7 +58,8 @@ export default {
next: 'Next',
volume: 'Volume',
favorite: 'Favorite {name}',
- unFavorite: 'Unfavorite {name}'
+ unFavorite: 'Unfavorite {name}',
+ playbackSpeed: 'Playback Speed'
},
eq: {
title: 'Equalizer',
diff --git a/src/i18n/lang/zh-CN/player.ts b/src/i18n/lang/zh-CN/player.ts
index bc5296b..b9986da 100644
--- a/src/i18n/lang/zh-CN/player.ts
+++ b/src/i18n/lang/zh-CN/player.ts
@@ -59,7 +59,8 @@ export default {
volume: '音量',
favorite: '已收藏{name}',
unFavorite: '已取消收藏{name}',
- miniPlayBar: '迷你播放栏'
+ miniPlayBar: '迷你播放栏',
+ playbackSpeed: '播放速度'
},
eq: {
title: '均衡器',
diff --git a/src/renderer/components/player/PlayBar.vue b/src/renderer/components/player/PlayBar.vue
index cc2b5f2..cc4fc91 100644
--- a/src/renderer/components/player/PlayBar.vue
+++ b/src/renderer/components/player/PlayBar.vue
@@ -161,6 +161,23 @@
{{ t('player.playBar.playList') }}
+
+
+
+
+
+ {{ playbackRate }}x
+
+
+ {{ t('player.playBar.playbackSpeed') }}
+
+
@@ -319,6 +336,23 @@ const playModeText = computed(() => {
}
});
+// 播放速度控制
+const playbackRate = ref(1.0);
+const playbackRateOptions = [
+ { label: '0.5x', key: 0.5 },
+ { label: '0.75x', key: 0.75 },
+ { label: '1.0x', key: 1.0 },
+ { label: '1.25x', key: 1.25 },
+ { label: '1.5x', key: 1.5 },
+ { label: '2.0x', key: 2.0 }
+];
+
+
+const handlePlaybackRateChange = (rate: number) => {
+ playbackRate.value = rate;
+ audioService.setPlaybackRate(rate);
+};
+
// 切换播放模式
const togglePlayMode = () => {
playerStore.togglePlayMode();
@@ -702,4 +736,24 @@ const openPlayListDrawer = () => {
color: white;
animation: spin 1s linear infinite;
}
+
+.play-speed {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ cursor: pointer;
+ padding: 0 8px;
+}
+
+.speed-button {
+ font-size: 14px;
+ color: var(--text-color);
+ padding: 4px 8px;
+ border-radius: 4px;
+ background: var(--hover-color);
+}
+
+.speed-button:hover {
+ background: var(--hover-color-dark);
+}
diff --git a/src/renderer/services/audioService.ts b/src/renderer/services/audioService.ts
index 585f015..5347c51 100644
--- a/src/renderer/services/audioService.ts
+++ b/src/renderer/services/audioService.ts
@@ -18,6 +18,8 @@ class AudioService {
private bypass = false;
+ private playbackRate = 1.0; // 添加播放速度属性
+
// 预设的 EQ 频段
private readonly frequencies = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
@@ -143,7 +145,7 @@ class AudioService {
if ('setPositionState' in navigator.mediaSession) {
navigator.mediaSession.setPositionState({
duration: this.currentSound.duration(),
- playbackRate: 1.0,
+ playbackRate: this.playbackRate,
position: this.currentSound.seek() as number
});
}
@@ -565,6 +567,7 @@ class AudioService {
volume: localStorage.getItem('volume')
? parseFloat(localStorage.getItem('volume') as string)
: 1,
+ rate: this.playbackRate, // 设置初始播放速度
format: ['mp3', 'aac'],
onloaderror: (_, error) => {
console.error('Audio load error:', error);
@@ -747,6 +750,35 @@ class AudioService {
public setCurrentPreset(preset: string): void {
localStorage.setItem('currentPreset', preset);
}
+
+ public setPlaybackRate(rate: number) {
+ if (!this.currentSound) return;
+ this.playbackRate = rate;
+
+ // Howler 的 rate() 在 html5 模式下不生效
+ this.currentSound.rate(rate);
+
+ // 取出底层 HTMLAudioElement,改原生 playbackRate
+ const sounds = (this.currentSound as any)._sounds as any[];
+ sounds.forEach(({ _node }) => {
+ if (_node instanceof HTMLAudioElement) {
+ _node.playbackRate = rate;
+ }
+ });
+
+ // 同步给 Media Session UI
+ if ('mediaSession' in navigator && 'setPositionState' in navigator.mediaSession) {
+ navigator.mediaSession.setPositionState({
+ duration: this.currentSound.duration(),
+ playbackRate: rate,
+ position: this.currentSound.seek() as number
+ });
+ }
+ }
+
+ public getPlaybackRate(): number {
+ return this.playbackRate;
+ }
}
export const audioService = new AudioService();
diff --git a/src/renderer/store/modules/player.ts b/src/renderer/store/modules/player.ts
index 7994031..852b30d 100644
--- a/src/renderer/store/modules/player.ts
+++ b/src/renderer/store/modules/player.ts
@@ -399,6 +399,9 @@ export const usePlayerStore = defineStore('player', () => {
value: 0
}));
+ // 添加播放速度状态
+ const playbackRate = ref(1.0);
+
// 清空播放列表
const clearPlayAll = async () => {
audioService.pause()
@@ -1042,6 +1045,23 @@ export const usePlayerStore = defineStore('player', () => {
setPlayList(newPlayList);
};
+ // 设置播放速度
+ const setPlaybackRate = (rate: number) => {
+ playbackRate.value = rate;
+ audioService.setPlaybackRate(rate);
+ // 保存到本地存储
+ localStorage.setItem('playbackRate', rate.toString());
+ };
+
+ // 初始化播放速度
+ const initializePlaybackRate = () => {
+ const savedRate = localStorage.getItem('playbackRate');
+ if (savedRate) {
+ playbackRate.value = parseFloat(savedRate);
+ audioService.setPlaybackRate(playbackRate.value);
+ }
+ };
+
// 初始化播放状态
const initializePlayState = async () => {
const settingStore = useSettingsStore();
@@ -1093,6 +1113,7 @@ export const usePlayerStore = defineStore('player', () => {
localStorage.removeItem('playProgress');
}
}
+ initializePlaybackRate();
};
const initializeFavoriteList = async () => {
@@ -1343,6 +1364,8 @@ export const usePlayerStore = defineStore('player', () => {
playAudio,
reparseCurrentSong,
setPlayListDrawerVisible,
- handlePause
+ handlePause,
+ playbackRate,
+ setPlaybackRate
};
});