mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2024-11-22 12:32:07 +08:00
Merge branch 'qier222:master' into revincx-pr
This commit is contained in:
commit
845bc8a921
|
@ -1,6 +1,6 @@
|
|||
VUE_APP_NETEASE_API_URL=/api
|
||||
VUE_APP_ELECTRON_API_URL=/api
|
||||
VUE_APP_ELECTRON_API_URL_DEV=http://127.0.0.1:35216
|
||||
VUE_APP_ELECTRON_API_URL_DEV=http://127.0.0.1:10754
|
||||
VUE_APP_LASTFM_API_KEY=09c55292403d961aa517ff7f5e8a3d9c
|
||||
VUE_APP_LASTFM_API_SHARED_SECRET=307c9fda32b3904e53654baff215cb67
|
||||
DEV_SERVER_PORT=20201
|
||||
|
|
6
.github/workflows/build.yaml
vendored
6
.github/workflows/build.yaml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
|||
|
||||
strategy:
|
||||
matrix:
|
||||
os: [macos-latest, windows-latest, ubuntu-18.04]
|
||||
os: [macos-latest, windows-latest, ubuntu-22.04]
|
||||
|
||||
steps:
|
||||
- name: Check out Git repository
|
||||
|
@ -36,7 +36,7 @@ jobs:
|
|||
run: |
|
||||
sudo apt-get update &&
|
||||
sudo apt-get install --no-install-recommends -y rpm &&
|
||||
sudo apt-get install --no-install-recommends -y bsdtar &&
|
||||
sudo apt-get install --no-install-recommends -y libarchive-tools &&
|
||||
sudo apt-get install --no-install-recommends -y libopenjp2-tools
|
||||
|
||||
- name: Install Snapcraft (on Ubuntu)
|
||||
|
@ -82,7 +82,7 @@ jobs:
|
|||
uses: samuelmeuli/action-electron-builder@v1.6.0
|
||||
env:
|
||||
VUE_APP_ELECTRON_API_URL: /api
|
||||
VUE_APP_ELECTRON_API_URL_DEV: http://127.0.0.1:35216
|
||||
VUE_APP_ELECTRON_API_URL_DEV: http://127.0.0.1:10754
|
||||
VUE_APP_LASTFM_API_KEY: 09c55292403d961aa517ff7f5e8a3d9c
|
||||
VUE_APP_LASTFM_API_SHARED_SECRET: 307c9fda32b3904e53654baff215cb67
|
||||
with:
|
||||
|
|
34
Dockerfile
34
Dockerfile
|
@ -8,41 +8,15 @@ COPY . .
|
|||
RUN yarn build
|
||||
|
||||
FROM nginx:1.20.2-alpine as app
|
||||
RUN echo $'server { \n\
|
||||
gzip on;\n\
|
||||
listen 80; \n\
|
||||
listen [::]:80; \n\
|
||||
server_name localhost; \n\
|
||||
\n\
|
||||
location / { \n\
|
||||
root /usr/share/nginx/html; \n\
|
||||
index index.html; \n\
|
||||
try_files $uri $uri/ /index.html; \n\
|
||||
} \n\
|
||||
\n\
|
||||
location @rewrites { \n\
|
||||
rewrite ^(.*)$ /index.html last; \n\
|
||||
} \n\
|
||||
\n\
|
||||
location /api/ { \n\
|
||||
proxy_buffer_size 128k; \n\
|
||||
proxy_buffers 16 32k; \n\
|
||||
proxy_busy_buffers_size 128k; \n\
|
||||
proxy_set_header Host $host; \n\
|
||||
proxy_set_header X-Real-IP $remote_addr; \n\
|
||||
proxy_set_header X-Forwarded-For $remote_addr; \n\
|
||||
proxy_set_header X-Forwarded-Host $remote_addr; \n\
|
||||
proxy_set_header X-NginX-Proxy true; \n\
|
||||
proxy_pass http://localhost:3000/; \n\
|
||||
} \n\
|
||||
}' > /etc/nginx/conf.d/default.conf
|
||||
|
||||
COPY --from=build /app/package.json /usr/local/lib/
|
||||
|
||||
RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main libuv jq \
|
||||
RUN apk add --no-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main libuv \
|
||||
&& apk add --no-cache --update-cache --repository http://dl-cdn.alpinelinux.org/alpine/v3.14/main nodejs npm \
|
||||
&& npm i -g NeteaseCloudMusicApi@"$(jq -r '.dependencies.NeteaseCloudMusicApi' /usr/local/lib/package.json)"
|
||||
&& npm i -g $(awk -F \" '{if($2=="NeteaseCloudMusicApi") print $2"@"$4}' /usr/local/lib/package.json) \
|
||||
&& rm -f /usr/local/lib/package.json
|
||||
|
||||
COPY --from=build /app/docker/nginx.conf.example /etc/nginx/conf.d/default.conf
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
|
||||
CMD nginx ; exec npx NeteaseCloudMusicApi
|
||||
|
|
2
LICENSE
2
LICENSE
|
@ -1,6 +1,6 @@
|
|||
MIT License
|
||||
|
||||
Copyright (c) 2020-2022 qier222
|
||||
Copyright (c) 2020-2023 qier222
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
|
|
@ -18,6 +18,11 @@
|
|||
|
||||
[![Library][library-screenshot]](https://music.qier222.com)
|
||||
|
||||
|
||||
## 全新版本
|
||||
全新2.0 Alpha测试版已发布,欢迎前往 [Releases](https://github.com/qier222/YesPlayMusic/releases) 页面下载。
|
||||
当前版本将会进入维护模式,除重大bug修复外,不会再更新新功能。
|
||||
|
||||
## ✨ 特性
|
||||
|
||||
- ✅ 使用 Vue.js 全家桶开发
|
||||
|
|
|
@ -4,6 +4,9 @@ services:
|
|||
context: .
|
||||
image: yesplaymusic
|
||||
container_name: YesPlayMusic
|
||||
volumes:
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
- /etc/timezone:/etc/timezone:ro
|
||||
ports:
|
||||
- 80:80
|
||||
restart: always
|
||||
|
|
28
docker/nginx.conf.example
Normal file
28
docker/nginx.conf.example
Normal file
|
@ -0,0 +1,28 @@
|
|||
server {
|
||||
gzip on;
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
location @rewrites {
|
||||
rewrite ^(.*)$ /index.html last;
|
||||
}
|
||||
|
||||
location /api/ {
|
||||
proxy_buffers 16 32k;
|
||||
proxy_buffer_size 128k;
|
||||
proxy_busy_buffers_size 128k;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $remote_addr;
|
||||
proxy_set_header X-Forwarded-Host $remote_addr;
|
||||
proxy_set_header X-NginX-Proxy true;
|
||||
proxy_pass http://localhost:3000/;
|
||||
}
|
||||
}
|
11
package.json
11
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "yesplaymusic",
|
||||
"version": "0.4.5",
|
||||
"version": "0.4.7",
|
||||
"private": true,
|
||||
"description": "A third party music player for Netease Music",
|
||||
"author": "qier222<qier222@outlook.com>",
|
||||
|
@ -22,9 +22,12 @@
|
|||
"netease_api:run": "npx NeteaseCloudMusicApi"
|
||||
},
|
||||
"main": "background.js",
|
||||
"engines": {
|
||||
"node": "14 || 16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@unblockneteasemusic/rust-napi": "^0.3.0-pre.1",
|
||||
"NeteaseCloudMusicApi": "^4.5.2",
|
||||
"@unblockneteasemusic/rust-napi": "^0.4.0",
|
||||
"NeteaseCloudMusicApi": "^4.8.7",
|
||||
"axios": "^0.26.1",
|
||||
"change-case": "^4.1.2",
|
||||
"cli-color": "^2.0.0",
|
||||
|
@ -59,7 +62,6 @@
|
|||
"nprogress": "^0.2.0",
|
||||
"pac-proxy-agent": "^4.1.0",
|
||||
"plyr": "^3.6.2",
|
||||
"prettier": "2.5.1",
|
||||
"qrcode": "^1.4.4",
|
||||
"register-service-worker": "^1.7.1",
|
||||
"svg-sprite-loader": "^6.0.11",
|
||||
|
@ -83,6 +85,7 @@
|
|||
"@vue/cli-service": "~4.5.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"prettier": "2.5.1",
|
||||
"eslint-config-prettier": "^8.1.0",
|
||||
"eslint-plugin-prettier": "^3.3.1",
|
||||
"eslint-plugin-vue": "^7.9.0",
|
||||
|
|
|
@ -67,7 +67,7 @@ const closeOnLinux = (e, win, store) => {
|
|||
win.hide(); //调用 最小化实例方法
|
||||
} else if (result.response === 1) {
|
||||
win = null;
|
||||
app.exit(); // exit()直接关闭客户端,不会执行quit();
|
||||
app.exit(); //exit()直接关闭客户端,不会执行quit();
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
|
@ -154,7 +154,7 @@ class Background {
|
|||
|
||||
const expressApp = express();
|
||||
expressApp.use('/', express.static(__dirname + '/'));
|
||||
expressApp.use('/api', expressProxy('http://127.0.0.1:35216'));
|
||||
expressApp.use('/api', expressProxy('http://127.0.0.1:10754'));
|
||||
expressApp.use('/player', (req, res) => {
|
||||
this.window.webContents
|
||||
.executeJavaScript('window.yesplaymusic.player')
|
||||
|
@ -167,7 +167,7 @@ class Background {
|
|||
});
|
||||
});
|
||||
});
|
||||
this.expressApp = expressApp.listen(41342, '127.0.0.1');
|
||||
this.expressApp = expressApp.listen(27232, '127.0.0.1');
|
||||
}
|
||||
|
||||
createWindow() {
|
||||
|
@ -258,8 +258,8 @@ class Background {
|
|||
createProtocol('app');
|
||||
this.window.loadURL(
|
||||
showLibraryDefault
|
||||
? 'http://localhost:41342/#/library'
|
||||
: 'http://localhost:41342'
|
||||
? 'http://localhost:27232/#/library'
|
||||
: 'http://localhost:27232'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -194,7 +194,7 @@ nav {
|
|||
|
||||
@media (max-width: 1336px) {
|
||||
nav {
|
||||
padding: 0 5vw;
|
||||
padding: 0 max(5vw, 90px);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -187,6 +187,7 @@ import '@/assets/css/slider.css';
|
|||
import ButtonIcon from '@/components/ButtonIcon.vue';
|
||||
import VueSlider from 'vue-slider-component';
|
||||
import { goToListSource, hasListSource } from '@/utils/playList';
|
||||
import { formatTrackTime } from '@/utils/common';
|
||||
|
||||
export default {
|
||||
name: 'Player',
|
||||
|
@ -239,10 +240,7 @@ export default {
|
|||
: this.$router.push({ name: 'next' });
|
||||
},
|
||||
formatTrackTime(value) {
|
||||
if (!value) return '';
|
||||
let min = ~~((value / 60) % 60);
|
||||
let sec = (~~(value % 60)).toString().padStart(2, '0');
|
||||
return `${min}:${sec}`;
|
||||
return formatTrackTime(value);
|
||||
},
|
||||
hasList() {
|
||||
return hasListSource();
|
||||
|
|
|
@ -65,6 +65,7 @@
|
|||
v-for="(track, index) in tracks"
|
||||
:key="itemKey === 'id' ? track.id : `${track.id}${index}`"
|
||||
:track-prop="track"
|
||||
:track-no="index + 1"
|
||||
:highlight-playing-track="highlightPlayingTrack"
|
||||
@dblclick.native="playThisList(track.id || track.songId)"
|
||||
@click.right.native="openMenu($event, track, index)"
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
style="height: 14px; width: 14px"
|
||||
></svg-icon>
|
||||
</button>
|
||||
<span v-show="(!focus || !playable) && !isPlaying">{{ track.no }}</span>
|
||||
<span v-show="(!focus || !playable) && !isPlaying">{{ trackNo }}</span>
|
||||
<button v-show="isPlaying">
|
||||
<svg-icon
|
||||
icon-class="volume"
|
||||
|
@ -96,6 +96,7 @@ export default {
|
|||
|
||||
props: {
|
||||
trackProp: Object,
|
||||
trackNo: Number,
|
||||
highlightPlayingTrack: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
|
|
|
@ -37,6 +37,7 @@ export function createMpris(window) {
|
|||
'xesam:title': metadata.title,
|
||||
'xesam:album': metadata.album,
|
||||
'xesam:artist': metadata.artist.split(','),
|
||||
'xesam:url': metadata.url,
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ export async function startNeteaseMusicApi() {
|
|||
|
||||
// Load the NCM API.
|
||||
await server.serveNcmApi({
|
||||
port: 35216,
|
||||
port: 10754,
|
||||
moduleDefs: require('../ncmModDef'),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -113,6 +113,8 @@ export default {
|
|||
pause: 'Pause',
|
||||
mute: 'Mute',
|
||||
nextUp: 'Next Up',
|
||||
translationLyric: 'lyric (trans)',
|
||||
PronunciationLyric: 'lyric (pronounce)',
|
||||
},
|
||||
modal: {
|
||||
close: 'Close',
|
||||
|
@ -130,6 +132,17 @@ export default {
|
|||
settings: 'Settings',
|
||||
logout: 'LOGOUT',
|
||||
language: 'Languages',
|
||||
lyric: 'Lyric',
|
||||
others: 'Others',
|
||||
customization: 'Customization',
|
||||
MusicGenrePreference: {
|
||||
text: 'Music Language Preference',
|
||||
none: 'No preferences',
|
||||
mandarin: 'Mandarin',
|
||||
western: 'Europe & America',
|
||||
korean: 'Korean',
|
||||
japanese: 'Japanese',
|
||||
},
|
||||
musicQuality: {
|
||||
text: 'Music Quality',
|
||||
low: 'Low',
|
||||
|
|
|
@ -108,6 +108,8 @@ export default {
|
|||
pause: 'Durdur',
|
||||
mute: 'Sesi kapat',
|
||||
nextUp: 'Sıradaki',
|
||||
translationLyric: 'şarkı sözleri (çeviri)',
|
||||
PronunciationLyric: 'şarkı sözleri (çeviri)',
|
||||
},
|
||||
modal: {
|
||||
close: 'Kapat',
|
||||
|
@ -125,6 +127,17 @@ export default {
|
|||
settings: 'Ayarlar',
|
||||
logout: 'ÇIKIŞ YAP',
|
||||
language: 'Diller',
|
||||
lyric: 'Şarkı Sözleri',
|
||||
others: 'Diğerleri',
|
||||
customization: 'Özelleştirme',
|
||||
MusicGenrePreference: {
|
||||
text: 'Müzik Dili Tercihi',
|
||||
none: 'Tercih yok',
|
||||
mandarin: 'Çince dili',
|
||||
western: 'Avrupa ve Amerika',
|
||||
korean: 'Korece',
|
||||
japanese: 'Japonca',
|
||||
},
|
||||
musicQuality: {
|
||||
text: 'Müzik Kalitesi',
|
||||
low: 'Düşük',
|
||||
|
|
|
@ -114,6 +114,8 @@ export default {
|
|||
pause: '暂停',
|
||||
mute: '静音',
|
||||
nextUp: '播放列表',
|
||||
translationLyric: '歌词(译)',
|
||||
PronunciationLyric: '歌词(音)',
|
||||
},
|
||||
modal: {
|
||||
close: '关闭',
|
||||
|
@ -131,6 +133,17 @@ export default {
|
|||
settings: '设置',
|
||||
logout: '登出',
|
||||
language: '语言',
|
||||
lyric: '歌词',
|
||||
others: '其他',
|
||||
customization: '自定义',
|
||||
MusicGenrePreference: {
|
||||
text: '音乐语种偏好',
|
||||
none: '无偏好',
|
||||
mandarin: '华语',
|
||||
western: '欧美',
|
||||
korean: '韩语',
|
||||
japanese: '日语',
|
||||
},
|
||||
musicQuality: {
|
||||
text: '音质选择',
|
||||
low: '普通',
|
||||
|
|
|
@ -110,6 +110,8 @@ export default {
|
|||
pause: '暫停',
|
||||
mute: '靜音',
|
||||
nextUp: '播放清單',
|
||||
translationLyric: '歌詞(譯)',
|
||||
PronunciationLyric: '歌詞(音)',
|
||||
},
|
||||
modal: {
|
||||
close: '關閉',
|
||||
|
@ -127,6 +129,17 @@ export default {
|
|||
settings: '設定',
|
||||
logout: '登出',
|
||||
language: '語言',
|
||||
lyric: '歌詞',
|
||||
others: '其他',
|
||||
customization: '自訂',
|
||||
MusicGenrePreference: {
|
||||
text: '音樂語種偏好',
|
||||
none: '無偏好',
|
||||
mandarin: '華語',
|
||||
western: '歐美',
|
||||
korean: '韓語',
|
||||
japanese: '日語',
|
||||
},
|
||||
musicQuality: {
|
||||
text: '音質選擇',
|
||||
low: '普通',
|
||||
|
|
|
@ -146,7 +146,7 @@ export default class {
|
|||
}
|
||||
set volume(volume) {
|
||||
this._volume = volume;
|
||||
Howler.volume(volume);
|
||||
this._howler?.volume(volume);
|
||||
}
|
||||
get list() {
|
||||
return this.shuffle ? this._shuffledList : this._list;
|
||||
|
@ -207,7 +207,7 @@ export default class {
|
|||
|
||||
_init() {
|
||||
this._loadSelfFromLocalStorage();
|
||||
Howler.volume(this.volume);
|
||||
this._howler?.volume(this.volume);
|
||||
|
||||
if (this._enabled) {
|
||||
// 恢复当前播放歌曲
|
||||
|
@ -338,6 +338,10 @@ export default class {
|
|||
// code 3: MEDIA_ERR_DECODE
|
||||
if (errCode === 3) {
|
||||
this._playNextTrack(this._isPersonalFM);
|
||||
} else if (errCode === 4) {
|
||||
// code 4: MEDIA_ERR_SRC_NOT_SUPPORTED
|
||||
store.dispatch('showToast', `无法播放: 不支持的音频格式`);
|
||||
this._playNextTrack(this._isPersonalFM);
|
||||
} else {
|
||||
const t = this.progress;
|
||||
this._replaceCurrentTrackAudio(this.currentTrack, false, false).then(
|
||||
|
@ -432,12 +436,11 @@ export default class {
|
|||
}
|
||||
};
|
||||
|
||||
/** @type {import("@unblockneteasemusic/rust-napi").RetrievedSongInfo | null} */
|
||||
const retrieveSongInfo = await ipcRenderer.invoke(
|
||||
'unblock-music',
|
||||
store.state.settings.unmSource,
|
||||
track,
|
||||
/** @type {import("@unblockneteasemusic/rust-napi").Context} */ ({
|
||||
{
|
||||
enableFlac: store.state.settings.unmEnableFlac || null,
|
||||
proxyUri: store.state.settings.unmProxyUri || null,
|
||||
searchMode: determineSearchMode(store.state.settings.unmSearchMode),
|
||||
|
@ -446,7 +449,7 @@ export default class {
|
|||
'qq:cookie': store.state.settings.unmQQCookie || null,
|
||||
'ytdl:exe': store.state.settings.unmYtDlExe || null,
|
||||
},
|
||||
})
|
||||
}
|
||||
);
|
||||
|
||||
if (store.state.settings.automaticallyCacheSongs && retrieveSongInfo?.url) {
|
||||
|
@ -612,6 +615,7 @@ export default class {
|
|||
],
|
||||
length: this.currentTrackDuration,
|
||||
trackId: this.current,
|
||||
url: '/trackid/' + track.id,
|
||||
};
|
||||
|
||||
navigator.mediaSession.metadata = new window.MediaMetadata(metadata);
|
||||
|
|
|
@ -221,7 +221,7 @@ export function bytesToSize(bytes) {
|
|||
|
||||
export function formatTrackTime(value) {
|
||||
if (!value) return '';
|
||||
let min = ~~((value / 60) % 60);
|
||||
let min = ~~(value / 60);
|
||||
let sec = (~~(value % 60)).toString().padStart(2, '0');
|
||||
return `${min}:${sec}`;
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ export function lyricParser(lrc) {
|
|||
return {
|
||||
lyric: parseLyric(lrc?.lrc?.lyric || ''),
|
||||
tlyric: parseLyric(lrc?.tlyric?.lyric || ''),
|
||||
romalyric: parseLyric(lrc?.romalrc?.lyric || ''),
|
||||
lyricuser: lrc.lyricUser,
|
||||
transuser: lrc.transUser,
|
||||
};
|
||||
|
|
|
@ -23,7 +23,11 @@ const service = axios.create({
|
|||
service.interceptors.request.use(function (config) {
|
||||
if (!config.params) config.params = {};
|
||||
if (baseURL.length) {
|
||||
if (baseURL[0] !== '/' && !process.env.IS_ELECTRON) {
|
||||
if (
|
||||
baseURL[0] !== '/' &&
|
||||
!process.env.IS_ELECTRON &&
|
||||
getCookie('MUSIC_U') !== null
|
||||
) {
|
||||
config.params.cookie = `MUSIC_U=${getCookie('MUSIC_U')};`;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -96,9 +96,7 @@
|
|||
{{ $t('album.released') }}
|
||||
{{ album.publishTime | formatDate('MMMM D, YYYY') }}
|
||||
</div>
|
||||
<div v-if="album.company !== null" class="copyright">
|
||||
© {{ album.company }}
|
||||
</div>
|
||||
<div v-if="album.company" class="copyright"> © {{ album.company }} </div>
|
||||
</div>
|
||||
<div v-if="filteredMoreAlbums.length !== 0" class="more-by">
|
||||
<div class="section-title">
|
||||
|
|
|
@ -241,7 +241,9 @@ export default {
|
|||
computed: {
|
||||
...mapState(['player']),
|
||||
albums() {
|
||||
return this.albumsData.filter(a => a.type === '专辑');
|
||||
return this.albumsData.filter(
|
||||
a => a.type === '专辑' || a.type === '精选集'
|
||||
);
|
||||
},
|
||||
eps() {
|
||||
return this.albumsData.filter(a =>
|
||||
|
|
|
@ -261,6 +261,8 @@ export default {
|
|||
});
|
||||
},
|
||||
checkQrCodeLogin() {
|
||||
// 清除二维码检测
|
||||
clearInterval(this.qrCodeCheckInterval);
|
||||
this.qrCodeCheckInterval = setInterval(() => {
|
||||
if (this.qrCodeKey === '') return;
|
||||
loginQrCodeCheck(this.qrCodeKey).then(result => {
|
||||
|
@ -275,7 +277,7 @@ export default {
|
|||
clearInterval(this.qrCodeCheckInterval);
|
||||
this.qrCodeInformation = '登录成功,请稍等...';
|
||||
result.code = 200;
|
||||
result.cookie = result.cookie.replace('HTTPOnly', '');
|
||||
result.cookie = result.cookie.replaceAll(' HTTPOnly', '');
|
||||
this.handleLoginResponse(result);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -201,6 +201,28 @@
|
|||
>
|
||||
<svg-icon icon-class="shuffle" />
|
||||
</button-icon>
|
||||
<button-icon
|
||||
v-show="
|
||||
isShowLyricTypeSwitch &&
|
||||
$store.state.settings.showLyricsTranslation &&
|
||||
lyricType === 'translation'
|
||||
"
|
||||
:title="$t('player.translationLyric')"
|
||||
@click.native="switchLyricType"
|
||||
>
|
||||
<span class="lyric-switch-icon">译</span>
|
||||
</button-icon>
|
||||
<button-icon
|
||||
v-show="
|
||||
isShowLyricTypeSwitch &&
|
||||
$store.state.settings.showLyricsTranslation &&
|
||||
lyricType === 'romaPronunciation'
|
||||
"
|
||||
:title="$t('player.PronunciationLyric')"
|
||||
@click.native="switchLyricType"
|
||||
>
|
||||
<span class="lyric-switch-icon">音</span>
|
||||
</button-icon>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -215,7 +237,7 @@
|
|||
>
|
||||
<div id="line-1" class="line"></div>
|
||||
<div
|
||||
v-for="(line, index) in lyricWithTranslation"
|
||||
v-for="(line, index) in lyricToShow"
|
||||
:id="`line${index}`"
|
||||
:key="index"
|
||||
class="line"
|
||||
|
@ -277,6 +299,8 @@ export default {
|
|||
lyricsInterval: null,
|
||||
lyric: [],
|
||||
tlyric: [],
|
||||
romalyric: [],
|
||||
lyricType: 'translation', // or 'romaPronunciation'
|
||||
highlightLyricIndex: -1,
|
||||
minimize: true,
|
||||
background: '',
|
||||
|
@ -302,6 +326,14 @@ export default {
|
|||
bgImageUrl() {
|
||||
return this.player.currentTrack?.al?.picUrl + '?param=512y512';
|
||||
},
|
||||
isShowLyricTypeSwitch() {
|
||||
return this.romalyric.length > 0 && this.tlyric.length > 0;
|
||||
},
|
||||
lyricToShow() {
|
||||
return this.lyricType === 'translation'
|
||||
? this.lyricWithTranslation
|
||||
: this.lyricWithRomaPronunciation;
|
||||
},
|
||||
lyricWithTranslation() {
|
||||
let ret = [];
|
||||
// 空内容的去除
|
||||
|
@ -333,6 +365,37 @@ export default {
|
|||
}
|
||||
return ret;
|
||||
},
|
||||
lyricWithRomaPronunciation() {
|
||||
let ret = [];
|
||||
// 空内容的去除
|
||||
const lyricFiltered = this.lyric.filter(({ content }) =>
|
||||
Boolean(content)
|
||||
);
|
||||
// content统一转换数组形式
|
||||
if (lyricFiltered.length) {
|
||||
lyricFiltered.forEach(l => {
|
||||
const { rawTime, time, content } = l;
|
||||
const lyricItem = { time, content, contents: [content] };
|
||||
const sameTimeRomaLyric = this.romalyric.find(
|
||||
({ rawTime: tLyricRawTime }) => tLyricRawTime === rawTime
|
||||
);
|
||||
if (sameTimeRomaLyric) {
|
||||
const { content: romaLyricContent } = sameTimeRomaLyric;
|
||||
if (content) {
|
||||
lyricItem.contents.push(romaLyricContent);
|
||||
}
|
||||
}
|
||||
ret.push(lyricItem);
|
||||
});
|
||||
} else {
|
||||
ret = lyricFiltered.map(({ time, content }) => ({
|
||||
time,
|
||||
content,
|
||||
contents: [content],
|
||||
}));
|
||||
}
|
||||
return ret;
|
||||
},
|
||||
lyricFontSize() {
|
||||
return {
|
||||
fontSize: `${this.$store.state.settings.lyricFontSize || 28}px`,
|
||||
|
@ -439,9 +502,10 @@ export default {
|
|||
if (!data?.lrc?.lyric) {
|
||||
this.lyric = [];
|
||||
this.tlyric = [];
|
||||
this.romalyric = [];
|
||||
return false;
|
||||
} else {
|
||||
let { lyric, tlyric } = lyricParser(data);
|
||||
let { lyric, tlyric, romalyric } = lyricParser(data);
|
||||
lyric = lyric.filter(
|
||||
l => !/^作(词|曲)\s*(:|:)\s*无$/.exec(l.content)
|
||||
);
|
||||
|
@ -461,15 +525,27 @@ export default {
|
|||
if (lyric.length === 1 && includeAM) {
|
||||
this.lyric = [];
|
||||
this.tlyric = [];
|
||||
this.romalyric = [];
|
||||
return false;
|
||||
} else {
|
||||
this.lyric = lyric;
|
||||
this.tlyric = tlyric;
|
||||
this.romalyric = romalyric;
|
||||
if (tlyric.length * romalyric.length > 0) {
|
||||
this.lyricType = 'translation';
|
||||
} else {
|
||||
this.lyricType =
|
||||
lyric.length > 0 ? 'translation' : 'romaPronunciation';
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
switchLyricType() {
|
||||
this.lyricType =
|
||||
this.lyricType === 'translation' ? 'romaPronunciation' : 'translation';
|
||||
},
|
||||
formatTrackTime(value) {
|
||||
return formatTrackTime(value);
|
||||
},
|
||||
|
@ -758,6 +834,12 @@ export default {
|
|||
width: 22px;
|
||||
}
|
||||
}
|
||||
.lyric-switch-icon {
|
||||
color: var(--color-text);
|
||||
font-size: 14px;
|
||||
line-height: 14px;
|
||||
opacity: 0.88;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,20 +58,32 @@
|
|||
</div>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> 音乐语种偏好 </div>
|
||||
<div class="title">
|
||||
{{ $t('settings.MusicGenrePreference.text') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<select v-model="musicLanguage">
|
||||
<option value="all">无偏好</option>
|
||||
<option value="zh">华语</option>
|
||||
<option value="ea">欧美</option>
|
||||
<option value="jp">日语</option>
|
||||
<option value="kr">韩语</option>
|
||||
<option value="all">{{
|
||||
$t('settings.MusicGenrePreference.none')
|
||||
}}</option>
|
||||
<option value="zh">{{
|
||||
$t('settings.MusicGenrePreference.mandarin')
|
||||
}}</option>
|
||||
<option value="ea">{{
|
||||
$t('settings.MusicGenrePreference.western')
|
||||
}}</option>
|
||||
<option value="jp">{{
|
||||
$t('settings.MusicGenrePreference.japanese')
|
||||
}}</option>
|
||||
<option value="kr">{{
|
||||
$t('settings.MusicGenrePreference.korean')
|
||||
}}</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>音质</h3>
|
||||
<!-- <h3>音质</h3> -->
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t('settings.musicQuality.text') }} </div>
|
||||
|
@ -166,7 +178,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h3>歌词</h3>
|
||||
<h3>{{ $t('settings.lyric') }}</h3>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title">{{ $t('settings.showLyricsTranslation') }}</div>
|
||||
|
@ -433,7 +445,7 @@
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<h3>第三方</h3>
|
||||
<h3>{{ $t('settings.customization') }}</h3>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
|
@ -470,7 +482,7 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h3>其他</h3>
|
||||
<h3>{{ $t('settings.others') }}</h3>
|
||||
<div v-if="isElectron && !isMac" class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t('settings.closeAppOption.text') }} </div>
|
||||
|
|
Loading…
Reference in New Issue
Block a user