mirror of
https://github.com/algerkong/AlgerMusicPlayer.git
synced 2026-04-29 11:27:23 +08:00
Merge pull request #320 from Hellodwadawd12312312/feature
修复音频初始化音量问题,完善翻译
This commit is contained in:
@@ -85,7 +85,7 @@ export default {
|
|||||||
login: 'Login',
|
login: 'Login',
|
||||||
toLogin: 'To Login',
|
toLogin: 'To Login',
|
||||||
logout: 'Logout',
|
logout: 'Logout',
|
||||||
set: 'Set',
|
set: 'Settings',
|
||||||
theme: 'Theme',
|
theme: 'Theme',
|
||||||
restart: 'Restart',
|
restart: 'Restart',
|
||||||
refresh: 'Refresh',
|
refresh: 'Refresh',
|
||||||
@@ -180,5 +180,13 @@ export default {
|
|||||||
clearTasksSuccess: 'Task list cleared',
|
clearTasksSuccess: 'Task list cleared',
|
||||||
clearTasksFailed: 'Failed to clear task list'
|
clearTasksFailed: 'Failed to clear task list'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
settings: 'Settings',
|
||||||
|
user: 'User',
|
||||||
|
toplist: 'Toplist',
|
||||||
|
history: 'History',
|
||||||
|
list: 'Playlist',
|
||||||
|
mv: 'MV',
|
||||||
|
home: 'Home',
|
||||||
|
search: 'Search'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -178,5 +178,13 @@ export default {
|
|||||||
clearTasksSuccess: '任务列表已清除',
|
clearTasksSuccess: '任务列表已清除',
|
||||||
clearTasksFailed: '清除任务列表失败'
|
clearTasksFailed: '清除任务列表失败'
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
settings: '设置',
|
||||||
|
user: '用户',
|
||||||
|
toplist: '排行榜',
|
||||||
|
history: '收藏历史',
|
||||||
|
list: '歌单',
|
||||||
|
mv: 'MV',
|
||||||
|
home: '首页',
|
||||||
|
search: '搜索'
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,11 +13,10 @@
|
|||||||
<template #trigger>
|
<template #trigger>
|
||||||
<router-link class="app-menu-item-link" :to="item.path">
|
<router-link class="app-menu-item-link" :to="item.path">
|
||||||
<i class="iconfont app-menu-item-icon" :style="iconStyle(index)" :class="item.meta.icon"></i>
|
<i class="iconfont app-menu-item-icon" :style="iconStyle(index)" :class="item.meta.icon"></i>
|
||||||
<span v-if="isText" class="app-menu-item-text ml-3" :class="isChecked(index) ? 'text-green-500' : ''">{{
|
<span v-if="isText" class="app-menu-item-text ml-3" :class="isChecked(index) ? 'text-green-500' : ''">{{ t(item.meta.title) }}</span>
|
||||||
item.meta.title }}</span>
|
|
||||||
</router-link>
|
</router-link>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="!isText">{{ item.meta.title }}</div>
|
<div v-if="!isText">{{ t(item.meta.title) }}</div>
|
||||||
</n-tooltip>
|
</n-tooltip>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -28,6 +27,7 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { useRoute } from 'vue-router';
|
import { useRoute } from 'vue-router';
|
||||||
import { ref, watch } from 'vue';
|
import { ref, watch } from 'vue';
|
||||||
|
import { useI18n } from 'vue-i18n';
|
||||||
|
|
||||||
import icon from '@/assets/icon.png';
|
import icon from '@/assets/icon.png';
|
||||||
|
|
||||||
@@ -59,6 +59,8 @@ watch(
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const { t } = useI18n();
|
||||||
|
|
||||||
const isChecked = (index: number) => {
|
const isChecked = (index: number) => {
|
||||||
return path.value === props.menus[index].path;
|
return path.value === props.menus[index].path;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ const layoutRouter = [
|
|||||||
path: '/',
|
path: '/',
|
||||||
name: 'home',
|
name: 'home',
|
||||||
meta: {
|
meta: {
|
||||||
title: '首页',
|
title: 'comp.home',
|
||||||
icon: 'icon-Home',
|
icon: 'icon-Home',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
isMobile: true
|
isMobile: true
|
||||||
@@ -14,7 +14,7 @@ const layoutRouter = [
|
|||||||
path: '/search',
|
path: '/search',
|
||||||
name: 'search',
|
name: 'search',
|
||||||
meta: {
|
meta: {
|
||||||
title: '搜索',
|
title: 'comp.search',
|
||||||
noScroll: true,
|
noScroll: true,
|
||||||
icon: 'icon-Search',
|
icon: 'icon-Search',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
@@ -26,7 +26,7 @@ const layoutRouter = [
|
|||||||
path: '/list',
|
path: '/list',
|
||||||
name: 'list',
|
name: 'list',
|
||||||
meta: {
|
meta: {
|
||||||
title: '歌单',
|
title: 'comp.list',
|
||||||
icon: 'icon-Paper',
|
icon: 'icon-Paper',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
isMobile: true
|
isMobile: true
|
||||||
@@ -37,7 +37,7 @@ const layoutRouter = [
|
|||||||
path: '/toplist',
|
path: '/toplist',
|
||||||
name: 'toplist',
|
name: 'toplist',
|
||||||
meta: {
|
meta: {
|
||||||
title: '排行榜',
|
title: 'comp.toplist',
|
||||||
icon: 'ri-bar-chart-grouped-fill',
|
icon: 'ri-bar-chart-grouped-fill',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
isMobile: true
|
isMobile: true
|
||||||
@@ -48,7 +48,7 @@ const layoutRouter = [
|
|||||||
path: '/mv',
|
path: '/mv',
|
||||||
name: 'mv',
|
name: 'mv',
|
||||||
meta: {
|
meta: {
|
||||||
title: 'MV',
|
title: 'comp.mv',
|
||||||
icon: 'icon-recordfill',
|
icon: 'icon-recordfill',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
isMobile: false
|
isMobile: false
|
||||||
@@ -60,7 +60,7 @@ const layoutRouter = [
|
|||||||
name: 'history',
|
name: 'history',
|
||||||
component: () => import('@/views/historyAndFavorite/index.vue'),
|
component: () => import('@/views/historyAndFavorite/index.vue'),
|
||||||
meta: {
|
meta: {
|
||||||
title: '收藏历史',
|
title: 'comp.history',
|
||||||
icon: 'icon-a-TicketStar',
|
icon: 'icon-a-TicketStar',
|
||||||
keepAlive: true
|
keepAlive: true
|
||||||
}
|
}
|
||||||
@@ -69,7 +69,7 @@ const layoutRouter = [
|
|||||||
path: '/user',
|
path: '/user',
|
||||||
name: 'user',
|
name: 'user',
|
||||||
meta: {
|
meta: {
|
||||||
title: '用户',
|
title: 'comp.user',
|
||||||
icon: 'icon-Profile',
|
icon: 'icon-Profile',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
noScroll: true,
|
noScroll: true,
|
||||||
@@ -81,7 +81,7 @@ const layoutRouter = [
|
|||||||
path: '/set',
|
path: '/set',
|
||||||
name: 'set',
|
name: 'set',
|
||||||
meta: {
|
meta: {
|
||||||
title: '设置',
|
title: 'comp.settings',
|
||||||
icon: 'ri-settings-3-fill',
|
icon: 'ri-settings-3-fill',
|
||||||
keepAlive: true,
|
keepAlive: true,
|
||||||
noScroll: true,
|
noScroll: true,
|
||||||
|
|||||||
@@ -330,15 +330,17 @@ class AudioService {
|
|||||||
// 应用EQ状态
|
// 应用EQ状态
|
||||||
this.applyBypassState();
|
this.applyBypassState();
|
||||||
|
|
||||||
// 设置音量
|
// 从 localStorage 应用音量到增益节点
|
||||||
const volume = localStorage.getItem('volume');
|
const savedVolume = localStorage.getItem('volume');
|
||||||
if (this.gainNode) {
|
if (savedVolume) {
|
||||||
this.gainNode.gain.value = volume ? parseFloat(volume) : 1;
|
this.applyVolume(parseFloat(savedVolume));
|
||||||
|
} else {
|
||||||
|
this.applyVolume(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('EQ初始化成功');
|
console.log('EQ initialization successful');
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('EQ初始化失败:', error);
|
console.error('EQ initialization failed:', error);
|
||||||
await this.disposeEQ();
|
await this.disposeEQ();
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
@@ -563,11 +565,9 @@ class AudioService {
|
|||||||
this.currentSound = new Howl({
|
this.currentSound = new Howl({
|
||||||
src: [url],
|
src: [url],
|
||||||
html5: true,
|
html5: true,
|
||||||
autoplay: false, // 修改为 false,不自动播放,等待完全初始化后手动播放
|
autoplay: false,
|
||||||
volume: localStorage.getItem('volume')
|
volume: 1, // 禁用 Howler.js 音量控制
|
||||||
? parseFloat(localStorage.getItem('volume') as string)
|
rate: this.playbackRate,
|
||||||
: 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);
|
||||||
@@ -596,34 +596,43 @@ class AudioService {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
onload: async () => {
|
onload: async () => {
|
||||||
// 音频加载成功后设置 EQ 和更新媒体会话
|
try {
|
||||||
if (this.currentSound) {
|
// 初始化音频管道
|
||||||
try {
|
await this.setupEQ(this.currentSound!);
|
||||||
if (seekTime > 0) {
|
|
||||||
this.currentSound.seek(seekTime);
|
// 重新应用已保存的音量
|
||||||
}
|
const savedVolume = localStorage.getItem('volume');
|
||||||
console.log('audioService: 音频加载成功,设置 EQ');
|
if (savedVolume) {
|
||||||
await this.setupEQ(this.currentSound);
|
this.applyVolume(parseFloat(savedVolume));
|
||||||
this.updateMediaSessionMetadata(track);
|
|
||||||
this.updateMediaSessionPositionState();
|
|
||||||
this.emit('load');
|
|
||||||
|
|
||||||
// 此时音频已完全初始化,根据 isPlay 参数决定是否播放
|
|
||||||
console.log('audioService: 音频完全初始化,isPlay =', isPlay);
|
|
||||||
if (isPlay) {
|
|
||||||
console.log('audioService: 开始播放');
|
|
||||||
this.currentSound.play();
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(this.currentSound);
|
|
||||||
} catch (error) {
|
|
||||||
console.error('设置 EQ 失败:', error);
|
|
||||||
// 即使 EQ 设置失败,也继续播放(如果需要)
|
|
||||||
if (isPlay) {
|
|
||||||
this.currentSound.play();
|
|
||||||
}
|
|
||||||
resolve(this.currentSound);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 音频加载成功后设置 EQ 和更新媒体会话
|
||||||
|
if (this.currentSound) {
|
||||||
|
try {
|
||||||
|
if (seekTime > 0) {
|
||||||
|
this.currentSound.seek(seekTime);
|
||||||
|
}
|
||||||
|
console.log('audioService: 音频加载成功,设置 EQ');
|
||||||
|
this.updateMediaSessionMetadata(track);
|
||||||
|
this.updateMediaSessionPositionState();
|
||||||
|
this.emit('load');
|
||||||
|
|
||||||
|
// 此时音频已完全初始化,根据 isPlay 参数决定是否播放
|
||||||
|
console.log('audioService: 音频完全初始化,isPlay =', isPlay);
|
||||||
|
if (isPlay) {
|
||||||
|
console.log('audioService: 开始播放');
|
||||||
|
this.currentSound.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(this.currentSound);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Audio initialization failed:', error);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Audio initialization failed:', error);
|
||||||
|
reject(error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -702,10 +711,7 @@ class AudioService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setVolume(volume: number) {
|
setVolume(volume: number) {
|
||||||
if (this.currentSound) {
|
this.applyVolume(volume);
|
||||||
this.currentSound.volume(volume);
|
|
||||||
localStorage.setItem('volume', volume.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
seek(time: number) {
|
seek(time: number) {
|
||||||
@@ -782,6 +788,27 @@ class AudioService {
|
|||||||
public getPlaybackRate(): number {
|
public getPlaybackRate(): number {
|
||||||
return this.playbackRate;
|
return this.playbackRate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新的音量调节方法
|
||||||
|
private applyVolume(volume: number) {
|
||||||
|
// 确保值在0到1之间
|
||||||
|
const normalizedVolume = Math.max(0, Math.min(1, volume));
|
||||||
|
|
||||||
|
// 使用线性缩放音量
|
||||||
|
const linearVolume = normalizedVolume;
|
||||||
|
|
||||||
|
// 将音量应用到所有相关节点
|
||||||
|
if (this.gainNode) {
|
||||||
|
// 立即设置音量
|
||||||
|
this.gainNode.gain.cancelScheduledValues(this.context!.currentTime);
|
||||||
|
this.gainNode.gain.setValueAtTime(linearVolume, this.context!.currentTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存值
|
||||||
|
localStorage.setItem('volume', linearVolume.toString());
|
||||||
|
|
||||||
|
console.log('Volume applied (linear):', linearVolume);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const audioService = new AudioService();
|
export const audioService = new AudioService();
|
||||||
|
|||||||
Reference in New Issue
Block a user