YesPlayMusic/src/views/settings.vue
2021-06-08 00:37:35 +08:00

1022 lines
32 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<div class="settings-page">
<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">
<option
v-for="device in allOutputDevices"
:key="device.deviceId"
:value="device.deviceId"
:selected="device.deviceId == outputDevice"
>
{{ $t(device.label) }}
</option>
</select>
</div>
</div>
<h3 v-if="isElectron">缓存</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="blur"> 模糊封面 </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 v-if="isElectron" 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 v-if="isElectron" 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 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 v-if="isElectron">
<h3>快捷键</h3>
<div 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>
<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',
},
],
};
},
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() {
const value = this.settings.enableUnblockNeteaseMusic;
return value !== undefined ? value : 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-page {
display: flex;
justify-content: center;
margin-top: 32px;
}
.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>