You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1017 lines
32 KiB

<template>
<div class="settings">
<div class="container">
<div v-if="showUserInfo" class="user">
<div class="left">
<img class="avatar" :src="data.user.avatarUrl" />
<div class="info">
<div class="nickname">{{ data.user.nickname }}</div>
<div class="extra-info">
<span v-if="data.user.vipType !== 0" class="vip"
><img
class="cvip"
src="data:image/png;base64,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"
/>
<span class="text">黑胶VIP</span>
</span>
<span v-else class="text">{{ data.user.signature }}</span>
</div>
</div>
</div>
<div class="right">
<button @click="logout">
<svg-icon icon-class="logout" />
{{ $t('settings.logout') }}
</button>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"> {{ $t('settings.language') }} </div>
</div>
<div class="right">
<select v-model="lang">
<option value="en">🇬🇧 English</option>
<option value="tr">🇹🇷 Türkçe</option>
<option value="zh-CN">🇨🇳 简体中文</option>
</select>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"> {{ $t('settings.appearance.text') }} </div>
</div>
<div class="right">
<select v-model="appearance">
<option value="auto">{{ $t('settings.appearance.auto') }}</option>
<option value="light"
>🌞 {{ $t('settings.appearance.light') }}</option
>
<option value="dark"
>🌚 {{ $t('settings.appearance.dark') }}</option
>
</select>
</div>
</div>
<h3>音质</h3>
<div class="item">
<div class="left">
<div class="title"> {{ $t('settings.musicQuality.text') }} </div>
</div>
<div class="right">
<select v-model="musicQuality">
<option value="128000">
{{ $t('settings.musicQuality.low') }} - 128Kbps
</option>
<option value="192000">
{{ $t('settings.musicQuality.medium') }} - 192Kbps
</option>
<option value="320000">
{{ $t('settings.musicQuality.high') }} - 320Kbps
</option>
<option value="999000">
{{ $t('settings.musicQuality.lossless') }} - FLAC
</option>
</select>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title"> {{ $t('settings.deviceSelector') }} </div>
</div>
<div class="right">
<select v-model="outputDevice" :disabled="withoutAudioPrivilege">
<option
v-for="device in allOutputDevices"
:key="device.deviceId"
:value="device.deviceId"
:selected="device.deviceId == outputDevice"
>
{{ $t(device.label) }}
</option>
</select>
</div>
</div>
<h3>缓存</h3>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title">
{{ $t('settings.automaticallyCacheSongs') }}
</div>
</div>
<div class="right">
<div class="toggle">
<input
id="automatically-cache-songs"
v-model="automaticallyCacheSongs"
type="checkbox"
name="automatically-cache-songs"
/>
<label for="automatically-cache-songs"></label>
</div>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title"> {{ $t('settings.cacheLimit.text') }} </div>
</div>
<div class="right">
<select v-model="cacheLimit">
<option :value="false">
{{ $t('settings.cacheLimit.none') }}
</option>
<option :value="512"> 500MB </option>
<option :value="1024"> 1GB </option>
<option :value="2048"> 2GB </option>
<option :value="4096"> 4GB </option>
</select>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title">
{{
$t('settings.cacheCount', {
song: tracksCache.length,
size: tracksCache.size,
})
}}</div
>
</div>
<div class="right">
<button @click="clearCache()">
{{ $t('settings.clearSongsCache') }}
</button>
</div>
</div>
<h3>歌词</h3>
<div class="item">
<div class="left">
<div class="title">{{ $t('settings.showLyricsTranslation') }}</div>
</div>
<div class="right">
<div class="toggle">
<input
id="show-lyrics-translation"
v-model="showLyricsTranslation"
type="checkbox"
name="show-lyrics-translation"
/>
<label for="show-lyrics-translation"></label>
</div>
</div>
</div>
<div class="item">
<div class="left">
<div class="title">{{ $t('settings.lyricsBackground.text') }}</div>
</div>
<div class="right">
<select v-model="lyricsBackground">
<option :value="false">
{{ $t('settings.lyricsBackground.off') }}
</option>
<option :value="true">
{{ $t('settings.lyricsBackground.on') }}
</option>
<option value="dynamic">
{{ $t('settings.lyricsBackground.dynamic') }}
</option>
</select>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"> {{ $t('settings.lyricFontSize.text') }} </div>
</div>
<div class="right">
<select v-model="lyricFontSize">
<option value="16">
{{ $t('settings.lyricFontSize.small') }} - 16px
</option>
<option value="22">
{{ $t('settings.lyricFontSize.medium') }} - 22px
</option>
<option value="28">
{{ $t('settings.lyricFontSize.large') }} - 28px
</option>
<option value="36">
{{ $t('settings.lyricFontSize.xlarge') }} - 36px
</option>
</select>
</div>
</div>
<h3>第三方</h3>
<div class="item">
<div class="left">
<div class="title">
{{
isLastfmConnected
? `已连接到 Last.fm (${lastfm.name})`
: '连接 Last.fm '
}}</div
>
</div>
<div class="right">
<button v-if="isLastfmConnected" @click="lastfmDisconnect()"
>断开连接
</button>
<button v-else @click="lastfmConnect()"> 授权连接 </button>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"
>启用
<a
href="https://github.com/nondanee/UnblockNeteaseMusic"
target="blank"
>UnblockNeteaseMusic</a
></div
>
</div>
<div class="right">
<div class="toggle">
<input
id="enable-unblock-netease-music"
v-model="enableUnblockNeteaseMusic"
type="checkbox"
name="enable-unblock-netease-music"
/>
<label for="enable-unblock-netease-music"></label>
</div>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title">
{{ $t('settings.enableDiscordRichPresence') }}</div
>
</div>
<div class="right">
<div class="toggle">
<input
id="enable-discord-rich-presence"
v-model="enableDiscordRichPresence"
type="checkbox"
name="enable-discord-rich-presence"
/>
<label for="enable-discord-rich-presence"></label>
</div>
</div>
</div>
<h3>其他</h3>
<div v-if="isElectron && !isMac" class="item">
<div class="left">
<div class="title">{{ $t('settings.minimizeToTray') }}</div>
</div>
<div class="right">
<div class="toggle">
<input
id="minimize-to-tray"
v-model="minimizeToTray"
type="checkbox"
name="minimize-to-tray"
/>
<label for="minimize-to-tray"></label>
</div>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"> {{ $t('settings.showLibraryDefault') }}</div>
</div>
<div class="right">
<div class="toggle">
<input
id="show-library-default"
v-model="showLibraryDefault"
type="checkbox"
name="show-library-default"
/>
<label for="show-library-default"></label>
</div>
</div>
</div>
<div class="item">
<div class="left">
<div class="title">
{{ $t('settings.showPlaylistsByAppleMusic') }}</div
>
</div>
<div class="right">
<div class="toggle">
<input
id="show-playlists-by-apple-music"
v-model="showPlaylistsByAppleMusic"
type="checkbox"
name="show-playlists-by-apple-music"
/>
<label for="show-playlists-by-apple-music"></label>
</div>
</div>
</div>
<div v-if="isElectron" class="item">
<div class="left">
<div class="title"> {{ $t('settings.enableGlobalShortcut') }}</div>
</div>
<div class="right">
<div class="toggle">
<input
id="enable-enable-global-shortcut"
v-model="enableGlobalShortcut"
type="checkbox"
name="enable-enable-global-shortcut"
/>
<label for="enable-enable-global-shortcut"></label>
</div>
</div>
</div>
<div class="item">
<div class="left">
<div class="title" style="transform: scaleX(-1)">🐈️ 🏳️‍🌈</div>
</div>
<div class="right">
<div class="toggle">
<input
id="nyancat-style"
v-model="nyancatStyle"
type="checkbox"
name="nyancat-style"
/>
<label for="nyancat-style"></label>
</div>
</div>
</div>
<div v-if="isElectron">
<h3>代理</h3>
<div class="item">
<div class="left">
<div class="title"> 代理协议 </div>
</div>
<div class="right">
<select v-model="proxyProtocol">
<option value="noProxy"> 关闭代理 </option>
<option value="HTTP"> HTTP 代理 </option>
<option value="HTTPS"> HTTPS 代理 </option>
<option value="SOCKS"> SOCKS 代理 </option>
</select>
</div>
</div>
<div id="proxy-form" :class="{ disabled: proxyProtocol === 'noProxy' }">
<input
v-model="proxyServer"
class="text-input"
placeholder="服务器地址"
:disabled="proxyProtocol === 'noProxy'"
/><input
v-model="proxyPort"
class="text-input"
placeholder="端口"
type="number"
min="1"
max="65535"
:disabled="proxyProtocol === 'noProxy'"
/>
<button @click="sendProxyConfig">更新代理</button>
</div>
</div>
<div class="footer">
<p class="author"
>MADE BY
<a href="http://github.com/qier222" target="_blank">QIER222</a></p
>
<p class="version">v{{ version }}</p>
</div>
</div>
</div>
</template>
<script>
import { mapState, mapActions } from 'vuex';
import { isLooseLoggedIn, doLogout } from '@/utils/auth';
import { auth as lastfmAuth } from '@/api/lastfm';
import { changeAppearance, bytesToSize } from '@/utils/common';
import { countDBSize, clearDB } from '@/utils/db';
import pkg from '../../package.json';
const electron =
process.env.IS_ELECTRON === true ? window.require('electron') : null;
const ipcRenderer =
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
export default {
name: 'Settings',
data() {
return {
tracksCache: {
size: '0KB',
length: 0,
},
allOutputDevices: [
{
deviceId: 'default',
label: 'settings.permissionRequired',
},
],
withoutAudioPrivilege: true,
};
},
computed: {
...mapState(['player', 'settings', 'data', 'lastfm']),
isElectron() {
return process.env.IS_ELECTRON;
},
isMac() {
return /macintosh|mac os x/i.test(navigator.userAgent);
},
version() {
return pkg.version;
},
showUserInfo() {
return isLooseLoggedIn() && this.data.user.nickname;
},
lang: {
get() {
return this.settings.lang;
},
set(lang) {
this.$i18n.locale = lang;
this.$store.commit('changeLang', lang);
},
},
appearance: {
get() {
if (this.settings.appearance === undefined) return 'auto';
return this.settings.appearance;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'appearance',
value,
});
changeAppearance(value);
},
},
musicQuality: {
get() {
if (this.settings.musicQuality === undefined) return 320000;
return this.settings.musicQuality;
},
set(value) {
if (value === this.settings.musicQuality) return;
this.$store.commit('changeMusicQuality', value);
this.clearCache();
},
},
lyricFontSize: {
get() {
if (this.settings.lyricFontSize === undefined) return 28;
return this.settings.lyricFontSize;
},
set(value) {
this.$store.commit('changeLyricFontSize', value);
},
},
outputDevice: {
get() {
const isValidDevice = this.allOutputDevices.find(
device => device.deviceId === this.settings.outputDevice
);
if (
this.settings.outputDevice === undefined ||
isValidDevice === undefined
)
return 'default'; // Default deviceId
return this.settings.outputDevice;
},
set(deviceId) {
if (deviceId === this.settings.outputDevice || deviceId === undefined)
return;
this.$store.commit('changeOutputDevice', deviceId);
this.player.setOutputDevice();
},
},
enableUnblockNeteaseMusic: {
get() {
return this.settings.enableUnblockNeteaseMusic || true;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'enableUnblockNeteaseMusic',
value,
});
},
},
showPlaylistsByAppleMusic: {
get() {
if (this.settings.showPlaylistsByAppleMusic === undefined) return true;
return this.settings.showPlaylistsByAppleMusic;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'showPlaylistsByAppleMusic',
value,
});
},
},
nyancatStyle: {
get() {
if (this.settings.nyancatStyle === undefined) return false;
return this.settings.nyancatStyle;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'nyancatStyle',
value,
});
},
},
automaticallyCacheSongs: {
get() {
if (this.settings.automaticallyCacheSongs === undefined) return false;
return this.settings.automaticallyCacheSongs;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'automaticallyCacheSongs',
value,
});
if (value === false) {
this.clearCache();
}
},
},
showLyricsTranslation: {
get() {
return this.settings.showLyricsTranslation;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'showLyricsTranslation',
value,
});
},
},
lyricsBackground: {
get() {
return this.settings.lyricsBackground || false;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'lyricsBackground',
value,
});
},
},
minimizeToTray: {
get() {
return this.settings.minimizeToTray;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'minimizeToTray',
value,
});
},
},
enableDiscordRichPresence: {
get() {
return this.settings.enableDiscordRichPresence;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'enableDiscordRichPresence',
value,
});
},
},
enableGlobalShortcut: {
get() {
return this.settings.enableGlobalShortcut;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'enableGlobalShortcut',
value,
});
},
},
showLibraryDefault: {
get() {
return this.settings.showLibraryDefault || false;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'showLibraryDefault',
value,
});
},
},
cacheLimit: {
get() {
return this.settings.cacheLimit || false;
},
set(value) {
this.$store.commit('updateSettings', {
key: 'cacheLimit',
value,
});
},
},
proxyProtocol: {
get() {
return this.settings.proxyConfig?.protocol || 'noProxy';
},
set(value) {
let config = this.settings.proxyConfig || {};
config.protocol = value;
if (value === 'noProxy') {
ipcRenderer.send('removeProxy');
this.showToast('已关闭代理');
}
this.$store.commit('updateSettings', {
key: 'proxyConfig',
value: config,
});
},
},
proxyServer: {
get() {
return this.settings.proxyConfig?.server || '';
},
set(value) {
let config = this.settings.proxyConfig || {};
config.server = value;
this.$store.commit('updateSettings', {
key: 'proxyConfig',
value: config,
});
},
},
proxyPort: {
get() {
return this.settings.proxyConfig?.port || '';
},
set(value) {
let config = this.settings.proxyConfig || {};
config.port = value;
this.$store.commit('updateSettings', {
key: 'proxyConfig',
value: config,
});
},
},
isLastfmConnected() {
return this.lastfm.key !== undefined;
},
},
created() {
this.countDBSize('tracks');
if (process.env.IS_ELECTRON) this.getAllOutputDevices();
},
activated() {
this.countDBSize('tracks');
if (process.env.IS_ELECTRON) this.getAllOutputDevices();
},
methods: {
...mapActions(['showToast']),
getAllOutputDevices() {
navigator.mediaDevices.enumerateDevices().then(devices => {
this.allOutputDevices = devices.filter(device => {
return device.kind == 'audiooutput';
});
if (
this.allOutputDevices.length > 0 &&
this.allOutputDevices[0].label !== ''
) {
this.withoutAudioPriviledge = false;
} else {
this.allOutputDevices = [
{
deviceId: 'default',
label: 'settings.permissionRequired',
},
];
}
});
},
logout() {
doLogout();
this.$router.push({ name: 'home' });
},
countDBSize() {
countDBSize().then(data => {
if (data === undefined) {
this.tracksCache = {
size: '0KB',
length: 0,
};
return;
}
this.tracksCache.size = bytesToSize(data.bytes);
this.tracksCache.length = data.length;
});
},
clearCache() {
clearDB().then(() => {
this.countDBSize();
});
},
lastfmConnect() {
lastfmAuth();
let lastfmChecker = setInterval(() => {
const session = localStorage.getItem('lastfm');
if (session) {
this.$store.commit('updateLastfm', JSON.parse(session));
clearInterval(lastfmChecker);
}
}, 1000);
},
lastfmDisconnect() {
localStorage.removeItem('lastfm');
this.$store.commit('updateLastfm', {});
},
sendProxyConfig() {
if (this.proxyProtocol === 'noProxy') return;
const config = this.settings.proxyConfig;
if (
config.server === '' ||
!config.port ||
config.protocol === 'noProxy'
) {
ipcRenderer.send('removeProxy');
} else {
ipcRenderer.send('setProxy', config);
}
this.showToast('已更新代理设置');
},
},
};
</script>
<style lang="scss" scoped>
.settings {
display: flex;
justify-content: center;
}
.container {
margin-top: 24px;
width: 720px;
}
h2 {
margin-top: 48px;
font-size: 36px;
color: var(--color-text);
}
h3 {
margin-top: 48px;
padding-bottom: 12px;
font-size: 26px;
color: var(--color-text);
border-bottom: 1px solid rgba(128, 128, 128, 0.18);
}
.user {
display: flex;
align-items: center;
justify-content: space-between;
background: var(--color-secondary-bg);
color: var(--color-text);
padding: 16px 20px;
border-radius: 16px;
margin-bottom: 48px;
img.avatar {
border-radius: 50%;
height: 64px;
width: 64px;
}
img.cvip {
height: 13px;
margin-right: 4px;
}
.left {
display: flex;
align-items: center;
.info {
margin-left: 24px;
}
.nickname {
font-size: 20px;
font-weight: 600;
margin-bottom: 2px;
}
.extra-info {
font-size: 13px;
.text {
opacity: 0.68;
}
.vip {
display: flex;
align-items: center;
}
}
}
.right {
.svg-icon {
height: 18px;
width: 18px;
margin-right: 4px;
}
button {
display: flex;
align-items: center;
font-size: 18px;
font-weight: 600;
text-decoration: none;
border-radius: 10px;
padding: 8px 12px;
opacity: 0.68;
color: var(--color-text);
transition: 0.2s;
margin: {
right: 12px;
left: 12px;
}
&:hover {
opacity: 1;
background: #eaeffd;
color: #335eea;
}
&:active {
opacity: 1;
transform: scale(0.92);
transition: 0.2s;
}
}
}
}
.item {
margin: 24px 0;
display: flex;
align-items: center;
justify-content: space-between;
color: var(--color-text);
.title {
font-size: 16px;
font-weight: 500;
opacity: 0.78;
}
}
select {
min-width: 192px;
font-weight: 600;
border: none;
padding: 8px 12px 8px 12px;
border-radius: 8px;
color: var(--color-text);
background: var(--color-secondary-bg);
appearance: none;
&:focus {
outline: none;
color: var(--color-primary);
background: var(--color-primary-bg);
}
}
button {
color: var(--color-text);
background: var(--color-secondary-bg);
padding: 8px 12px 8px 12px;
font-weight: 600;
border-radius: 8px;
transition: 0.2s;
&:hover {
transform: scale(1.06);
}
&:active {
transform: scale(0.94);
}
}
input.text-input {
background: var(--color-secondary-bg);
border: none;
margin-right: 22px;
padding: 8px 12px 8px 12px;
border-radius: 8px;
color: var(--color-text);
font-weight: 600;
font-size: 16px;
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
}
input[type='number'] {
-moz-appearance: textfield;
}
#proxy-form {
display: flex;
align-items: center;
}
#proxy-form.disabled {
opacity: 0.47;
button:hover {
transform: unset;
}
}
.footer {
text-align: center;
margin-top: 6rem;
color: var(--color-text);
font-weight: 600;
.author {
font-size: 0.9rem;
}
.version {
font-size: 0.88rem;
opacity: 0.58;
margin-top: -10px;
}
}
.beforeAnimation {
-webkit-transition: 0.2s cubic-bezier(0.24, 0, 0.5, 1);
transition: 0.2s cubic-bezier(0.24, 0, 0.5, 1);
}
.afterAnimation {
box-shadow: 0 0 0 1px hsla(0, 0%, 0%, 0.1), 0 4px 0px 0 hsla(0, 0%, 0%, 0.04),
0 4px 9px hsla(0, 0%, 0%, 0.13), 0 3px 3px hsla(0, 0%, 0%, 0.05);
-webkit-transition: 0.35s cubic-bezier(0.54, 1.6, 0.5, 1);
transition: 0.35s cubic-bezier(0.54, 1.6, 0.5, 1);
}
.toggle {
margin: auto;
}
.toggle input {
opacity: 0;
position: absolute;
}
.toggle input + label {
position: relative;
display: inline-block;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-transition: 0.4s ease;
transition: 0.4s ease;
height: 32px;
width: 52px;
background: var(--color-secondary-bg);
border-radius: 8px;
}
.toggle input + label:before {
content: '';
position: absolute;
display: block;
-webkit-transition: 0.2s cubic-bezier(0.24, 0, 0.5, 1);
transition: 0.2s cubic-bezier(0.24, 0, 0.5, 1);
height: 32px;
width: 52px;
top: 0;
left: 0;
border-radius: 8px;
}
.toggle input + label:after {
content: '';
position: absolute;
display: block;
box-shadow: 0 0 0 1px hsla(0, 0%, 0%, 0.02), 0 4px 0px 0 hsla(0, 0%, 0%, 0.01),
0 4px 9px hsla(0, 0%, 0%, 0.08), 0 3px 3px hsla(0, 0%, 0%, 0.03);
-webkit-transition: 0.35s cubic-bezier(0.54, 1.6, 0.5, 1);
transition: 0.35s cubic-bezier(0.54, 1.6, 0.5, 1);
background: #fff;
height: 20px;
width: 20px;
top: 6px;
left: 6px;
border-radius: 6px;
}
.toggle input:checked + label:before {
background: var(--color-primary);
-webkit-transition: width 0.2s cubic-bezier(0, 0, 0, 0.1);
transition: width 0.2s cubic-bezier(0, 0, 0, 0.1);
}
.toggle input:checked + label:after {
left: 26px;
}
</style>