Merge branch 'master' into deploy

This commit is contained in:
qier222 2021-09-25 23:59:50 +08:00
commit 48c0dfe98e
No known key found for this signature in database
GPG key ID: 9C85007ED905F14D
52 changed files with 626 additions and 113 deletions

View file

@ -1,6 +1,12 @@
name: Build / Release name: Build / Release
on: [push, pull_request] on:
push:
branches:
- 'master'
pull_request:
branches:
- '!deploy'
jobs: jobs:
release: release:
@ -8,7 +14,7 @@ jobs:
strategy: strategy:
matrix: matrix:
os: [macos-latest, windows-latest, ubuntu-16.04] os: [macos-latest, windows-latest, ubuntu-18.04]
steps: steps:
- name: Check out Git repository - name: Check out Git repository

View file

@ -0,0 +1,15 @@
// 歌手粉丝
module.exports = (query, request) => {
const data = {
id: query.id,
limit: query.limit || 20,
offset: query.offset || 0,
}
return request('POST', `https://music.163.com/weapi/artist/fans/get`, data, {
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
})
}

View file

@ -0,0 +1,20 @@
module.exports = (query, request) => {
query.cookie.os = 'ios'
query.cookie.appver = '8.1.20'
const data = {
userId: query.uid,
songId: query.sid,
adjustSongId: query.asid,
}
return request(
'POST',
`https://music.163.com/api/cloud/user/song/match`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,18 @@
// 数字专辑详情
module.exports = (query, request) => {
const data = {
id: query.id,
}
return request(
'POST',
`https://music.163.com/weapi/vipmall/albumproduct/detail`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,18 @@
// 数字专辑销量
module.exports = (query, request) => {
const data = {
albumIds: query.ids,
}
return request(
'POST',
`https://music.163.com/weapi/vipmall/albumproduct/album/query/sales`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -4,7 +4,7 @@
module.exports = (query, request) => { module.exports = (query, request) => {
query.cookie.os = 'ios' query.cookie.os = 'ios'
query.cookie.appver = '8.1.20' query.cookie.appver = '8.1.20'
const data = { refresh: query.refresh || true } const data = { refresh: query.refresh || false, cursor: query.cursor }
return request( return request(
'POST', 'POST',
`https://music.163.com/api/homepage/block/page`, `https://music.163.com/api/homepage/block/page`,

View file

@ -4,9 +4,6 @@
// !需要登录或者匿名登录,非登录返回 [] // !需要登录或者匿名登录,非登录返回 []
const config = require('../util/config.json') const config = require('../util/config.json')
module.exports = (query, request) => { module.exports = (query, request) => {
if (typeof query.cookie === 'string') {
query.cookie = cookieToJson(query.cookie)
}
if (!('MUSIC_U' in query.cookie)) if (!('MUSIC_U' in query.cookie))
query.cookie.MUSIC_A = config.anonymous_token query.cookie.MUSIC_A = config.anonymous_token
const data = {} const data = {}

View file

@ -0,0 +1,15 @@
// 一起听状态
module.exports = (query, request) => {
return request(
'POST',
`https://music.163.com/api/listen/together/status/get`,
{},
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -7,9 +7,11 @@ module.exports = async (query, request) => {
const data = { const data = {
phone: query.phone, phone: query.phone,
countrycode: query.countrycode || '86', countrycode: query.countrycode || '86',
password: captcha: query.captcha,
query.md5_password || [query.captcha ? 'captcha' : 'password']: query.captcha
crypto.createHash('md5').update(query.password).digest('hex'), ? query.captcha
: query.md5_password ||
crypto.createHash('md5').update(query.password).digest('hex'),
rememberLogin: 'true', rememberLogin: 'true',
} }
let result = await request( let result = await request(

View file

@ -0,0 +1,23 @@
// 歌曲相关视频
module.exports = (query, request) => {
const data = {
id: query.mvid || 0,
type: 2,
rcmdType: 20,
limit: query.limit || 10,
extInfo: JSON.stringify({ songId: query.songid }),
}
return request(
'POST',
`https://interface.music.163.com/eapi/mlog/rcmd/feed/list`,
data,
{
crypto: 'eapi',
cookie: query.cookie,
proxy: query.proxy,
url: '/api/mlog/rcmd/feed/list',
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,18 @@
// 将mlog id转为video id
module.exports = (query, request) => {
const data = {
mlogId: query.id,
}
return request(
'POST',
`https://music.163.com/weapi/mlog/video/convert/id`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,15 @@
// mlog链接
module.exports = (query, request) => {
const data = {
id: query.id,
resolution: query.res || 1080,
type: 1,
}
return request('POST', `https://music.163.com/weapi/mlog/detail/v1`, data, {
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
})
}

View file

@ -0,0 +1,11 @@
// 账号云豆数
module.exports = (query, request) => {
const data = {}
return request('POST', `https://music.163.com/weapi/cloudbean/get`, data, {
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
})
}

View file

@ -0,0 +1,19 @@
// 领取云豆
module.exports = (query, request) => {
const data = {
userMissionId: query.id,
period: query.period,
}
return request(
'POST',
`https://music.163.com/weapi/nmusician/workbench/mission/reward/obtain/new`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,16 @@
// 音乐人数据概况
module.exports = (query, request) => {
const data = {}
return request(
'POST',
`https://music.163.com/weapi/creator/musician/statistic/data/overview/get`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,19 @@
// 音乐人歌曲播放趋势
module.exports = (query, request) => {
const data = {
startTime: query.startTime,
endTime: query.endTime,
}
return request(
'POST',
`https://music.163.com/weapi/creator/musician/play/count/statistic/data/trend/get`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,16 @@
// 音乐人签到
module.exports = (query, request) => {
const data = {}
return request(
'POST',
`https://music.163.com/weapi/creator/user/access`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,16 @@
// 获取音乐人任务
module.exports = (query, request) => {
const data = {}
return request(
'POST',
`https://music.163.com/weapi/nmusician/workbench/mission/cycle/list`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -1,6 +1,7 @@
// 推荐新歌 // 推荐新歌
module.exports = (query, request) => { module.exports = (query, request) => {
query.cookie.os = 'pc'
const data = { const data = {
type: 'recommend', type: 'recommend',
limit: query.limit || 10, limit: query.limit || 10,
@ -8,7 +9,7 @@ module.exports = (query, request) => {
} }
return request( return request(
'POST', 'POST',
`https://music.163.com/weapi/personalized/newsong`, `https://music.163.com/api/personalized/newsong`,
data, data,
{ {
crypto: 'weapi', crypto: 'weapi',

View file

@ -0,0 +1,20 @@
// 公开隐私歌单
module.exports = (query, request) => {
const data = {
id: query.id,
privacy: 0,
}
return request(
'POST',
`https://interface.music.163.com/eapi/playlist/update/privacy`,
data,
{
crypto: 'eapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
url: '/api/playlist/update/privacy',
},
)
}

View file

@ -13,7 +13,8 @@ module.exports = (query, request) => {
}, },
).then((response) => { ).then((response) => {
try { try {
const pattern = /<div class="cver u-cover u-cover-3">[\s\S]*?<img src="([^"]+)">[\s\S]*?<a class="sname f-fs1 s-fc0" href="([^"]+)"[^>]*>([^<]+?)<\/a>[\s\S]*?<a class="nm nm f-thide s-fc3" href="([^"]+)"[^>]*>([^<]+?)<\/a>/g const pattern =
/<div class="cver u-cover u-cover-3">[\s\S]*?<img src="([^"]+)">[\s\S]*?<a class="sname f-fs1 s-fc0" href="([^"]+)"[^>]*>([^<]+?)<\/a>[\s\S]*?<a class="nm nm f-thide s-fc3" href="([^"]+)"[^>]*>([^<]+?)<\/a>/g
let result, let result,
playlists = [] playlists = []
while ((result = pattern.exec(response.body)) != null) { while ((result = pattern.exec(response.body)) != null) {

View file

@ -1,9 +1,6 @@
// 相似歌手 // 相似歌手
const config = require('../util/config.json') const config = require('../util/config.json')
module.exports = (query, request) => { module.exports = (query, request) => {
if (typeof query.cookie === 'string') {
query.cookie = cookieToJson(query.cookie)
}
if (!('MUSIC_U' in query.cookie)) if (!('MUSIC_U' in query.cookie))
query.cookie.MUSIC_A = config.anonymous_token query.cookie.MUSIC_A = config.anonymous_token
const data = { const data = {

View file

@ -5,7 +5,7 @@ module.exports = (query, request) => {
const data = { const data = {
c: '[' + query.ids.map((id) => '{"id":' + id + '}').join(',') + ']', c: '[' + query.ids.map((id) => '{"id":' + id + '}').join(',') + ']',
} }
return request('POST', `https://music.163.com/weapi/v3/song/detail`, data, { return request('POST', `https://music.163.com/api/v3/song/detail`, data, {
crypto: 'weapi', crypto: 'weapi',
cookie: query.cookie, cookie: query.cookie,
proxy: query.proxy, proxy: query.proxy,

View file

@ -0,0 +1,19 @@
// 已购单曲
module.exports = (query, request) => {
const data = {
limit: query.limit || 20,
offset: query.offset || 0,
}
return request(
'POST',
`https://music.163.com/weapi/single/mybought/song/list`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -1,11 +1,7 @@
// 歌曲链接 // 歌曲链接
const crypto = require('crypto') const crypto = require('crypto')
const { cookieToJson } = require('../util/index')
module.exports = (query, request) => { module.exports = (query, request) => {
if (typeof query.cookie === 'string') {
query.cookie = cookieToJson(query.cookie)
}
if (!('MUSIC_U' in query.cookie)) if (!('MUSIC_U' in query.cookie))
query.cookie._ntes_nuid = crypto.randomBytes(16).toString('hex') query.cookie._ntes_nuid = crypto.randomBytes(16).toString('hex')
query.cookie.os = 'pc' query.cookie.os = 'pc'

View file

@ -0,0 +1,22 @@
module.exports = (query, request) => {
query.cookie.os = 'ios'
query.cookie.appver = '8.1.20'
const data = {
compose_reminder: 'true',
compose_hot_comment: 'true',
limit: query.limit || 10,
user_id: query.uid,
time: query.time || 0,
}
return request(
'POST',
`https://music.163.com/api/comment/user/comment/history`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,16 @@
// 会员成长值
module.exports = (query, request) => {
const data = {}
return request(
'POST',
`https://music.163.com/weapi/vipnewcenter/app/level/growhpoint/basic`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,19 @@
// 会员成长值领取记录
module.exports = (query, request) => {
const data = {
limit: query.limit || 20,
offset: query.offset || 0,
}
return request(
'POST',
`https://music.163.com/weapi/vipnewcenter/app/level/growth/details`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,18 @@
// 领取会员成长值
module.exports = (query, request) => {
const data = {
taskIds: query.ids,
}
return request(
'POST',
`https://music.163.com/weapi/vipnewcenter/app/level/task/reward/get`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,15 @@
// 获取 VIP 信息
module.exports = (query, request) => {
return request(
'POST',
`https://music.163.com/weapi/music-vip-membership/front/vip/info`,
{},
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,16 @@
// 会员任务
module.exports = (query, request) => {
const data = {}
return request(
'POST',
`https://music.163.com/weapi/vipnewcenter/app/level/task/list`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,21 @@
// 云贝推歌
module.exports = (query, request) => {
const data = {
songId: query.id,
reason: query.reason || '好歌献给你',
scene: '',
fromUserId: -1,
}
return request(
'POST',
`https://music.163.com/weapi/yunbei/rcmd/song/submit`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -0,0 +1,21 @@
// 云贝推歌历史记录
module.exports = (query, request) => {
const data = {
page: JSON.stringify({
size: query.size || 20,
cursor: query.cursor || '',
}),
}
return request(
'POST',
`https://music.163.com/weapi/yunbei/rcmd/song/history/list`,
data,
{
crypto: 'weapi',
cookie: query.cookie,
proxy: query.proxy,
realIP: query.realIP,
},
)
}

View file

@ -5,7 +5,7 @@ module.exports = async (query, request) => {
'POST', 'POST',
`https://music.163.com/weapi/nos/token/alloc`, `https://music.163.com/weapi/nos/token/alloc`,
{ {
bucket: '', bucket: 'jd-musicrep-privatecloud-audio-public',
ext: 'mp3', ext: 'mp3',
filename: query.songFile.name.replace('.mp3', ''), filename: query.songFile.name.replace('.mp3', ''),
local: false, local: false,
@ -21,7 +21,7 @@ module.exports = async (query, request) => {
try { try {
await axios({ await axios({
method: 'post', method: 'post',
url: `http://45.127.129.8/ymusic/${objectKey}?offset=0&complete=true&version=1.0`, url: `http://45.127.129.8/jd-musicrep-privatecloud-audio-public/${objectKey}?offset=0&complete=true&version=1.0`,
headers: { headers: {
'x-nos-token': tokenRes.body.result.token, 'x-nos-token': tokenRes.body.result.token,
'Content-MD5': query.songFile.md5, 'Content-MD5': query.songFile.md5,
@ -29,9 +29,12 @@ module.exports = async (query, request) => {
'Content-Length': String(query.songFile.size), 'Content-Length': String(query.songFile.size),
}, },
data: query.songFile.data, data: query.songFile.data,
maxContentLength: Infinity,
maxBodyLength: Infinity,
}) })
} catch (error) { } catch (error) {
console.log('error', error.response) console.log('error', error.response)
throw error.response
} }
return { return {
...tokenRes, ...tokenRes,

View file

@ -1,6 +1,6 @@
{ {
"name": "yesplaymusic", "name": "yesplaymusic",
"version": "0.4.0", "version": "0.4.1",
"private": true, "private": true,
"description": "A third party music player for Netease Music", "description": "A third party music player for Netease Music",
"author": "hawtim<hawtimzhang@gmail.com>", "author": "hawtim<hawtimzhang@gmail.com>",
@ -52,7 +52,7 @@
"express-fileupload": "^1.2.0", "express-fileupload": "^1.2.0",
"express-http-proxy": "^1.6.2", "express-http-proxy": "^1.6.2",
"extract-zip": "^2.0.1", "extract-zip": "^2.0.1",
"howler": "^2.2.1", "howler": "^2.2.3",
"js-cookie": "^2.2.1", "js-cookie": "^2.2.1",
"lodash": "^4.17.20", "lodash": "^4.17.20",
"node-vibrant": "^3.1.6", "node-vibrant": "^3.1.6",

View file

@ -22,9 +22,10 @@ const sign = params => {
}; };
export function auth() { export function auth() {
window.open( const url = process.env.IS_ELECTRON
`https://www.last.fm/api/auth/?api_key=${apiKey}&cb=${baseUrl}/#/lastfm/callback` ? `https://www.last.fm/api/auth/?api_key=${apiKey}&cb=${baseUrl}/#/lastfm/callback`
); : `https://www.last.fm/api/auth/?api_key=${apiKey}&cb=${baseUrl}/lastfm/callback`;
window.open(url);
} }
export function authGetSession(token) { export function authGetSession(token) {

View file

@ -150,6 +150,9 @@ export function uploadSong(file) {
headers: { headers: {
'Content-Type': 'multipart/form-data', 'Content-Type': 'multipart/form-data',
}, },
timeout: 200000,
}).catch(error => {
alert(`上传失败Error: ${error}`);
}); });
} }

View file

@ -26,6 +26,11 @@ const log = text => {
console.log(`${clc.blueBright('[background.js]')} ${text}`); console.log(`${clc.blueBright('[background.js]')} ${text}`);
}; };
const isWindows = process.platform === 'win32';
const isMac = process.platform === 'darwin';
const isLinux = process.platform === 'linux';
const isDevelopment = process.env.NODE_ENV === 'development';
class Background { class Background {
constructor() { constructor() {
this.window = null; this.window = null;
@ -38,7 +43,7 @@ class Background {
}); });
this.neteaseMusicAPI = null; this.neteaseMusicAPI = null;
this.expressApp = null; this.expressApp = null;
this.willQuitApp = process.platform === 'darwin' ? false : true; this.willQuitApp = isMac ? false : true;
this.init(); this.init();
} }
@ -73,7 +78,7 @@ class Background {
} }
// Exit cleanly on request from parent process in development mode. // Exit cleanly on request from parent process in development mode.
if (process.platform === 'win32') { if (isWindows) {
process.on('message', data => { process.on('message', data => {
if (data === 'graceful-exit') { if (data === 'graceful-exit') {
app.quit(); app.quit();
@ -119,7 +124,7 @@ class Background {
minWidth: 1080, minWidth: 1080,
minHeight: 720, minHeight: 720,
titleBarStyle: 'hiddenInset', titleBarStyle: 'hiddenInset',
frame: process.platform !== 'win32', frame: !isWindows,
title: 'YesPlayMusic', title: 'YesPlayMusic',
show: false, show: false,
webPreferences: { webPreferences: {
@ -165,7 +170,7 @@ class Background {
} }
checkForUpdates() { checkForUpdates() {
if (process.env.NODE_ENV === 'development') return; if (isDevelopment) return;
log('checkForUpdates'); log('checkForUpdates');
autoUpdater.checkForUpdatesAndNotify(); autoUpdater.checkForUpdatesAndNotify();
@ -195,20 +200,24 @@ class Background {
handleWindowEvents() { handleWindowEvents() {
this.window.once('ready-to-show', () => { this.window.once('ready-to-show', () => {
log('windows ready-to-show event'); log('window ready-to-show event');
this.window.show(); this.window.show();
}); });
this.window.on('close', e => { this.window.on('close', e => {
log('windows close event'); log('window close event');
if (this.willQuitApp) { let closeOpt = this.store.get('settings.closeAppOption');
if (this.willQuitApp && (closeOpt === 'exit' || closeOpt === 'ask')) {
/* the user tried to quit the app */ /* the user tried to quit the app */
this.window = null; this.window = null;
app.quit(); app.quit();
} else if (!this.willQuitApp && isMac) {
e.preventDefault();
this.window.hide();
} else { } else {
/* the user only tried to close the window */ /* the user only tried to close the window */
e.preventDefault(); e.preventDefault();
this.window.hide(); this.window.minimize();
} }
}); });
@ -222,8 +231,8 @@ class Background {
this.window.on('minimize', () => { this.window.on('minimize', () => {
if ( if (
['win32', 'linux'].includes(process.platform) && !isMac &&
this.store.get('settings.minimizeToTray') this.store.get('settings.closeAppOption') === 'minimizeToTray'
) { ) {
this.window.hide(); this.window.hide();
} }
@ -262,7 +271,7 @@ class Background {
log('app ready event'); log('app ready event');
// for development // for development
if (process.env.NODE_ENV === 'development') { if (isDevelopment) {
this.initDevtools(); this.initDevtools();
} }
@ -291,10 +300,7 @@ class Background {
createMenu(this.window, this.store); createMenu(this.window, this.store);
// create tray // create tray
if ( if (isWindows || isLinux || isDevelopment) {
['win32', 'linux'].includes(process.platform) ||
process.env.NODE_ENV === 'development'
) {
this.tray = createTray(this.window); this.tray = createTray(this.window);
} }
@ -305,7 +311,7 @@ class Background {
this.window.setTouchBar(createTouchBar(this.window)); this.window.setTouchBar(createTouchBar(this.window));
// register global shortcuts // register global shortcuts
if (this.store.get('settings.enableGlobalShortcut')) { if (this.store.get('settings.enableGlobalShortcut') !== false) {
registerGlobalShortcut(this.window, this.store); registerGlobalShortcut(this.window, this.store);
} }
}); });
@ -322,7 +328,7 @@ class Background {
}); });
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
if (process.platform !== 'darwin') { if (!isMac) {
app.quit(); app.quit();
} }
}); });

View file

@ -101,6 +101,7 @@ img {
width: 100%; width: 100%;
user-select: none; user-select: none;
aspect-ratio: 1 / 1; aspect-ratio: 1 / 1;
border: 1px solid rgba(0, 0, 0, 0.04);
} }
.cover-hover { .cover-hover {

View file

@ -86,6 +86,7 @@ export default {
this.getColor(); this.getColor();
}, },
getColor() { getColor() {
if (!this.player.personalFMTrack?.album?.picUrl) return;
const cover = `${this.player.personalFMTrack.album.picUrl.replace( const cover = `${this.player.personalFMTrack.album.picUrl.replace(
'http://', 'http://',
'https://' 'https://'

View file

@ -39,30 +39,21 @@ export function initIpcMain(win, store) {
ipcMain.on('close', e => { ipcMain.on('close', e => {
if (process.platform == 'darwin') { if (process.platform == 'darwin') {
win.hide(); win.hide();
exitAsk(e);
return;
}
let closeOpt = store.get('settings.closeAppOption');
if (closeOpt === 'exit') {
win = null;
//app.quit();
app.exit(); //exit()直接关闭客户端不会执行quit();
} else if (closeOpt === 'minimize' || closeOpt === 'minimizeToTray') {
e.preventDefault(); //阻止默认行为
win.minimize(); //调用 最小化实例方法
} else {
exitAsk(e);
} }
e.preventDefault(); //阻止默认行为
dialog
.showMessageBox({
type: 'info',
title: 'Information',
cancelId: 2,
defaultId: 0,
message: '确定要关闭吗?',
buttons: ['最小化', '直接退出'],
})
.then(result => {
if (result.response == 0) {
e.preventDefault(); //阻止默认行为
win.minimize(); //调用 最小化实例方法
} else if (result.response == 1) {
win = null;
//app.quit();
app.exit(); //exit()直接关闭客户端不会执行quit();
}
})
.catch(err => {
log(err);
});
}); });
ipcMain.on('minimize', () => { ipcMain.on('minimize', () => {
@ -80,6 +71,7 @@ export function initIpcMain(win, store) {
if (options.enableGlobalShortcut) { if (options.enableGlobalShortcut) {
registerGlobalShortcut(win, store); registerGlobalShortcut(win, store);
} else { } else {
log('unregister global shortcut');
globalShortcut.unregisterAll(); globalShortcut.unregisterAll();
} }
}); });
@ -129,6 +121,7 @@ export function initIpcMain(win, store) {
}); });
ipcMain.on('switchGlobalShortcutStatusTemporary', (e, status) => { ipcMain.on('switchGlobalShortcutStatusTemporary', (e, status) => {
log('switchGlobalShortcutStatusTemporary');
if (status === 'disable') { if (status === 'disable') {
globalShortcut.unregisterAll(); globalShortcut.unregisterAll();
} else { } else {
@ -156,4 +149,30 @@ export function initIpcMain(win, store) {
globalShortcut.unregisterAll(); globalShortcut.unregisterAll();
registerGlobalShortcut(win, store); registerGlobalShortcut(win, store);
}); });
const exitAsk = e => {
e.preventDefault(); //阻止默认行为
dialog
.showMessageBox({
type: 'info',
title: 'Information',
cancelId: 2,
defaultId: 0,
message: '确定要关闭吗?',
buttons: ['最小化', '直接退出'],
})
.then(result => {
if (result.response == 0) {
e.preventDefault(); //阻止默认行为
win.minimize(); //调用 最小化实例方法
} else if (result.response == 1) {
win = null;
//app.quit();
app.exit(); //exit()直接关闭客户端不会执行quit();
}
})
.catch(err => {
log(err);
});
};
} }

View file

@ -151,7 +151,6 @@ export default {
clearSongsCache: 'Clear Songs Cache', clearSongsCache: 'Clear Songs Cache',
cacheCount: 'Cached {song} songs ({size})', cacheCount: 'Cached {song} songs ({size})',
showLyricsTranslation: 'Show lyrics translation', showLyricsTranslation: 'Show lyrics translation',
minimizeToTray: 'Minimize to tray',
showPlaylistsByAppleMusic: 'Show playlists by Apple Music', showPlaylistsByAppleMusic: 'Show playlists by Apple Music',
enableDiscordRichPresence: 'Enable Discord Rich Presence', enableDiscordRichPresence: 'Enable Discord Rich Presence',
enableGlobalShortcut: 'Enable Global Shortcut', enableGlobalShortcut: 'Enable Global Shortcut',
@ -162,6 +161,13 @@ export default {
on: 'On', on: 'On',
dynamic: 'Dynamic (High GPU usage)', dynamic: 'Dynamic (High GPU usage)',
}, },
closeAppOption: {
text: 'Close App...',
ask: 'Ask',
exit: 'Exit',
minimize: 'Minimize',
minimizeToTray: 'Minimize to tray',
},
}, },
contextMenu: { contextMenu: {
play: 'Play', play: 'Play',

View file

@ -147,7 +147,6 @@ export default {
clearSongsCache: 'Müzik çerezlerini temizle', clearSongsCache: 'Müzik çerezlerini temizle',
cacheCount: 'Çerezlenen {song} Müzikler ({size})', cacheCount: 'Çerezlenen {song} Müzikler ({size})',
showLyricsTranslation: 'Müzik sözlerinin çevirilerini göster', showLyricsTranslation: 'Müzik sözlerinin çevirilerini göster',
minimizeToTray: 'Küçült',
showPlaylistsByAppleMusic: "Apple Music'in Çalma Listelerini Göster", showPlaylistsByAppleMusic: "Apple Music'in Çalma Listelerini Göster",
enableDiscordRichPresence: 'Discord gösterimini aktifleştir', enableDiscordRichPresence: 'Discord gösterimini aktifleştir',
showLibraryDefault: 'Kitaplık Varsayılanını göster', showLibraryDefault: 'Kitaplık Varsayılanını göster',
@ -157,6 +156,13 @@ export default {
on: 'açık', on: 'açık',
dynamic: 'dinamik(Yüksek GPU kullanımı)', dynamic: 'dinamik(Yüksek GPU kullanımı)',
}, },
closeAppOption: {
text: 'Close App...',
ask: 'Ask',
exit: 'Exit',
minimize: 'Minimize',
minimizeToTray: 'Küçült',
},
}, },
contextMenu: { contextMenu: {
play: 'Oynat', play: 'Oynat',

View file

@ -152,7 +152,6 @@ export default {
clearSongsCache: '清除歌曲缓存', clearSongsCache: '清除歌曲缓存',
cacheCount: '已缓存 {song} 首 ({size})', cacheCount: '已缓存 {song} 首 ({size})',
showLyricsTranslation: '显示歌词翻译', showLyricsTranslation: '显示歌词翻译',
minimizeToTray: '最小化到托盘',
showPlaylistsByAppleMusic: '首页显示来自 Apple Music 的歌单', showPlaylistsByAppleMusic: '首页显示来自 Apple Music 的歌单',
enableDiscordRichPresence: '启用 Discord Rich Presence', enableDiscordRichPresence: '启用 Discord Rich Presence',
enableGlobalShortcut: '启用全局快捷键', enableGlobalShortcut: '启用全局快捷键',
@ -163,6 +162,13 @@ export default {
on: '打开', on: '打开',
dynamic: '动态GPU 占用较高)', dynamic: '动态GPU 占用较高)',
}, },
closeAppOption: {
text: '关闭主面板时...',
ask: '询问',
exit: '退出',
minimize: '最小化',
minimizeToTray: '最小化到托盘',
},
}, },
contextMenu: { contextMenu: {
play: '播放', play: '播放',

View file

@ -159,6 +159,13 @@ export default {
on: '開啟', on: '開啟',
dynamic: '動態GPU 占用較高)', dynamic: '動態GPU 占用較高)',
}, },
closeAppOption: {
text: '關閉主面板時...',
ask: '詢問',
exit: '退出',
minimize: '最小化',
minimizeToTray: '最小化到系統列',
},
}, },
contextMenu: { contextMenu: {
play: '播放', play: '播放',

View file

@ -38,22 +38,26 @@ export default {
} }
let like = true; let like = true;
if (state.liked.songs.includes(id)) like = false; if (state.liked.songs.includes(id)) like = false;
likeATrack({ id, like }).then(() => { likeATrack({ id, like })
if (like === false) { .then(() => {
commit('updateLikedXXX', { if (like === false) {
name: 'songs', commit('updateLikedXXX', {
data: state.liked.songs.filter(d => d !== id), name: 'songs',
}); data: state.liked.songs.filter(d => d !== id),
} else { });
let newLikeSongs = state.liked.songs; } else {
newLikeSongs.push(id); let newLikeSongs = state.liked.songs;
commit('updateLikedXXX', { newLikeSongs.push(id);
name: 'songs', commit('updateLikedXXX', {
data: newLikeSongs, name: 'songs',
}); data: newLikeSongs,
} });
dispatch('fetchLikedSongsWithDetails'); }
}); dispatch('fetchLikedSongsWithDetails');
})
.catch(() => {
dispatch('showToast', '操作失败,专辑下架或版权锁定');
});
}, },
fetchLikedSongs: ({ state, commit }) => { fetchLikedSongs: ({ state, commit }) => {
if (!isLooseLoggedIn()) return; if (!isLooseLoggedIn()) return;
@ -140,7 +144,7 @@ export default {
}, },
fetchLikedMVs: ({ commit }) => { fetchLikedMVs: ({ commit }) => {
if (!isAccountLoggedIn()) return; if (!isAccountLoggedIn()) return;
return likedMVs({ limit: 2000 }).then(result => { return likedMVs({ limit: 1000 }).then(result => {
if (result.data) { if (result.data) {
commit('updateLikedXXX', { commit('updateLikedXXX', {
name: 'mvs', name: 'mvs',

View file

@ -17,12 +17,12 @@ let localStorage = {
outputDevice: 'default', outputDevice: 'default',
showPlaylistsByAppleMusic: true, showPlaylistsByAppleMusic: true,
enableUnblockNeteaseMusic: true, enableUnblockNeteaseMusic: true,
automaticallyCacheSongs: false, automaticallyCacheSongs: true,
cacheLimit: false, cacheLimit: 8192,
nyancatStyle: false, nyancatStyle: false,
showLyricsTranslation: true, showLyricsTranslation: true,
lyricsBackground: true, lyricsBackground: true,
minimizeToTray: false, closeAppOption: 'ask',
enableDiscordRichPresence: false, enableDiscordRichPresence: false,
enableGlobalShortcut: true, enableGlobalShortcut: true,
showLibraryDefault: false, showLibraryDefault: false,

View file

@ -51,6 +51,7 @@ async function deleteExcessCache() {
} }
export function cacheTrackSource(trackInfo, url, bitRate, from = 'netease') { export function cacheTrackSource(trackInfo, url, bitRate, from = 'netease') {
if (!process.env.IS_ELECTRON) return;
const name = trackInfo.name; const name = trackInfo.name;
const artist = const artist =
(trackInfo.ar && trackInfo.ar[0]?.name) || (trackInfo.ar && trackInfo.ar[0]?.name) ||

View file

@ -71,12 +71,25 @@
</div> </div>
</div> </div>
</div> </div>
<TrackList <div v-if="Object.keys(tracksByDisc).length !== 1">
:id="album.id" <div v-for="(disc, cd) in tracksByDisc" :key="cd">
:tracks="tracks" <h2>Disc {{ cd }}</h2>
:type="'album'" <TrackList
:album-object="album" :id="album.id"
/> :tracks="disc"
:type="'album'"
:album-object="album"
/>
</div>
</div>
<div v-else>
<TrackList
:id="album.id"
:tracks="tracks"
:type="'album'"
:album-object="album"
/>
</div>
<div class="extra-info"> <div class="extra-info">
<div class="album-time"></div> <div class="album-time"></div>
<div class="release-date"> <div class="release-date">
@ -137,6 +150,7 @@ import locale from '@/locale';
import { splitSoundtrackAlbumTitle, splitAlbumTitle } from '@/utils/common'; import { splitSoundtrackAlbumTitle, splitAlbumTitle } from '@/utils/common';
import NProgress from 'nprogress'; import NProgress from 'nprogress';
import { isAccountLoggedIn } from '@/utils/auth'; import { isAccountLoggedIn } from '@/utils/auth';
import { groupBy } from 'lodash';
import ExplicitSymbol from '@/components/ExplicitSymbol.vue'; import ExplicitSymbol from '@/components/ExplicitSymbol.vue';
import ButtonTwoTone from '@/components/ButtonTwoTone.vue'; import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
@ -204,6 +218,9 @@ export default {
return [...realAlbums, ...restItems].slice(0, 5); return [...realAlbums, ...restItems].slice(0, 5);
} }
}, },
tracksByDisc() {
return groupBy(this.tracks, 'cd');
},
}, },
created() { created() {
this.loadData(this.$route.params.id); this.loadData(this.$route.params.id);

View file

@ -42,7 +42,7 @@
</div> </div>
</div> </div>
</div> </div>
<div class="latest-release"> <div v-if="latestRelease !== undefined" class="latest-release">
<div class="section-title">{{ $t('artist.latestRelease') }}</div> <div class="section-title">{{ $t('artist.latestRelease') }}</div>
<div class="release"> <div class="release">
<div class="container"> <div class="container">

View file

@ -285,18 +285,23 @@
<h3>其他</h3> <h3>其他</h3>
<div v-if="isElectron && !isMac" class="item"> <div v-if="isElectron && !isMac" class="item">
<div class="left"> <div class="left">
<div class="title">{{ $t('settings.minimizeToTray') }}</div> <div class="title"> {{ $t('settings.closeAppOption.text') }} </div>
</div> </div>
<div class="right"> <div class="right">
<div class="toggle"> <select v-model="closeAppOption">
<input <option value="ask">
id="minimize-to-tray" {{ $t('settings.closeAppOption.ask') }}
v-model="minimizeToTray" </option>
type="checkbox" <option value="exit">
name="minimize-to-tray" {{ $t('settings.closeAppOption.exit') }}
/> </option>
<label for="minimize-to-tray"></label> <option value="minimize">
</div> {{ $t('settings.closeAppOption.minimize') }}
</option>
<option value="minimizeToTray">
{{ $t('settings.closeAppOption.minimizeToTray') }}
</option>
</select>
</div> </div>
</div> </div>
@ -723,13 +728,13 @@ export default {
}); });
}, },
}, },
minimizeToTray: { closeAppOption: {
get() { get() {
return this.settings.minimizeToTray; return this.settings.closeAppOption;
}, },
set(value) { set(value) {
this.$store.commit('updateSettings', { this.$store.commit('updateSettings', {
key: 'minimizeToTray', key: 'closeAppOption',
value, value,
}); });
}, },
@ -973,6 +978,7 @@ export default {
this.recordedShortcut = []; this.recordedShortcut = [];
}, },
exitRecordShortcut() { exitRecordShortcut() {
if (this.shortcutInput.recording === false) return;
this.shortcutInput = { id: '', type: '', recording: false }; this.shortcutInput = { id: '', type: '', recording: false };
this.recordedShortcut = []; this.recordedShortcut = [];
ipcRenderer.send('switchGlobalShortcutStatusTemporary', 'enable'); ipcRenderer.send('switchGlobalShortcutStatusTemporary', 'enable');

View file

@ -6355,10 +6355,10 @@ hosted-git-info@^4.0.1:
dependencies: dependencies:
lru-cache "^6.0.0" lru-cache "^6.0.0"
howler@^2.2.1: howler@^2.2.3:
version "2.2.1" version "2.2.3"
resolved "https://registry.yarnpkg.com/howler/-/howler-2.2.1.tgz#a521a9b495841e8bb9aa12e651bebba0affc179e" resolved "https://registry.yarnpkg.com/howler/-/howler-2.2.3.tgz#a2eff9b08b586798e7a2ee17a602a90df28715da"
integrity sha512-0iIXvuBO/81CcrQ/HSSweYmbT50fT2mIc9XMFb+kxIfk2pW/iKzDbX1n3fZmDXMEIpYvyyfrB+gXwPYSDqUxIQ== integrity sha512-QM0FFkw0LRX1PR8pNzJVAY25JhIWvbKMBFM4gqk+QdV+kPXOhleWGCB6AiAF/goGjIHK2e/nIElplvjQwhr0jg==
hpack.js@^2.1.6: hpack.js@^2.1.6:
version "2.1.6" version "2.1.6"