diff --git a/src/locale/lang/en.js b/src/locale/lang/en.js index cdd5a45..fb4ff63 100644 --- a/src/locale/lang/en.js +++ b/src/locale/lang/en.js @@ -118,6 +118,7 @@ export default { high: "High", lossless: "Lossless", }, + deviceSelector: "Output Device", appearance: { text: "Appearance", auto: "Auto", diff --git a/src/locale/lang/zh-CN.js b/src/locale/lang/zh-CN.js index efd84ce..cb030d7 100644 --- a/src/locale/lang/zh-CN.js +++ b/src/locale/lang/zh-CN.js @@ -119,6 +119,7 @@ export default { high: "极高", lossless: "无损", }, + deviceSelector: "音频输出设备", appearance: { text: "外观", auto: "自动", diff --git a/src/store/initLocalStorage.js b/src/store/initLocalStorage.js index e08997e..3802ed3 100644 --- a/src/store/initLocalStorage.js +++ b/src/store/initLocalStorage.js @@ -7,6 +7,7 @@ let localStorage = { lang: null, appearance: "auto", musicQuality: 320000, + outputDevice: "default", showGithubIcon: true, showPlaylistsByAppleMusic: true, showUnavailableSongInGreyStyle: true, diff --git a/src/store/mutations.js b/src/store/mutations.js index 66a66af..c166d12 100644 --- a/src/store/mutations.js +++ b/src/store/mutations.js @@ -9,6 +9,9 @@ export default { changeMusicQuality(state, value) { state.settings.musicQuality = value; }, + changeOutputDevice(state, deviceId) { + state.settings.outputDevice = deviceId; + }, updateSettings(state, { key, value }) { state.settings[key] = value; }, diff --git a/src/utils/Player.js b/src/utils/Player.js index 9bf98df..db594cf 100644 --- a/src/utils/Player.js +++ b/src/utils/Player.js @@ -102,6 +102,8 @@ export default class { _init() { Howler.autoUnlock = false; + Howler.usingWebAudio = true; + Howler.masterGain = true; this._loadSelfFromLocalStorage(); this._replaceCurrentTrack(this._currentTrack.id, false).then(() => { this._howler.seek(localStorage.getItem("playerCurrentTrackTime") ?? 0); @@ -150,11 +152,27 @@ export default class { time, }); } + _setupAudioNode() { + Howler.masterGain.disconnect(); + const mediaStreamNode = Howler.ctx.createMediaStreamDestination(); + Howler.masterGain.connect(mediaStreamNode); + let audio = ''; + if (document.querySelector('audio') !== null) { + audio = document.querySelector('audio'); + } else { + audio = document.createElement('audio'); + document.body.append(audio); + } + audio.autoplay = true; + audio.srcObject = mediaStreamNode.stream; + audio.setSinkId(store.state.settings.outputDevice); + } _playAudioSource(source, autoplay = true) { Howler.unload(); + this._setupAudioNode(); this._howler = new Howl({ src: [source], - html5: true, + html5: false, format: ["mp3", "flac"], }); if (autoplay) { diff --git a/src/views/playlist.vue b/src/views/playlist.vue index 3aeb948..5f678e3 100644 --- a/src/views/playlist.vue +++ b/src/views/playlist.vue @@ -545,28 +545,6 @@ export default { } } -@media (max-width: 600px) { - .playlist-info { - width: calc(100vw - 2 * var(--main-content-padding-x)); - display: block; - - .cover { - display: flex; - justify-content: center; - align-items: center; - } - - .info { - margin-top: 24px; - margin-left: 0; - - .title { - font-size: 48px; - } - } - } -} - .special-playlist { margin-top: 192px; margin-bottom: 128px; diff --git a/src/views/settings.vue b/src/views/settings.vue index 6432ea2..2084dcd 100644 --- a/src/views/settings.vue +++ b/src/views/settings.vue @@ -74,6 +74,18 @@ +