mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-14 14:50:50 +08:00
@@ -58,7 +58,8 @@ export default {
|
|||||||
next: 'Next',
|
next: 'Next',
|
||||||
volume: 'Volume',
|
volume: 'Volume',
|
||||||
favorite: 'Favorite {name}',
|
favorite: 'Favorite {name}',
|
||||||
unFavorite: 'Unfavorite {name}'
|
unFavorite: 'Unfavorite {name}',
|
||||||
|
playbackSpeed: 'Playback Speed'
|
||||||
},
|
},
|
||||||
eq: {
|
eq: {
|
||||||
title: 'Equalizer',
|
title: 'Equalizer',
|
||||||
|
|||||||
@@ -59,7 +59,8 @@ export default {
|
|||||||
volume: '音量',
|
volume: '音量',
|
||||||
favorite: '已收藏{name}',
|
favorite: '已收藏{name}',
|
||||||
unFavorite: '已取消收藏{name}',
|
unFavorite: '已取消收藏{name}',
|
||||||
miniPlayBar: '迷你播放栏'
|
miniPlayBar: '迷你播放栏',
|
||||||
|
playbackSpeed: '播放速度'
|
||||||
},
|
},
|
||||||
eq: {
|
eq: {
|
||||||
title: '均衡器',
|
title: '均衡器',
|
||||||
|
|||||||
@@ -161,6 +161,23 @@
|
|||||||
</template>
|
</template>
|
||||||
{{ t('player.playBar.playList') }}
|
{{ t('player.playBar.playList') }}
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
|
<!-- 添加播放速度控制按钮 -->
|
||||||
|
<n-dropdown
|
||||||
|
v-if="!isMobile"
|
||||||
|
:options="playbackRateOptions"
|
||||||
|
@select="handlePlaybackRateChange"
|
||||||
|
trigger="click"
|
||||||
|
:z-index="9999999"
|
||||||
|
>
|
||||||
|
<n-tooltip trigger="hover" :z-index="9999999">
|
||||||
|
<template #trigger>
|
||||||
|
<div class="play-speed">
|
||||||
|
<span class="speed-button">{{ playbackRate }}x</span>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
{{ t('player.playBar.playbackSpeed') }}
|
||||||
|
</n-tooltip>
|
||||||
|
</n-dropdown>
|
||||||
</div>
|
</div>
|
||||||
<!-- 播放音乐 -->
|
<!-- 播放音乐 -->
|
||||||
<music-full ref="MusicFullRef" v-model="musicFullVisible" :background="background" />
|
<music-full ref="MusicFullRef" v-model="musicFullVisible" :background="background" />
|
||||||
@@ -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 = () => {
|
const togglePlayMode = () => {
|
||||||
playerStore.togglePlayMode();
|
playerStore.togglePlayMode();
|
||||||
@@ -702,4 +736,24 @@ const openPlayListDrawer = () => {
|
|||||||
color: white;
|
color: white;
|
||||||
animation: spin 1s linear infinite;
|
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);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ class AudioService {
|
|||||||
|
|
||||||
private bypass = false;
|
private bypass = false;
|
||||||
|
|
||||||
|
private playbackRate = 1.0; // 添加播放速度属性
|
||||||
|
|
||||||
// 预设的 EQ 频段
|
// 预设的 EQ 频段
|
||||||
private readonly frequencies = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
|
private readonly frequencies = [31, 62, 125, 250, 500, 1000, 2000, 4000, 8000, 16000];
|
||||||
|
|
||||||
@@ -143,7 +145,7 @@ class AudioService {
|
|||||||
if ('setPositionState' in navigator.mediaSession) {
|
if ('setPositionState' in navigator.mediaSession) {
|
||||||
navigator.mediaSession.setPositionState({
|
navigator.mediaSession.setPositionState({
|
||||||
duration: this.currentSound.duration(),
|
duration: this.currentSound.duration(),
|
||||||
playbackRate: 1.0,
|
playbackRate: this.playbackRate,
|
||||||
position: this.currentSound.seek() as number
|
position: this.currentSound.seek() as number
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -565,6 +567,7 @@ class AudioService {
|
|||||||
volume: localStorage.getItem('volume')
|
volume: localStorage.getItem('volume')
|
||||||
? parseFloat(localStorage.getItem('volume') as string)
|
? parseFloat(localStorage.getItem('volume') as string)
|
||||||
: 1,
|
: 1,
|
||||||
|
rate: this.playbackRate, // 设置初始播放速度
|
||||||
format: ['mp3', 'aac'],
|
format: ['mp3', 'aac'],
|
||||||
onloaderror: (_, error) => {
|
onloaderror: (_, error) => {
|
||||||
console.error('Audio load error:', error);
|
console.error('Audio load error:', error);
|
||||||
@@ -747,6 +750,35 @@ class AudioService {
|
|||||||
public setCurrentPreset(preset: string): void {
|
public setCurrentPreset(preset: string): void {
|
||||||
localStorage.setItem('currentPreset', preset);
|
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();
|
export const audioService = new AudioService();
|
||||||
|
|||||||
@@ -399,6 +399,9 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
value: 0
|
value: 0
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
// 添加播放速度状态
|
||||||
|
const playbackRate = ref(1.0);
|
||||||
|
|
||||||
// 清空播放列表
|
// 清空播放列表
|
||||||
const clearPlayAll = async () => {
|
const clearPlayAll = async () => {
|
||||||
audioService.pause()
|
audioService.pause()
|
||||||
@@ -1042,6 +1045,23 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
setPlayList(newPlayList);
|
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 initializePlayState = async () => {
|
||||||
const settingStore = useSettingsStore();
|
const settingStore = useSettingsStore();
|
||||||
@@ -1093,6 +1113,7 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
localStorage.removeItem('playProgress');
|
localStorage.removeItem('playProgress');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
initializePlaybackRate();
|
||||||
};
|
};
|
||||||
|
|
||||||
const initializeFavoriteList = async () => {
|
const initializeFavoriteList = async () => {
|
||||||
@@ -1343,6 +1364,8 @@ export const usePlayerStore = defineStore('player', () => {
|
|||||||
playAudio,
|
playAudio,
|
||||||
reparseCurrentSong,
|
reparseCurrentSong,
|
||||||
setPlayListDrawerVisible,
|
setPlayListDrawerVisible,
|
||||||
handlePause
|
handlePause,
|
||||||
|
playbackRate,
|
||||||
|
setPlaybackRate
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user