mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-16 13:17:46 +00:00
chore: format codes
This commit is contained in:
parent
6922c716e2
commit
9351f6bc89
73 changed files with 2321 additions and 2321 deletions
|
|
@ -1,15 +1,15 @@
|
|||
// node module
|
||||
const fs = require("fs");
|
||||
const https = require("https");
|
||||
const resolve = require("path").resolve;
|
||||
const join = require("path").resolve;
|
||||
const extract = require("extract-zip");
|
||||
const fs = require('fs');
|
||||
const https = require('https');
|
||||
const resolve = require('path').resolve;
|
||||
const join = require('path').resolve;
|
||||
const extract = require('extract-zip');
|
||||
|
||||
// 函数参数
|
||||
const dest = resolve(__dirname, "../");
|
||||
const fileName = "NeteaseCloudMusicApi-master.zip";
|
||||
const dest = resolve(__dirname, '../');
|
||||
const fileName = 'NeteaseCloudMusicApi-master.zip';
|
||||
const options = {
|
||||
hostname: "github.91chifun.workers.dev",
|
||||
hostname: 'github.91chifun.workers.dev',
|
||||
path: `//https://github.com/Binaryify/NeteaseCloudMusicApi/archive/master.zip`,
|
||||
};
|
||||
|
||||
|
|
@ -27,13 +27,13 @@ function fix2(number) {
|
|||
|
||||
async function download(options, fileName, callback) {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const destPath = join(__dirname, "../" + fileName);
|
||||
const destPath = join(__dirname, '../' + fileName);
|
||||
// Check if exist
|
||||
if (fs.existsSync(destPath)) return resolve(destPath);
|
||||
|
||||
const file = fs.createWriteStream(destPath);
|
||||
const request = https.get(options, (res) => {
|
||||
let len = res.headers && parseInt(res.headers["content-length"], 10);
|
||||
const request = https.get(options, res => {
|
||||
let len = res.headers && parseInt(res.headers['content-length'], 10);
|
||||
let cur = 0;
|
||||
// 1048576 - bytes in 1Megabyte
|
||||
const MEGA = 1048576;
|
||||
|
|
@ -43,10 +43,10 @@ async function download(options, fileName, callback) {
|
|||
}
|
||||
if (!len) {
|
||||
console.log(
|
||||
"Downloading, but can not get content-length, please be patient."
|
||||
'Downloading, but can not get content-length, please be patient.'
|
||||
);
|
||||
}
|
||||
res.on("data", (chunk) => {
|
||||
res.on('data', chunk => {
|
||||
if (len) {
|
||||
cur += chunk.length;
|
||||
console.log(
|
||||
|
|
@ -56,22 +56,22 @@ async function download(options, fileName, callback) {
|
|||
);
|
||||
}
|
||||
});
|
||||
res.on("end", () => {
|
||||
callback("Downloading complete!");
|
||||
res.on('end', () => {
|
||||
callback('Downloading complete!');
|
||||
});
|
||||
res.pipe(file);
|
||||
file.on("finish", () => {
|
||||
file.on('finish', () => {
|
||||
file.close(() => {
|
||||
callback("File wrote complete!");
|
||||
callback('File wrote complete!');
|
||||
resolve(destPath);
|
||||
});
|
||||
});
|
||||
file.on("error", (err) => {
|
||||
file.on('error', err => {
|
||||
fs.unlink(destPath);
|
||||
reject(err);
|
||||
});
|
||||
request.on("error", (err) => {
|
||||
console.log("Error: " + err.message);
|
||||
request.on('error', err => {
|
||||
console.log('Error: ' + err.message);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -82,21 +82,21 @@ async function unzip(source, target) {
|
|||
await extract(source, {
|
||||
dir: target,
|
||||
});
|
||||
console.log("Extraction complete");
|
||||
console.log('Extraction complete');
|
||||
return true;
|
||||
} catch (err) {
|
||||
// handle any errors
|
||||
if (err.message === "end of central directory record signature not found") {
|
||||
console.log("Not a full_downloaded zip file, removed!");
|
||||
if (err.message === 'end of central directory record signature not found') {
|
||||
console.log('Not a full_downloaded zip file, removed!');
|
||||
fs.unlinkSync(source);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
// Download process
|
||||
download(options, fileName, (text) => {
|
||||
download(options, fileName, text => {
|
||||
console.log(text);
|
||||
}).then((path) => {
|
||||
}).then(path => {
|
||||
console.log(path);
|
||||
// Unzip process
|
||||
return unzip(path, dest);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
import request from '@/utils/request';
|
||||
import { mapTrackPlayableStatus } from '@/utils/common';
|
||||
|
||||
/**
|
||||
* 获取专辑内容
|
||||
|
|
@ -8,12 +8,12 @@ import { mapTrackPlayableStatus } from "@/utils/common";
|
|||
*/
|
||||
export function getAlbum(id) {
|
||||
return request({
|
||||
url: "/album",
|
||||
method: "get",
|
||||
url: '/album',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
data.songs = mapTrackPlayableStatus(data.songs);
|
||||
return data;
|
||||
});
|
||||
|
|
@ -32,8 +32,8 @@ export function getAlbum(id) {
|
|||
*/
|
||||
export function newAlbums(params) {
|
||||
return request({
|
||||
url: "/album/new",
|
||||
method: "get",
|
||||
url: '/album/new',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -46,8 +46,8 @@ export function newAlbums(params) {
|
|||
*/
|
||||
export function albumDynamicDetail(id) {
|
||||
return request({
|
||||
url: "/album/detail/dynamic",
|
||||
method: "get",
|
||||
url: '/album/detail/dynamic',
|
||||
method: 'get',
|
||||
params: { id, timestamp: new Date().getTime() },
|
||||
});
|
||||
}
|
||||
|
|
@ -63,8 +63,8 @@ export function albumDynamicDetail(id) {
|
|||
*/
|
||||
export function likeAAlbum(params) {
|
||||
return request({
|
||||
url: "/album/sub",
|
||||
method: "post",
|
||||
url: '/album/sub',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
import request from '@/utils/request';
|
||||
import { mapTrackPlayableStatus } from '@/utils/common';
|
||||
|
||||
/**
|
||||
* 获取歌手单曲
|
||||
|
|
@ -8,13 +8,13 @@ import { mapTrackPlayableStatus } from "@/utils/common";
|
|||
*/
|
||||
export function getArtist(id) {
|
||||
return request({
|
||||
url: "/artists",
|
||||
method: "get",
|
||||
url: '/artists',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
data.hotSongs = mapTrackPlayableStatus(data.hotSongs);
|
||||
return data;
|
||||
});
|
||||
|
|
@ -33,8 +33,8 @@ export function getArtist(id) {
|
|||
*/
|
||||
export function getArtistAlbum(params) {
|
||||
return request({
|
||||
url: "/artist/album",
|
||||
method: "get",
|
||||
url: '/artist/album',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -51,8 +51,8 @@ export function getArtistAlbum(params) {
|
|||
*/
|
||||
export function toplistOfArtists(type = null) {
|
||||
return request({
|
||||
url: "/toplist/artist",
|
||||
method: "get",
|
||||
url: '/toplist/artist',
|
||||
method: 'get',
|
||||
params: {
|
||||
type,
|
||||
},
|
||||
|
|
@ -67,8 +67,8 @@ export function toplistOfArtists(type = null) {
|
|||
*/
|
||||
export function artistMv(params) {
|
||||
return request({
|
||||
url: "/artist/mv",
|
||||
method: "get",
|
||||
url: '/artist/mv',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -84,8 +84,8 @@ export function artistMv(params) {
|
|||
*/
|
||||
export function followAArtist(params) {
|
||||
return request({
|
||||
url: "/artist/sub",
|
||||
method: "post",
|
||||
url: '/artist/sub',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -98,8 +98,8 @@ export function followAArtist(params) {
|
|||
*/
|
||||
export function similarArtists(id) {
|
||||
return request({
|
||||
url: "/simi/artist",
|
||||
method: "post",
|
||||
url: '/simi/artist',
|
||||
method: 'post',
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import request from "@/utils/request";
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 手机登录
|
||||
|
|
@ -14,8 +14,8 @@ import request from "@/utils/request";
|
|||
*/
|
||||
export function loginWithPhone(params) {
|
||||
return request({
|
||||
url: "/login/cellphone",
|
||||
method: "post",
|
||||
url: '/login/cellphone',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -31,8 +31,8 @@ export function loginWithPhone(params) {
|
|||
*/
|
||||
export function loginWithEmail(params) {
|
||||
return request({
|
||||
url: "/login",
|
||||
method: "post",
|
||||
url: '/login',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -44,8 +44,8 @@ export function loginWithEmail(params) {
|
|||
*/
|
||||
export function refreshCookie() {
|
||||
return request({
|
||||
url: "/login/refresh",
|
||||
method: "post",
|
||||
url: '/login/refresh',
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ export function refreshCookie() {
|
|||
*/
|
||||
export function logout() {
|
||||
return request({
|
||||
url: "/logout",
|
||||
method: "post",
|
||||
url: '/logout',
|
||||
method: 'post',
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
// Last.fm API documents 👉 https://www.last.fm/api
|
||||
|
||||
import axios from "axios";
|
||||
import md5 from "crypto-js/md5";
|
||||
import axios from 'axios';
|
||||
import md5 from 'crypto-js/md5';
|
||||
|
||||
const apiKey = process.env.VUE_APP_LASTFM_API_KEY;
|
||||
const apiSharedSecret = process.env.VUE_APP_LASTFM_API_SHARED_SECRET;
|
||||
const baseUrl = window.location.origin;
|
||||
const url = "https://ws.audioscrobbler.com/2.0/";
|
||||
const url = 'https://ws.audioscrobbler.com/2.0/';
|
||||
|
||||
const sign = (params) => {
|
||||
const sign = params => {
|
||||
const sortParamsKeys = Object.keys(params).sort();
|
||||
const sortedParams = sortParamsKeys.reduce((acc, key) => {
|
||||
acc[key] = params[key];
|
||||
return acc;
|
||||
}, {});
|
||||
let signature = "";
|
||||
let signature = '';
|
||||
for (const [key, value] of Object.entries(sortedParams)) {
|
||||
signature += `${key}${value}`;
|
||||
}
|
||||
|
|
@ -33,10 +33,10 @@ export function authGetSession(token) {
|
|||
).toString();
|
||||
return axios({
|
||||
url,
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
params: {
|
||||
method: "auth.getSession",
|
||||
format: "json",
|
||||
method: 'auth.getSession',
|
||||
format: 'json',
|
||||
api_key: apiKey,
|
||||
api_sig: signature,
|
||||
token,
|
||||
|
|
@ -46,34 +46,34 @@ export function authGetSession(token) {
|
|||
|
||||
export function trackUpdateNowPlaying(params) {
|
||||
params.api_key = apiKey;
|
||||
params.method = "track.updateNowPlaying";
|
||||
params.sk = JSON.parse(localStorage.getItem("lastfm"))["key"];
|
||||
params.method = 'track.updateNowPlaying';
|
||||
params.sk = JSON.parse(localStorage.getItem('lastfm'))['key'];
|
||||
const signature = sign(params);
|
||||
|
||||
return axios({
|
||||
url,
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
params: {
|
||||
...params,
|
||||
api_sig: signature,
|
||||
format: "json",
|
||||
format: 'json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function trackScrobble(params) {
|
||||
params.api_key = apiKey;
|
||||
params.method = "track.scrobble";
|
||||
params.sk = JSON.parse(localStorage.getItem("lastfm"))["key"];
|
||||
params.method = 'track.scrobble';
|
||||
params.sk = JSON.parse(localStorage.getItem('lastfm'))['key'];
|
||||
const signature = sign(params);
|
||||
|
||||
return axios({
|
||||
url,
|
||||
method: "POST",
|
||||
method: 'POST',
|
||||
params: {
|
||||
...params,
|
||||
api_sig: signature,
|
||||
format: "json",
|
||||
format: 'json',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import request from "@/utils/request";
|
||||
import request from '@/utils/request';
|
||||
|
||||
/**
|
||||
* 获取 mv 数据
|
||||
|
|
@ -9,8 +9,8 @@ import request from "@/utils/request";
|
|||
*/
|
||||
export function mvDetail(mvid) {
|
||||
return request({
|
||||
url: "/mv/detail",
|
||||
method: "get",
|
||||
url: '/mv/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
mvid,
|
||||
timestamp: new Date().getTime(),
|
||||
|
|
@ -30,8 +30,8 @@ export function mvDetail(mvid) {
|
|||
*/
|
||||
export function mvUrl(params) {
|
||||
return request({
|
||||
url: "/mv/url",
|
||||
method: "get",
|
||||
url: '/mv/url',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -43,8 +43,8 @@ export function mvUrl(params) {
|
|||
*/
|
||||
export function simiMv(mvid) {
|
||||
return request({
|
||||
url: "/simi/mv",
|
||||
method: "get",
|
||||
url: '/simi/mv',
|
||||
method: 'get',
|
||||
params: { mvid },
|
||||
});
|
||||
}
|
||||
|
|
@ -62,8 +62,8 @@ export function simiMv(mvid) {
|
|||
export function likeAMV(params) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/mv/sub",
|
||||
method: "post",
|
||||
url: '/mv/sub',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
import request from '@/utils/request';
|
||||
import { mapTrackPlayableStatus } from '@/utils/common';
|
||||
|
||||
/**
|
||||
* 搜索
|
||||
|
|
@ -18,10 +18,10 @@ import { mapTrackPlayableStatus } from "@/utils/common";
|
|||
*/
|
||||
export function search(params) {
|
||||
return request({
|
||||
url: "/search",
|
||||
method: "get",
|
||||
url: '/search',
|
||||
method: 'get',
|
||||
params,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
if (data.result?.song !== undefined)
|
||||
data.result.song.songs = mapTrackPlayableStatus(data.result.song.songs);
|
||||
return data;
|
||||
|
|
@ -30,8 +30,8 @@ export function search(params) {
|
|||
|
||||
export function personalFM() {
|
||||
return request({
|
||||
url: "/personal_fm",
|
||||
method: "get",
|
||||
url: '/personal_fm',
|
||||
method: 'get',
|
||||
params: {
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
|
|
@ -40,8 +40,8 @@ export function personalFM() {
|
|||
|
||||
export function fmTrash(id) {
|
||||
return request({
|
||||
url: "/fm_trash",
|
||||
method: "post",
|
||||
url: '/fm_trash',
|
||||
method: 'post',
|
||||
params: {
|
||||
timestamp: new Date().getTime(),
|
||||
id,
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
import request from '@/utils/request';
|
||||
import { mapTrackPlayableStatus } from '@/utils/common';
|
||||
|
||||
/**
|
||||
* 推荐歌单
|
||||
|
|
@ -11,8 +11,8 @@ import { mapTrackPlayableStatus } from "@/utils/common";
|
|||
*/
|
||||
export function recommendPlaylist(params) {
|
||||
return request({
|
||||
url: "/personalized",
|
||||
method: "get",
|
||||
url: '/personalized',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -24,8 +24,8 @@ export function recommendPlaylist(params) {
|
|||
*/
|
||||
export function dailyRecommendPlaylist(params) {
|
||||
return request({
|
||||
url: "/recommend/resource",
|
||||
method: "get",
|
||||
url: '/recommend/resource',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -43,10 +43,10 @@ export function getPlaylistDetail(id, noCache = false) {
|
|||
let params = { id };
|
||||
if (noCache) params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/playlist/detail",
|
||||
method: "get",
|
||||
url: '/playlist/detail',
|
||||
method: 'get',
|
||||
params,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
data.playlist.tracks = mapTrackPlayableStatus(
|
||||
data.playlist.tracks,
|
||||
data.privileges || []
|
||||
|
|
@ -67,8 +67,8 @@ export function getPlaylistDetail(id, noCache = false) {
|
|||
*/
|
||||
export function highQualityPlaylist(params) {
|
||||
return request({
|
||||
url: "/top/playlist/highquality",
|
||||
method: "get",
|
||||
url: '/top/playlist/highquality',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -86,8 +86,8 @@ export function highQualityPlaylist(params) {
|
|||
*/
|
||||
export function topPlaylist(params) {
|
||||
return request({
|
||||
url: "/top/playlist",
|
||||
method: "get",
|
||||
url: '/top/playlist',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -98,8 +98,8 @@ export function topPlaylist(params) {
|
|||
*/
|
||||
export function playlistCatlist() {
|
||||
return request({
|
||||
url: "/playlist/catlist",
|
||||
method: "get",
|
||||
url: '/playlist/catlist',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -109,8 +109,8 @@ export function playlistCatlist() {
|
|||
*/
|
||||
export function toplists() {
|
||||
return request({
|
||||
url: "/toplist",
|
||||
method: "get",
|
||||
url: '/toplist',
|
||||
method: 'get',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -126,8 +126,8 @@ export function toplists() {
|
|||
export function subscribePlaylist(params) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/playlist/subscribe",
|
||||
method: "post",
|
||||
url: '/playlist/subscribe',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -140,8 +140,8 @@ export function subscribePlaylist(params) {
|
|||
*/
|
||||
export function deletePlaylist(id) {
|
||||
return request({
|
||||
url: "/playlist/delete",
|
||||
method: "post",
|
||||
url: '/playlist/delete',
|
||||
method: 'post',
|
||||
params: { id },
|
||||
});
|
||||
}
|
||||
|
|
@ -160,8 +160,8 @@ export function deletePlaylist(id) {
|
|||
export function createPlaylist(params) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/playlist/create",
|
||||
method: "post",
|
||||
url: '/playlist/create',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -178,8 +178,8 @@ export function createPlaylist(params) {
|
|||
export function addOrRemoveTrackFromPlaylist(params) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/playlist/tracks",
|
||||
method: "post",
|
||||
url: '/playlist/tracks',
|
||||
method: 'post',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -193,10 +193,10 @@ export function addOrRemoveTrackFromPlaylist(params) {
|
|||
*/
|
||||
export function dailyRecommendTracks() {
|
||||
return request({
|
||||
url: "/recommend/songs",
|
||||
method: "post",
|
||||
url: '/recommend/songs',
|
||||
method: 'post',
|
||||
params: { timestamp: new Date().getTime() },
|
||||
}).then((result) => {
|
||||
}).then(result => {
|
||||
result.data.dailySongs = mapTrackPlayableStatus(
|
||||
result.data.dailySongs,
|
||||
result.data.privileges
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import store from "@/store";
|
||||
import request from "@/utils/request";
|
||||
import { mapTrackPlayableStatus } from "@/utils/common";
|
||||
import store from '@/store';
|
||||
import request from '@/utils/request';
|
||||
import { mapTrackPlayableStatus } from '@/utils/common';
|
||||
/**
|
||||
* 获取音乐 url
|
||||
* 说明 : 使用歌单详情接口后 , 能得到的音乐的 id, 但不能得到的音乐 url, 调用此接口, 传入的音乐 id( 可多个 , 用逗号隔开 ), 可以获取对应的音乐的 url,
|
||||
|
|
@ -13,8 +13,8 @@ export function getMP3(id) {
|
|||
? store.state.settings.musicQuality
|
||||
: 320000;
|
||||
return request({
|
||||
url: "/song/url",
|
||||
method: "get",
|
||||
url: '/song/url',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
br,
|
||||
|
|
@ -28,12 +28,12 @@ export function getMP3(id) {
|
|||
*/
|
||||
export function getTrackDetail(ids) {
|
||||
return request({
|
||||
url: "/song/detail",
|
||||
method: "get",
|
||||
url: '/song/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
ids,
|
||||
},
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
data.songs = mapTrackPlayableStatus(data.songs, data.privileges);
|
||||
return data;
|
||||
});
|
||||
|
|
@ -46,8 +46,8 @@ export function getTrackDetail(ids) {
|
|||
|
||||
export function getLyric(id) {
|
||||
return request({
|
||||
url: "/lyric",
|
||||
method: "get",
|
||||
url: '/lyric',
|
||||
method: 'get',
|
||||
params: {
|
||||
id,
|
||||
},
|
||||
|
|
@ -60,8 +60,8 @@ export function getLyric(id) {
|
|||
*/
|
||||
export function topSong(type) {
|
||||
return request({
|
||||
url: "/top/song",
|
||||
method: "get",
|
||||
url: '/top/song',
|
||||
method: 'get',
|
||||
params: {
|
||||
type,
|
||||
},
|
||||
|
|
@ -79,8 +79,8 @@ export function topSong(type) {
|
|||
export function likeATrack(params) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/like",
|
||||
method: "get",
|
||||
url: '/like',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
@ -99,8 +99,8 @@ export function likeATrack(params) {
|
|||
export function scrobble(params) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: "/scrobble",
|
||||
method: "get",
|
||||
url: '/scrobble',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -265,17 +265,17 @@ a.plyr__control::before {
|
|||
display: none;
|
||||
}
|
||||
|
||||
.plyr [data-plyr="airplay"],
|
||||
.plyr [data-plyr="captions"],
|
||||
.plyr [data-plyr="fullscreen"],
|
||||
.plyr [data-plyr="pip"] {
|
||||
.plyr [data-plyr='airplay'],
|
||||
.plyr [data-plyr='captions'],
|
||||
.plyr [data-plyr='fullscreen'],
|
||||
.plyr [data-plyr='pip'] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.plyr--airplay-supported [data-plyr="airplay"],
|
||||
.plyr--captions-enabled [data-plyr="captions"],
|
||||
.plyr--fullscreen-enabled [data-plyr="fullscreen"],
|
||||
.plyr--pip-supported [data-plyr="pip"] {
|
||||
.plyr--airplay-supported [data-plyr='airplay'],
|
||||
.plyr--captions-enabled [data-plyr='captions'],
|
||||
.plyr--fullscreen-enabled [data-plyr='fullscreen'],
|
||||
.plyr--pip-supported [data-plyr='pip'] {
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
|
|
@ -288,11 +288,11 @@ a.plyr__control::before {
|
|||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.plyr__menu .plyr__control[aria-expanded="true"] svg {
|
||||
.plyr__menu .plyr__control[aria-expanded='true'] svg {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.plyr__menu .plyr__control[aria-expanded="true"] .plyr__tooltip {
|
||||
.plyr__menu .plyr__control[aria-expanded='true'] .plyr__tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
|
@ -327,7 +327,7 @@ a.plyr__control::before {
|
|||
border: var(--plyr-menu-arrow-size, 4px) solid transparent;
|
||||
border-top-color: rgba(255, 255, 255, 0.9);
|
||||
border-top-color: var(--plyr-menu-background, rgba(255, 255, 255, 0.9));
|
||||
content: "";
|
||||
content: '';
|
||||
height: 0;
|
||||
position: absolute;
|
||||
right: calc(((18px / 2) + calc(10px * 0.7)) - (4px / 2));
|
||||
|
|
@ -341,18 +341,18 @@ a.plyr__control::before {
|
|||
width: 0;
|
||||
}
|
||||
|
||||
.plyr__menu__container [role="menu"] {
|
||||
.plyr__menu__container [role='menu'] {
|
||||
padding: calc(10px * 0.7);
|
||||
padding: calc(var(--plyr-control-spacing, 10px) * 0.7);
|
||||
}
|
||||
|
||||
.plyr__menu__container [role="menuitem"],
|
||||
.plyr__menu__container [role="menuitemradio"] {
|
||||
.plyr__menu__container [role='menuitem'],
|
||||
.plyr__menu__container [role='menuitemradio'] {
|
||||
margin-top: 2px;
|
||||
}
|
||||
|
||||
.plyr__menu__container [role="menuitem"]:first-child,
|
||||
.plyr__menu__container [role="menuitemradio"]:first-child {
|
||||
.plyr__menu__container [role='menuitem']:first-child,
|
||||
.plyr__menu__container [role='menuitemradio']:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
|
|
@ -386,7 +386,7 @@ a.plyr__control::before {
|
|||
.plyr__menu__container .plyr__control::after {
|
||||
border: 4px solid transparent;
|
||||
border: var(--plyr-menu-item-arrow-size, 4px) solid transparent;
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
|
|
@ -441,7 +441,7 @@ a.plyr__control::before {
|
|||
background: var(--plyr-menu-back-border-color, #dcdfe5);
|
||||
box-shadow: 0 1px 0 #fff;
|
||||
box-shadow: 0 1px 0 var(--plyr-menu-back-border-shadow-color, #fff);
|
||||
content: "";
|
||||
content: '';
|
||||
height: 1px;
|
||||
left: 0;
|
||||
margin-top: calc(calc(10px * 0.7) / 2);
|
||||
|
|
@ -457,19 +457,19 @@ a.plyr__control::before {
|
|||
border-right-color: currentColor;
|
||||
}
|
||||
|
||||
.plyr__menu__container .plyr__control[role="menuitemradio"] {
|
||||
.plyr__menu__container .plyr__control[role='menuitemradio'] {
|
||||
padding-left: calc(10px * 0.7);
|
||||
padding-left: calc(var(--plyr-control-spacing, 10px) * 0.7);
|
||||
}
|
||||
|
||||
.plyr__menu__container .plyr__control[role="menuitemradio"]::after,
|
||||
.plyr__menu__container .plyr__control[role="menuitemradio"]::before {
|
||||
.plyr__menu__container .plyr__control[role='menuitemradio']::after,
|
||||
.plyr__menu__container .plyr__control[role='menuitemradio']::before {
|
||||
border-radius: 100%;
|
||||
}
|
||||
|
||||
.plyr__menu__container .plyr__control[role="menuitemradio"]::before {
|
||||
.plyr__menu__container .plyr__control[role='menuitemradio']::before {
|
||||
background: rgba(0, 0, 0, 0.1);
|
||||
content: "";
|
||||
content: '';
|
||||
display: block;
|
||||
flex-shrink: 0;
|
||||
height: 16px;
|
||||
|
|
@ -479,7 +479,7 @@ a.plyr__control::before {
|
|||
width: 16px;
|
||||
}
|
||||
|
||||
.plyr__menu__container .plyr__control[role="menuitemradio"]::after {
|
||||
.plyr__menu__container .plyr__control[role='menuitemradio']::after {
|
||||
background: #fff;
|
||||
border: 0;
|
||||
height: 6px;
|
||||
|
|
@ -492,7 +492,7 @@ a.plyr__control::before {
|
|||
}
|
||||
|
||||
.plyr__menu__container
|
||||
.plyr__control[role="menuitemradio"][aria-checked="true"]::before {
|
||||
.plyr__control[role='menuitemradio'][aria-checked='true']::before {
|
||||
background: #00b3ff;
|
||||
background: var(
|
||||
--plyr-control-toggle-checked-background,
|
||||
|
|
@ -501,14 +501,14 @@ a.plyr__control::before {
|
|||
}
|
||||
|
||||
.plyr__menu__container
|
||||
.plyr__control[role="menuitemradio"][aria-checked="true"]::after {
|
||||
.plyr__control[role='menuitemradio'][aria-checked='true']::after {
|
||||
opacity: 1;
|
||||
transform: translateY(-50%) scale(1);
|
||||
}
|
||||
|
||||
.plyr__menu__container
|
||||
.plyr__control[role="menuitemradio"].plyr__tab-focus::before,
|
||||
.plyr__menu__container .plyr__control[role="menuitemradio"]:hover::before {
|
||||
.plyr__control[role='menuitemradio'].plyr__tab-focus::before,
|
||||
.plyr__menu__container .plyr__control[role='menuitemradio']:hover::before {
|
||||
background: rgba(35, 40, 47, 0.1);
|
||||
}
|
||||
|
||||
|
|
@ -524,7 +524,7 @@ a.plyr__control::before {
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"] {
|
||||
.plyr--full-ui input[type='range'] {
|
||||
-webkit-appearance: none;
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
|
|
@ -547,7 +547,7 @@ a.plyr__control::before {
|
|||
width: 100%;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-webkit-slider-runnable-track {
|
||||
.plyr--full-ui input[type='range']::-webkit-slider-runnable-track {
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
border-radius: calc(5px / 2);
|
||||
|
|
@ -566,7 +566,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-webkit-slider-thumb {
|
||||
.plyr--full-ui input[type='range']::-webkit-slider-thumb {
|
||||
background: #fff;
|
||||
background: var(--plyr-range-thumb-background, #fff);
|
||||
border: 0;
|
||||
|
|
@ -596,7 +596,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-moz-range-track {
|
||||
.plyr--full-ui input[type='range']::-moz-range-track {
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
border-radius: calc(5px / 2);
|
||||
|
|
@ -608,7 +608,7 @@ a.plyr__control::before {
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-moz-range-thumb {
|
||||
.plyr--full-ui input[type='range']::-moz-range-thumb {
|
||||
background: #fff;
|
||||
background: var(--plyr-range-thumb-background, #fff);
|
||||
border: 0;
|
||||
|
|
@ -628,7 +628,7 @@ a.plyr__control::before {
|
|||
width: var(--plyr-range-thumb-height, 13px);
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-moz-range-progress {
|
||||
.plyr--full-ui input[type='range']::-moz-range-progress {
|
||||
background: currentColor;
|
||||
border-radius: calc(5px / 2);
|
||||
border-radius: calc(var(--plyr-range-track-height, 5px) / 2);
|
||||
|
|
@ -636,7 +636,7 @@ a.plyr__control::before {
|
|||
height: var(--plyr-range-track-height, 5px);
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-ms-track {
|
||||
.plyr--full-ui input[type='range']::-ms-track {
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
border-radius: calc(5px / 2);
|
||||
|
|
@ -650,7 +650,7 @@ a.plyr__control::before {
|
|||
color: transparent;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-ms-fill-upper {
|
||||
.plyr--full-ui input[type='range']::-ms-fill-upper {
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
border-radius: calc(5px / 2);
|
||||
|
|
@ -663,7 +663,7 @@ a.plyr__control::before {
|
|||
user-select: none;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-ms-fill-lower {
|
||||
.plyr--full-ui input[type='range']::-ms-fill-lower {
|
||||
background: 0 0;
|
||||
border: 0;
|
||||
border-radius: calc(5px / 2);
|
||||
|
|
@ -677,7 +677,7 @@ a.plyr__control::before {
|
|||
background: currentColor;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-ms-thumb {
|
||||
.plyr--full-ui input[type='range']::-ms-thumb {
|
||||
background: #fff;
|
||||
background: var(--plyr-range-thumb-background, #fff);
|
||||
border: 0;
|
||||
|
|
@ -698,20 +698,20 @@ a.plyr__control::before {
|
|||
margin-top: 0;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-ms-tooltip {
|
||||
.plyr--full-ui input[type='range']::-ms-tooltip {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]:focus {
|
||||
.plyr--full-ui input[type='range']:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"]::-moz-focus-outer {
|
||||
.plyr--full-ui input[type='range']::-moz-focus-outer {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.plyr--full-ui
|
||||
input[type="range"].plyr__tab-focus::-webkit-slider-runnable-track {
|
||||
input[type='range'].plyr__tab-focus::-webkit-slider-runnable-track {
|
||||
outline-color: #00b3ff;
|
||||
outline-color: var(
|
||||
--plyr-tab-focus-color,
|
||||
|
|
@ -722,7 +722,7 @@ a.plyr__control::before {
|
|||
outline-width: 3px;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"].plyr__tab-focus::-moz-range-track {
|
||||
.plyr--full-ui input[type='range'].plyr__tab-focus::-moz-range-track {
|
||||
outline-color: #00b3ff;
|
||||
outline-color: var(
|
||||
--plyr-tab-focus-color,
|
||||
|
|
@ -733,7 +733,7 @@ a.plyr__control::before {
|
|||
outline-width: 3px;
|
||||
}
|
||||
|
||||
.plyr--full-ui input[type="range"].plyr__tab-focus::-ms-track {
|
||||
.plyr--full-ui input[type='range'].plyr__tab-focus::-ms-track {
|
||||
outline-color: #00b3ff;
|
||||
outline-color: var(
|
||||
--plyr-tab-focus-color,
|
||||
|
|
@ -769,7 +769,7 @@ a.plyr__control::before {
|
|||
}
|
||||
|
||||
.plyr__time + .plyr__time::before {
|
||||
content: "\2044";
|
||||
content: '\2044';
|
||||
margin-right: 10px;
|
||||
margin-right: var(--plyr-control-spacing, 10px);
|
||||
}
|
||||
|
|
@ -821,7 +821,7 @@ a.plyr__control::before {
|
|||
var(--plyr-tooltip-background, rgba(255, 255, 255, 0.9));
|
||||
bottom: calc(4px * -1);
|
||||
bottom: calc(var(--plyr-tooltip-arrow-size, 4px) * -1);
|
||||
content: "";
|
||||
content: '';
|
||||
height: 0;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
|
|
@ -906,7 +906,7 @@ a.plyr__control::before {
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.plyr__progress input[type="range"],
|
||||
.plyr__progress input[type='range'],
|
||||
.plyr__progress__buffer {
|
||||
margin-left: calc(13px * -0.5);
|
||||
margin-left: calc(var(--plyr-range-thumb-height, 13px) * -0.5);
|
||||
|
|
@ -916,7 +916,7 @@ a.plyr__control::before {
|
|||
width: calc(100% + var(--plyr-range-thumb-height, 13px));
|
||||
}
|
||||
|
||||
.plyr__progress input[type="range"] {
|
||||
.plyr__progress input[type='range'] {
|
||||
position: relative;
|
||||
z-index: 2;
|
||||
}
|
||||
|
|
@ -1024,7 +1024,7 @@ a.plyr__control::before {
|
|||
width: 20%;
|
||||
}
|
||||
|
||||
.plyr__volume input[type="range"] {
|
||||
.plyr__volume input[type='range'] {
|
||||
margin-left: calc(10px / 2);
|
||||
margin-left: calc(var(--plyr-control-spacing, 10px) / 2);
|
||||
margin-right: calc(10px / 2);
|
||||
|
|
@ -1054,7 +1054,7 @@ a.plyr__control::before {
|
|||
|
||||
.plyr--audio .plyr__control.plyr__tab-focus,
|
||||
.plyr--audio .plyr__control:hover,
|
||||
.plyr--audio .plyr__control[aria-expanded="true"] {
|
||||
.plyr--audio .plyr__control[aria-expanded='true'] {
|
||||
background: #00b3ff;
|
||||
background: var(
|
||||
--plyr-audio-control-background-hover,
|
||||
|
|
@ -1064,7 +1064,7 @@ a.plyr__control::before {
|
|||
color: var(--plyr-audio-control-color-hover, #fff);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--audio input[type="range"]::-webkit-slider-runnable-track {
|
||||
.plyr--full-ui.plyr--audio input[type='range']::-webkit-slider-runnable-track {
|
||||
background-color: rgba(193, 200, 209, 0.6);
|
||||
background-color: var(
|
||||
--plyr-audio-range-track-background,
|
||||
|
|
@ -1072,7 +1072,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--audio input[type="range"]::-moz-range-track {
|
||||
.plyr--full-ui.plyr--audio input[type='range']::-moz-range-track {
|
||||
background-color: rgba(193, 200, 209, 0.6);
|
||||
background-color: var(
|
||||
--plyr-audio-range-track-background,
|
||||
|
|
@ -1080,7 +1080,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--audio input[type="range"]::-ms-track {
|
||||
.plyr--full-ui.plyr--audio input[type='range']::-ms-track {
|
||||
background-color: rgba(193, 200, 209, 0.6);
|
||||
background-color: var(
|
||||
--plyr-audio-range-track-background,
|
||||
|
|
@ -1088,7 +1088,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--audio input[type="range"]:active::-webkit-slider-thumb {
|
||||
.plyr--full-ui.plyr--audio input[type='range']:active::-webkit-slider-thumb {
|
||||
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
|
||||
0 0 0 3px rgba(35, 40, 47, 0.1);
|
||||
box-shadow: var(
|
||||
|
|
@ -1100,7 +1100,7 @@ a.plyr__control::before {
|
|||
var(--plyr-audio-range-thumb-active-shadow-color, rgba(35, 40, 47, 0.1));
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--audio input[type="range"]:active::-moz-range-thumb {
|
||||
.plyr--full-ui.plyr--audio input[type='range']:active::-moz-range-thumb {
|
||||
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
|
||||
0 0 0 3px rgba(35, 40, 47, 0.1);
|
||||
box-shadow: var(
|
||||
|
|
@ -1112,7 +1112,7 @@ a.plyr__control::before {
|
|||
var(--plyr-audio-range-thumb-active-shadow-color, rgba(35, 40, 47, 0.1));
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--audio input[type="range"]:active::-ms-thumb {
|
||||
.plyr--full-ui.plyr--audio input[type='range']:active::-ms-thumb {
|
||||
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
|
||||
0 0 0 3px rgba(35, 40, 47, 0.1);
|
||||
box-shadow: var(
|
||||
|
|
@ -1207,7 +1207,7 @@ a.plyr__control::before {
|
|||
|
||||
.plyr--video .plyr__control.plyr__tab-focus,
|
||||
.plyr--video .plyr__control:hover,
|
||||
.plyr--video .plyr__control[aria-expanded="true"] {
|
||||
.plyr--video .plyr__control[aria-expanded='true'] {
|
||||
background: #00b3ff;
|
||||
background: var(
|
||||
--plyr-video-control-background-hover,
|
||||
|
|
@ -1258,7 +1258,7 @@ a.plyr__control::before {
|
|||
display: block;
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--video input[type="range"]::-webkit-slider-runnable-track {
|
||||
.plyr--full-ui.plyr--video input[type='range']::-webkit-slider-runnable-track {
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
background-color: var(
|
||||
--plyr-video-range-track-background,
|
||||
|
|
@ -1266,7 +1266,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--video input[type="range"]::-moz-range-track {
|
||||
.plyr--full-ui.plyr--video input[type='range']::-moz-range-track {
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
background-color: var(
|
||||
--plyr-video-range-track-background,
|
||||
|
|
@ -1274,7 +1274,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--video input[type="range"]::-ms-track {
|
||||
.plyr--full-ui.plyr--video input[type='range']::-ms-track {
|
||||
background-color: rgba(255, 255, 255, 0.25);
|
||||
background-color: var(
|
||||
--plyr-video-range-track-background,
|
||||
|
|
@ -1282,7 +1282,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--video input[type="range"]:active::-webkit-slider-thumb {
|
||||
.plyr--full-ui.plyr--video input[type='range']:active::-webkit-slider-thumb {
|
||||
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
|
||||
0 0 0 3px rgba(255, 255, 255, 0.5);
|
||||
box-shadow: var(
|
||||
|
|
@ -1297,7 +1297,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--video input[type="range"]:active::-moz-range-thumb {
|
||||
.plyr--full-ui.plyr--video input[type='range']:active::-moz-range-thumb {
|
||||
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
|
||||
0 0 0 3px rgba(255, 255, 255, 0.5);
|
||||
box-shadow: var(
|
||||
|
|
@ -1312,7 +1312,7 @@ a.plyr__control::before {
|
|||
);
|
||||
}
|
||||
|
||||
.plyr--full-ui.plyr--video input[type="range"]:active::-ms-thumb {
|
||||
.plyr--full-ui.plyr--video input[type='range']:active::-ms-thumb {
|
||||
box-shadow: 0 1px 1px rgba(35, 40, 47, 0.15), 0 0 0 1px rgba(35, 40, 47, 0.2),
|
||||
0 0 0 3px rgba(255, 255, 255, 0.5);
|
||||
box-shadow: var(
|
||||
|
|
@ -1713,7 +1713,7 @@ a.plyr__control::before {
|
|||
var(--plyr-tooltip-background, rgba(255, 255, 255, 0.9));
|
||||
bottom: calc(4px * -1);
|
||||
bottom: calc(var(--plyr-tooltip-arrow-size, 4px) * -1);
|
||||
content: "";
|
||||
content: '';
|
||||
height: 0;
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@
|
|||
}
|
||||
|
||||
.nyancat .vue-slider-dot-handle {
|
||||
background: url("/img/logos/nyancat.gif");
|
||||
background: url('/img/logos/nyancat.gif');
|
||||
background-size: 36px;
|
||||
width: 36px;
|
||||
height: 24px;
|
||||
|
|
@ -101,7 +101,7 @@
|
|||
}
|
||||
|
||||
.nyancat-stop .vue-slider-dot-handle {
|
||||
background-image: url("/img/logos/nyancat-stop.png");
|
||||
background-image: url('/img/logos/nyancat-stop.png');
|
||||
transition: 300ms;
|
||||
}
|
||||
|
||||
|
|
@ -126,10 +126,10 @@
|
|||
display: none;
|
||||
}
|
||||
|
||||
body[data-theme="dark"] .lyrics-page .vue-slider-process {
|
||||
body[data-theme='dark'] .lyrics-page .vue-slider-process {
|
||||
background-color: #fafafa;
|
||||
}
|
||||
|
||||
body[data-theme="dark"] .lyrics-page .vue-slider-dot-handle {
|
||||
body[data-theme='dark'] .lyrics-page .vue-slider-dot-handle {
|
||||
background-color: #fff;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import Vue from "vue";
|
||||
import SvgIcon from "@/components/SvgIcon";
|
||||
import Vue from 'vue';
|
||||
import SvgIcon from '@/components/SvgIcon';
|
||||
|
||||
Vue.component("svg-icon", SvgIcon);
|
||||
const requireAll = (requireContext) =>
|
||||
requireContext.keys().map(requireContext);
|
||||
const req = require.context("./", true, /\.svg$/);
|
||||
Vue.component('svg-icon', SvgIcon);
|
||||
const requireAll = requireContext => requireContext.keys().map(requireContext);
|
||||
const req = require.context('./', true, /\.svg$/);
|
||||
requireAll(req);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"use strict";
|
||||
'use strict';
|
||||
import {
|
||||
app,
|
||||
protocol,
|
||||
|
|
@ -7,20 +7,20 @@ import {
|
|||
dialog,
|
||||
globalShortcut,
|
||||
nativeTheme,
|
||||
} from "electron";
|
||||
import { createProtocol } from "vue-cli-plugin-electron-builder/lib";
|
||||
import { startNeteaseMusicApi } from "./electron/services";
|
||||
import { initIpcMain } from "./electron/ipcMain.js";
|
||||
import { createMenu } from "./electron/menu";
|
||||
import { createTray } from "@/electron/tray";
|
||||
import { createTouchBar } from "./electron/touchBar";
|
||||
import { createDockMenu } from "./electron/dockMenu";
|
||||
import { registerGlobalShortcut } from "./electron/globalShortcut";
|
||||
import { autoUpdater } from "electron-updater";
|
||||
import installExtension, { VUEJS_DEVTOOLS } from "electron-devtools-installer";
|
||||
import express from "express";
|
||||
import expressProxy from "express-http-proxy";
|
||||
import Store from "electron-store";
|
||||
} from 'electron';
|
||||
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib';
|
||||
import { startNeteaseMusicApi } from './electron/services';
|
||||
import { initIpcMain } from './electron/ipcMain.js';
|
||||
import { createMenu } from './electron/menu';
|
||||
import { createTray } from '@/electron/tray';
|
||||
import { createTouchBar } from './electron/touchBar';
|
||||
import { createDockMenu } from './electron/dockMenu';
|
||||
import { registerGlobalShortcut } from './electron/globalShortcut';
|
||||
import { autoUpdater } from 'electron-updater';
|
||||
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer';
|
||||
import express from 'express';
|
||||
import expressProxy from 'express-http-proxy';
|
||||
import Store from 'electron-store';
|
||||
|
||||
class Background {
|
||||
constructor() {
|
||||
|
|
@ -28,19 +28,19 @@ class Background {
|
|||
this.tray = null;
|
||||
this.store = new Store({
|
||||
windowWidth: {
|
||||
width: { type: "number", default: 1440 },
|
||||
height: { type: "number", default: 840 },
|
||||
width: { type: 'number', default: 1440 },
|
||||
height: { type: 'number', default: 840 },
|
||||
},
|
||||
});
|
||||
this.neteaseMusicAPI = null;
|
||||
this.expressApp = null;
|
||||
this.willQuitApp = process.platform === "darwin" ? false : true;
|
||||
this.willQuitApp = process.platform === 'darwin' ? false : true;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
console.log("initializing");
|
||||
console.log('initializing');
|
||||
|
||||
// Make sure the app is singleton.
|
||||
if (!app.requestSingleInstanceLock()) return app.quit();
|
||||
|
|
@ -53,7 +53,7 @@ class Background {
|
|||
|
||||
// Scheme must be registered before the app is ready
|
||||
protocol.registerSchemesAsPrivileged([
|
||||
{ scheme: "app", privileges: { secure: true, standard: true } },
|
||||
{ scheme: 'app', privileges: { secure: true, standard: true } },
|
||||
]);
|
||||
|
||||
// handle app events
|
||||
|
|
@ -65,45 +65,45 @@ class Background {
|
|||
try {
|
||||
await installExtension(VUEJS_DEVTOOLS);
|
||||
} catch (e) {
|
||||
console.error("Vue Devtools failed to install:", e.toString());
|
||||
console.error('Vue Devtools failed to install:', e.toString());
|
||||
}
|
||||
|
||||
// Exit cleanly on request from parent process in development mode.
|
||||
if (process.platform === "win32") {
|
||||
process.on("message", (data) => {
|
||||
if (data === "graceful-exit") {
|
||||
if (process.platform === 'win32') {
|
||||
process.on('message', data => {
|
||||
if (data === 'graceful-exit') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
process.on("SIGTERM", () => {
|
||||
process.on('SIGTERM', () => {
|
||||
app.quit();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
createExpressApp() {
|
||||
console.log("creating express app");
|
||||
console.log('creating express app');
|
||||
|
||||
const expressApp = express();
|
||||
expressApp.use("/", express.static(__dirname + "/"));
|
||||
expressApp.use("/api", expressProxy("http://127.0.0.1:10754"));
|
||||
expressApp.use('/', express.static(__dirname + '/'));
|
||||
expressApp.use('/api', expressProxy('http://127.0.0.1:10754'));
|
||||
this.expressApp = expressApp.listen(27232);
|
||||
}
|
||||
|
||||
createWindow() {
|
||||
console.log("creating app window");
|
||||
console.log('creating app window');
|
||||
|
||||
const appearance = this.store.get("settings.appearance");
|
||||
const appearance = this.store.get('settings.appearance');
|
||||
|
||||
this.window = new BrowserWindow({
|
||||
width: this.store.get("window.width") || 1440,
|
||||
height: this.store.get("window.height") || 840,
|
||||
width: this.store.get('window.width') || 1440,
|
||||
height: this.store.get('window.height') || 840,
|
||||
minWidth: 1080,
|
||||
minHeight: 720,
|
||||
titleBarStyle: "hiddenInset",
|
||||
frame: process.platform !== "win32",
|
||||
title: "YesPlayMusic",
|
||||
titleBarStyle: 'hiddenInset',
|
||||
frame: process.platform !== 'win32',
|
||||
title: 'YesPlayMusic',
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
nodeIntegration: true,
|
||||
|
|
@ -111,11 +111,11 @@ class Background {
|
|||
contextIsolation: false,
|
||||
},
|
||||
backgroundColor:
|
||||
((appearance === undefined || appearance === "auto") &&
|
||||
((appearance === undefined || appearance === 'auto') &&
|
||||
nativeTheme.shouldUseDarkColors) ||
|
||||
appearance === "dark"
|
||||
? "#222"
|
||||
: "#fff",
|
||||
appearance === 'dark'
|
||||
? '#222'
|
||||
: '#fff',
|
||||
});
|
||||
|
||||
// hide menu bar on Microsoft Windows and Linux
|
||||
|
|
@ -126,46 +126,46 @@ class Background {
|
|||
this.window.loadURL(process.env.WEBPACK_DEV_SERVER_URL);
|
||||
if (!process.env.IS_TEST) this.window.webContents.openDevTools();
|
||||
} else {
|
||||
createProtocol("app");
|
||||
this.window.loadURL("http://localhost:27232");
|
||||
createProtocol('app');
|
||||
this.window.loadURL('http://localhost:27232');
|
||||
}
|
||||
}
|
||||
|
||||
checkForUpdates() {
|
||||
autoUpdater.checkForUpdatesAndNotify();
|
||||
|
||||
const showNewVersionMessage = (info) => {
|
||||
const showNewVersionMessage = info => {
|
||||
dialog
|
||||
.showMessageBox({
|
||||
title: "发现新版本 v" + info.version,
|
||||
message: "发现新版本 v" + info.version,
|
||||
detail: "是否前往 GitHub 下载新版本安装包?",
|
||||
buttons: ["下载", "取消"],
|
||||
type: "question",
|
||||
title: '发现新版本 v' + info.version,
|
||||
message: '发现新版本 v' + info.version,
|
||||
detail: '是否前往 GitHub 下载新版本安装包?',
|
||||
buttons: ['下载', '取消'],
|
||||
type: 'question',
|
||||
noLink: true,
|
||||
})
|
||||
.then((result) => {
|
||||
.then(result => {
|
||||
if (result.response === 0) {
|
||||
shell.openExternal(
|
||||
"https://github.com/qier222/YesPlayMusic/releases"
|
||||
'https://github.com/qier222/YesPlayMusic/releases'
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
autoUpdater.on("update-available", (info) => {
|
||||
autoUpdater.on('update-available', info => {
|
||||
showNewVersionMessage(info);
|
||||
});
|
||||
}
|
||||
|
||||
handleWindowEvents() {
|
||||
this.window.once("ready-to-show", () => {
|
||||
console.log("windows ready-to-show event");
|
||||
this.window.once('ready-to-show', () => {
|
||||
console.log('windows ready-to-show event');
|
||||
this.window.show();
|
||||
});
|
||||
|
||||
this.window.on("close", (e) => {
|
||||
console.log("windows close event");
|
||||
this.window.on('close', e => {
|
||||
console.log('windows close event');
|
||||
if (this.willQuitApp) {
|
||||
/* the user tried to quit the app */
|
||||
this.window = null;
|
||||
|
|
@ -177,31 +177,31 @@ class Background {
|
|||
}
|
||||
});
|
||||
|
||||
this.window.on("resize", () => {
|
||||
this.window.on('resize', () => {
|
||||
let { height, width } = this.window.getBounds();
|
||||
this.store.set("window", { height, width });
|
||||
this.store.set('window', { height, width });
|
||||
});
|
||||
|
||||
this.window.on("minimize", () => {
|
||||
this.window.on('minimize', () => {
|
||||
if (
|
||||
["win32", "linux"].includes(process.platform) &&
|
||||
this.store.get("settings.minimizeToTray")
|
||||
['win32', 'linux'].includes(process.platform) &&
|
||||
this.store.get('settings.minimizeToTray')
|
||||
) {
|
||||
this.window.hide();
|
||||
}
|
||||
});
|
||||
|
||||
this.window.webContents.on("new-window", function (e, url) {
|
||||
this.window.webContents.on('new-window', function (e, url) {
|
||||
e.preventDefault();
|
||||
console.log("open url");
|
||||
const excludeHosts = ["www.last.fm"];
|
||||
const exclude = excludeHosts.find((host) => url.includes(host));
|
||||
console.log('open url');
|
||||
const excludeHosts = ['www.last.fm'];
|
||||
const exclude = excludeHosts.find(host => url.includes(host));
|
||||
if (exclude) {
|
||||
const newWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
titleBarStyle: "default",
|
||||
title: "YesPlayMusic",
|
||||
titleBarStyle: 'default',
|
||||
title: 'YesPlayMusic',
|
||||
webPreferences: {
|
||||
webSecurity: false,
|
||||
nodeIntegration: true,
|
||||
|
|
@ -217,14 +217,14 @@ class Background {
|
|||
}
|
||||
|
||||
handleAppEvents() {
|
||||
app.on("ready", async () => {
|
||||
app.on('ready', async () => {
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
console.log("app ready event");
|
||||
console.log('app ready event');
|
||||
|
||||
// for development
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
this.initDevtools();
|
||||
}
|
||||
|
||||
|
|
@ -242,7 +242,7 @@ class Background {
|
|||
createMenu(this.window);
|
||||
|
||||
// create tray
|
||||
if (["win32", "linux"].includes(process.platform)) {
|
||||
if (['win32', 'linux'].includes(process.platform)) {
|
||||
this.tray = createTray(this.window);
|
||||
}
|
||||
|
||||
|
|
@ -253,15 +253,15 @@ class Background {
|
|||
this.window.setTouchBar(createTouchBar(this.window));
|
||||
|
||||
// register global shortcuts
|
||||
if (this.store.get("settings.enableGlobalShortcut")) {
|
||||
if (this.store.get('settings.enableGlobalShortcut')) {
|
||||
registerGlobalShortcut(this.window);
|
||||
}
|
||||
});
|
||||
|
||||
app.on("activate", () => {
|
||||
app.on('activate', () => {
|
||||
// On macOS it's common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
console.log("app activate event");
|
||||
console.log('app activate event');
|
||||
if (this.window === null) {
|
||||
this.createWindow();
|
||||
} else {
|
||||
|
|
@ -269,21 +269,21 @@ class Background {
|
|||
}
|
||||
});
|
||||
|
||||
app.on("window-all-closed", () => {
|
||||
if (process.platform !== "darwin") {
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
|
||||
app.on("before-quit", () => {
|
||||
app.on('before-quit', () => {
|
||||
this.willQuitApp = true;
|
||||
});
|
||||
|
||||
app.on("quit", () => {
|
||||
app.on('quit', () => {
|
||||
this.expressApp.close();
|
||||
});
|
||||
|
||||
app.on("will-quit", () => {
|
||||
app.on('will-quit', () => {
|
||||
// unregister all global shortcuts
|
||||
globalShortcut.unregisterAll();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "ArtistInLine",
|
||||
name: 'ArtistInLine',
|
||||
props: {
|
||||
artists: {
|
||||
type: Array,
|
||||
|
|
@ -18,20 +18,20 @@ export default {
|
|||
},
|
||||
exclude: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
prefix: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
filteredArtists() {
|
||||
return this.artists.filter((a) => a.name !== this.exclude);
|
||||
return this.artists.filter(a => a.name !== this.exclude);
|
||||
},
|
||||
computedPrefix() {
|
||||
if (this.filteredArtists.length !== 0) return this.prefix;
|
||||
else return "";
|
||||
else return '';
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "ButtonIcon",
|
||||
name: 'ButtonIcon',
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
<button :style="buttonStyle" :class="color">
|
||||
<svg-icon
|
||||
v-if="iconClass !== null"
|
||||
:iconClass="iconClass"
|
||||
:icon-class="iconClass"
|
||||
:style="{ marginRight: iconButton ? '0px' : '8px' }"
|
||||
/>
|
||||
<slot></slot>
|
||||
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "ButtonTwoTone",
|
||||
name: 'ButtonTwoTone',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
|
|
@ -27,32 +27,32 @@ export default {
|
|||
},
|
||||
color: {
|
||||
type: String,
|
||||
default: "blue",
|
||||
default: 'blue',
|
||||
},
|
||||
backgroundColor: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
textColor: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
shape: {
|
||||
type: String,
|
||||
default: "square",
|
||||
default: 'square',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
buttonStyle() {
|
||||
let styles = {
|
||||
borderRadius: this.shape === "round" ? "50%" : "8px",
|
||||
borderRadius: this.shape === 'round' ? '50%' : '8px',
|
||||
padding: `8px ${this.horizontalPadding}px`,
|
||||
// height: "38px",
|
||||
width: this.shape === "round" ? "38px" : "auto",
|
||||
width: this.shape === 'round' ? '38px' : 'auto',
|
||||
};
|
||||
if (this.backgroundColor !== "")
|
||||
if (this.backgroundColor !== '')
|
||||
styles.backgroundColor = this.backgroundColor;
|
||||
if (this.textColor !== "") styles.color = this.textColor;
|
||||
if (this.textColor !== '') styles.color = this.textColor;
|
||||
return styles;
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="context-menu" ref="contextMenu">
|
||||
<div ref="contextMenu" class="context-menu">
|
||||
<div
|
||||
v-if="showMenu"
|
||||
ref="menu"
|
||||
class="menu"
|
||||
tabindex="-1"
|
||||
ref="menu"
|
||||
v-if="showMenu"
|
||||
@blur="closeMenu"
|
||||
:style="{ top: top, left: left }"
|
||||
@blur="closeMenu"
|
||||
@click="closeMenu"
|
||||
>
|
||||
<slot></slot>
|
||||
|
|
@ -16,12 +16,12 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "ContextMenu",
|
||||
name: 'ContextMenu',
|
||||
data() {
|
||||
return {
|
||||
showMenu: false,
|
||||
top: "0px",
|
||||
left: "0px",
|
||||
top: '0px',
|
||||
left: '0px',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
|
@ -31,8 +31,8 @@ export default {
|
|||
let largestWidth = window.innerWidth - this.$refs.menu.offsetWidth - 25;
|
||||
if (top > largestHeight) top = largestHeight;
|
||||
if (left > largestWidth) left = largestWidth;
|
||||
this.top = top + "px";
|
||||
this.left = left + "px";
|
||||
this.top = top + 'px';
|
||||
this.left = left + 'px';
|
||||
},
|
||||
|
||||
closeMenu() {
|
||||
|
|
@ -82,7 +82,7 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
.menu {
|
||||
background: rgba(36, 36, 36, 0.78);
|
||||
backdrop-filter: blur(16px) contrast(120%);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
<template>
|
||||
<div
|
||||
class="cover"
|
||||
:class="{ 'cover-hover': coverHover }"
|
||||
@mouseover="focus = true"
|
||||
@mouseleave="focus = false"
|
||||
:class="{ 'cover-hover': coverHover }"
|
||||
@click="clickCoverToPlay ? play() : goTo()"
|
||||
>
|
||||
<div class="cover-container">
|
||||
|
|
@ -11,16 +11,16 @@
|
|||
<button
|
||||
v-show="focus"
|
||||
class="play-button"
|
||||
@click.stop="play()"
|
||||
:style="playButtonStyles"
|
||||
@click.stop="play()"
|
||||
><svg-icon icon-class="play" />
|
||||
</button>
|
||||
</div>
|
||||
<img :src="imageUrl" :style="imageStyles" />
|
||||
<transition name="fade" v-if="coverHover || alwaysShowShadow">
|
||||
<transition v-if="coverHover || alwaysShowShadow" name="fade">
|
||||
<div
|
||||
class="shadow"
|
||||
v-show="focus || alwaysShowShadow"
|
||||
class="shadow"
|
||||
:style="shadowStyles"
|
||||
></div>
|
||||
</transition>
|
||||
|
|
@ -52,22 +52,22 @@ export default {
|
|||
imageStyles() {
|
||||
let styles = {};
|
||||
if (this.fixedSize !== 0) {
|
||||
styles.width = this.fixedSize + "px";
|
||||
styles.height = this.fixedSize + "px";
|
||||
styles.width = this.fixedSize + 'px';
|
||||
styles.height = this.fixedSize + 'px';
|
||||
}
|
||||
if (this.type === "artist") styles.borderRadius = "50%";
|
||||
if (this.type === 'artist') styles.borderRadius = '50%';
|
||||
return styles;
|
||||
},
|
||||
playButtonStyles() {
|
||||
let styles = {};
|
||||
styles.width = this.playButtonSize + "%";
|
||||
styles.height = this.playButtonSize + "%";
|
||||
styles.width = this.playButtonSize + '%';
|
||||
styles.height = this.playButtonSize + '%';
|
||||
return styles;
|
||||
},
|
||||
shadowStyles() {
|
||||
let styles = {};
|
||||
styles.backgroundImage = `url(${this.imageUrl})`;
|
||||
if (this.type === "artist") styles.borderRadius = "50%";
|
||||
if (this.type === 'artist') styles.borderRadius = '50%';
|
||||
return styles;
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
<template>
|
||||
<div class="cover-row" :style="rowStyles">
|
||||
<div
|
||||
class="item"
|
||||
v-for="item in items"
|
||||
:key="item.id"
|
||||
class="item"
|
||||
:class="{ artist: type === 'artist' }"
|
||||
>
|
||||
<Cover
|
||||
:imageUrl="getImageUrl(item)"
|
||||
:type="type"
|
||||
:id="item.id"
|
||||
:playButtonSize="type === 'artist' ? 26 : playButtonSize"
|
||||
:image-url="getImageUrl(item)"
|
||||
:type="type"
|
||||
:play-button-size="type === 'artist' ? 26 : playButtonSize"
|
||||
/>
|
||||
<div class="text">
|
||||
<div class="info" v-if="showPlayCount">
|
||||
<div v-if="showPlayCount" class="info">
|
||||
<span class="play-count"
|
||||
><svg-icon icon-class="play" />{{
|
||||
item.playCount | formatPlayCount
|
||||
|
|
@ -21,15 +21,15 @@
|
|||
</span>
|
||||
</div>
|
||||
<div class="title" :style="{ fontSize: subTextFontSize }">
|
||||
<span class="explicit-symbol" v-if="isExplicit(item)"
|
||||
<span v-if="isExplicit(item)" class="explicit-symbol"
|
||||
><ExplicitSymbol
|
||||
/></span>
|
||||
<span class="lock-icon" v-if="isPrivacy(item)">
|
||||
<span v-if="isPrivacy(item)" class="lock-icon">
|
||||
<svg-icon icon-class="lock"
|
||||
/></span>
|
||||
<router-link :to="getTitleLink(item)">{{ item.name }}</router-link>
|
||||
</div>
|
||||
<div class="info" v-if="type !== 'artist' && subText !== 'none'">
|
||||
<div v-if="type !== 'artist' && subText !== 'none'" class="info">
|
||||
<span v-html="getSubText(item)"></span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -38,11 +38,11 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Cover from "@/components/Cover.vue";
|
||||
import ExplicitSymbol from "@/components/ExplicitSymbol.vue";
|
||||
import Cover from '@/components/Cover.vue';
|
||||
import ExplicitSymbol from '@/components/ExplicitSymbol.vue';
|
||||
|
||||
export default {
|
||||
name: "CoverRow",
|
||||
name: 'CoverRow',
|
||||
components: {
|
||||
Cover,
|
||||
ExplicitSymbol,
|
||||
|
|
@ -50,64 +50,64 @@ export default {
|
|||
props: {
|
||||
items: { type: Array, required: true },
|
||||
type: { type: String, required: true },
|
||||
subText: { type: String, default: "null" },
|
||||
subTextFontSize: { type: String, default: "16px" },
|
||||
subText: { type: String, default: 'null' },
|
||||
subTextFontSize: { type: String, default: '16px' },
|
||||
showPlayCount: { type: Boolean, default: false },
|
||||
columnNumber: { type: Number, default: 5 },
|
||||
gap: { type: String, default: "44px 24px" },
|
||||
gap: { type: String, default: '44px 24px' },
|
||||
playButtonSize: { type: Number, default: 22 },
|
||||
},
|
||||
computed: {
|
||||
rowStyles() {
|
||||
return {
|
||||
"grid-template-columns": `repeat(${this.columnNumber}, 1fr)`,
|
||||
'grid-template-columns': `repeat(${this.columnNumber}, 1fr)`,
|
||||
gap: this.gap,
|
||||
};
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
getSubText(item) {
|
||||
if (this.subText === "copywriter") return item.copywriter;
|
||||
if (this.subText === "description") return item.description;
|
||||
if (this.subText === "updateFrequency") return item.updateFrequency;
|
||||
if (this.subText === "creator") return "by " + item.creator.nickname;
|
||||
if (this.subText === "releaseYear")
|
||||
if (this.subText === 'copywriter') return item.copywriter;
|
||||
if (this.subText === 'description') return item.description;
|
||||
if (this.subText === 'updateFrequency') return item.updateFrequency;
|
||||
if (this.subText === 'creator') return 'by ' + item.creator.nickname;
|
||||
if (this.subText === 'releaseYear')
|
||||
return new Date(item.publishTime).getFullYear();
|
||||
if (this.subText === "artist") {
|
||||
if (this.subText === 'artist') {
|
||||
if (item.artist !== undefined)
|
||||
return `<a href="/#/artist/${item.artist.id}">${item.artist.name}</a>`;
|
||||
if (item.artists !== undefined)
|
||||
return `<a href="/#/artist/${item.artists[0].id}">${item.artists[0].name}</a>`;
|
||||
}
|
||||
if (this.subText === "albumType+releaseYear") {
|
||||
if (this.subText === 'albumType+releaseYear') {
|
||||
let albumType = item.type;
|
||||
if (item.type === "EP/Single") {
|
||||
albumType = item.size === 1 ? "Single" : "EP";
|
||||
} else if (item.type === "Single") {
|
||||
albumType = "Single";
|
||||
} else if (item.type === "专辑") {
|
||||
albumType = "Album";
|
||||
if (item.type === 'EP/Single') {
|
||||
albumType = item.size === 1 ? 'Single' : 'EP';
|
||||
} else if (item.type === 'Single') {
|
||||
albumType = 'Single';
|
||||
} else if (item.type === '专辑') {
|
||||
albumType = 'Album';
|
||||
}
|
||||
return `${albumType} · ${new Date(item.publishTime).getFullYear()}`;
|
||||
}
|
||||
if (this.subText === "appleMusic") return "by Apple Music";
|
||||
if (this.subText === 'appleMusic') return 'by Apple Music';
|
||||
},
|
||||
isPrivacy(item) {
|
||||
return this.type === "playlist" && item.privacy === 10;
|
||||
return this.type === 'playlist' && item.privacy === 10;
|
||||
},
|
||||
isExplicit(item) {
|
||||
return this.type === "album" && item.mark === 1056768;
|
||||
return this.type === 'album' && item.mark === 1056768;
|
||||
},
|
||||
getTitleLink(item) {
|
||||
return `/${this.type}/${item.id}`;
|
||||
},
|
||||
getImageUrl(item) {
|
||||
if (item.img1v1Url) {
|
||||
let img1v1ID = item.img1v1Url.split("/");
|
||||
let img1v1ID = item.img1v1Url.split('/');
|
||||
img1v1ID = img1v1ID[img1v1ID.length - 1];
|
||||
if (img1v1ID === "5639395138885805.jpg") {
|
||||
if (img1v1ID === '5639395138885805.jpg') {
|
||||
// 没有头像的歌手,网易云返回的img1v1Url并不是正方形的 😅😅😅
|
||||
return "https://p2.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg?param=512y512";
|
||||
return 'https://p2.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg?param=512y512';
|
||||
}
|
||||
}
|
||||
let img = item.img1v1Url || item.picUrl || item.coverImgUrl;
|
||||
|
|
|
|||
|
|
@ -18,24 +18,24 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapState, mapActions } from "vuex";
|
||||
import { dailyRecommendTracks } from "@/api/playlist";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import sample from "lodash/sample";
|
||||
import { mapMutations, mapState, mapActions } from 'vuex';
|
||||
import { dailyRecommendTracks } from '@/api/playlist';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
import sample from 'lodash/sample';
|
||||
|
||||
const defaultCovers = [
|
||||
"https://p2.music.126.net/0-Ybpa8FrDfRgKYCTJD8Xg==/109951164796696795.jpg",
|
||||
"https://p2.music.126.net/QxJA2mr4hhb9DZyucIOIQw==/109951165422200291.jpg",
|
||||
"https://p1.music.126.net/AhYP9TET8l-VSGOpWAKZXw==/109951165134386387.jpg",
|
||||
'https://p2.music.126.net/0-Ybpa8FrDfRgKYCTJD8Xg==/109951164796696795.jpg',
|
||||
'https://p2.music.126.net/QxJA2mr4hhb9DZyucIOIQw==/109951165422200291.jpg',
|
||||
'https://p1.music.126.net/AhYP9TET8l-VSGOpWAKZXw==/109951165134386387.jpg',
|
||||
];
|
||||
|
||||
export default {
|
||||
name: "DailyTracksCard",
|
||||
name: 'DailyTracksCard',
|
||||
data() {
|
||||
return { useAnimation: false };
|
||||
},
|
||||
computed: {
|
||||
...mapState(["dailyTracks"]),
|
||||
...mapState(['dailyTracks']),
|
||||
coverUrl() {
|
||||
return `${
|
||||
this.dailyTracks[0]?.al.picUrl || sample(defaultCovers)
|
||||
|
|
@ -46,29 +46,29 @@ export default {
|
|||
if (this.dailyTracks.length === 0) this.loadDailyTracks();
|
||||
},
|
||||
methods: {
|
||||
...mapActions(["showToast"]),
|
||||
...mapMutations(["updateDailyTracks"]),
|
||||
...mapActions(['showToast']),
|
||||
...mapMutations(['updateDailyTracks']),
|
||||
loadDailyTracks() {
|
||||
if (!isAccountLoggedIn()) return;
|
||||
dailyRecommendTracks()
|
||||
.then((result) => {
|
||||
.then(result => {
|
||||
this.updateDailyTracks(result.data.dailySongs);
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
goToDailyTracks() {
|
||||
this.$router.push({ name: "dailySongs" });
|
||||
this.$router.push({ name: 'dailySongs' });
|
||||
},
|
||||
playDailyTracks() {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
let trackIDs = this.dailyTracks.map((t) => t.id);
|
||||
let trackIDs = this.dailyTracks.map(t => t.id);
|
||||
this.$store.state.player.replacePlaylist(
|
||||
trackIDs,
|
||||
"/daily/songs",
|
||||
"url",
|
||||
'/daily/songs',
|
||||
'url',
|
||||
this.dailyTracks[0].id
|
||||
);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import SvgIcon from "@/components/SvgIcon.vue";
|
||||
import SvgIcon from '@/components/SvgIcon.vue';
|
||||
|
||||
export default {
|
||||
name: "ExplicitSymbol",
|
||||
name: 'ExplicitSymbol',
|
||||
components: {
|
||||
SvgIcon,
|
||||
},
|
||||
|
|
@ -23,8 +23,8 @@ export default {
|
|||
},
|
||||
created() {
|
||||
this.svgStyle = {
|
||||
height: this.size + "px",
|
||||
width: this.size + "px",
|
||||
height: this.size + 'px',
|
||||
width: this.size + 'px',
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -12,17 +12,17 @@
|
|||
</div>
|
||||
<div class="controls">
|
||||
<div class="buttons">
|
||||
<button-icon @click.native="moveToFMTrash" title="不喜欢"
|
||||
><svg-icon icon-class="thumbs-down" id="thumbs-down"
|
||||
<button-icon title="不喜欢" @click.native="moveToFMTrash"
|
||||
><svg-icon id="thumbs-down" icon-class="thumbs-down"
|
||||
/></button-icon>
|
||||
<button-icon
|
||||
:title="$t(isPlaying ? 'player.pause' : 'player.play')"
|
||||
class="play"
|
||||
@click.native="play"
|
||||
:title="$t(isPlaying ? 'player.pause' : 'player.play')"
|
||||
>
|
||||
<svg-icon :iconClass="isPlaying ? 'pause' : 'play'"
|
||||
<svg-icon :icon-class="isPlaying ? 'pause' : 'play'"
|
||||
/></button-icon>
|
||||
<button-icon @click.native="next" :title="$t('player.next')"
|
||||
<button-icon :title="$t('player.next')" @click.native="next"
|
||||
><svg-icon icon-class="next" /></button-icon
|
||||
></div>
|
||||
<div class="card-name"><svg-icon icon-class="fm" />私人FM</div>
|
||||
|
|
@ -32,15 +32,15 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import ButtonIcon from "@/components/ButtonIcon.vue";
|
||||
import ArtistsInLine from "@/components/ArtistsInLine.vue";
|
||||
import { mapState } from "vuex";
|
||||
import ButtonIcon from '@/components/ButtonIcon.vue';
|
||||
import ArtistsInLine from '@/components/ArtistsInLine.vue';
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "FMCard",
|
||||
name: 'FMCard',
|
||||
components: { ButtonIcon, ArtistsInLine },
|
||||
computed: {
|
||||
...mapState(["player"]),
|
||||
...mapState(['player']),
|
||||
track() {
|
||||
return this.player.personalFMTrack;
|
||||
},
|
||||
|
|
@ -60,7 +60,7 @@ export default {
|
|||
},
|
||||
goToAlbum() {
|
||||
if (this.track.album.id === 0) return;
|
||||
this.$router.push({ path: "/album/" + this.track.album.id });
|
||||
this.$router.push({ path: '/album/' + this.track.album.id });
|
||||
},
|
||||
moveToFMTrash() {
|
||||
this.player.moveToFMTrash();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="shade" @click="clickOutside" v-show="show">
|
||||
<div class="modal" @click.stop :style="modalStyles">
|
||||
<div v-show="show" class="shade" @click="clickOutside">
|
||||
<div class="modal" :style="modalStyles" @click.stop>
|
||||
<div class="header">
|
||||
<div class="title">{{ title }}</div>
|
||||
<button class="close" @click="close"
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
/></button>
|
||||
</div>
|
||||
<div class="content"><slot></slot></div>
|
||||
<div class="footer" v-if="showFooter">
|
||||
<div v-if="showFooter" class="footer">
|
||||
<!-- <button>取消</button>
|
||||
<button class="primary">确定</button> -->
|
||||
<slot name="footer"></slot>
|
||||
|
|
@ -19,13 +19,13 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "Modal",
|
||||
name: 'Modal',
|
||||
props: {
|
||||
show: Boolean,
|
||||
close: Function,
|
||||
title: {
|
||||
type: String,
|
||||
default: "Title",
|
||||
default: 'Title',
|
||||
},
|
||||
showFooter: {
|
||||
type: Boolean,
|
||||
|
|
@ -33,7 +33,7 @@ export default {
|
|||
},
|
||||
width: {
|
||||
type: String,
|
||||
default: "50vw",
|
||||
default: '50vw',
|
||||
},
|
||||
clickOutsideHide: {
|
||||
type: Boolean,
|
||||
|
|
@ -173,7 +173,7 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
.shade {
|
||||
background: rgba(0, 0, 0, 0.38);
|
||||
color: var(--color-text);
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
class="add-track-to-playlist-modal"
|
||||
:show="show"
|
||||
:close="close"
|
||||
:showFooter="false"
|
||||
:show-footer="false"
|
||||
title="添加到歌单"
|
||||
width="25vw"
|
||||
>
|
||||
|
|
@ -12,9 +12,9 @@
|
|||
><svg-icon icon-class="plus" />新建歌单</div
|
||||
>
|
||||
<div
|
||||
class="playlist"
|
||||
v-for="playlist in ownPlaylists"
|
||||
:key="playlist.id"
|
||||
class="playlist"
|
||||
@click="addTrackToPlaylist(playlist.id)"
|
||||
>
|
||||
<img :src="playlist.coverImgUrl | resizeImage(224)" />
|
||||
|
|
@ -28,13 +28,13 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapActions, mapMutations, mapState } from "vuex";
|
||||
import Modal from "@/components/Modal.vue";
|
||||
import { userPlaylist } from "@/api/user";
|
||||
import { addOrRemoveTrackFromPlaylist } from "@/api/playlist";
|
||||
import { mapActions, mapMutations, mapState } from 'vuex';
|
||||
import Modal from '@/components/Modal.vue';
|
||||
import { userPlaylist } from '@/api/user';
|
||||
import { addOrRemoveTrackFromPlaylist } from '@/api/playlist';
|
||||
|
||||
export default {
|
||||
name: "ModalAddTrackToPlaylist",
|
||||
name: 'ModalAddTrackToPlaylist',
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
|
|
@ -44,22 +44,22 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["modals", "data"]),
|
||||
...mapState(['modals', 'data']),
|
||||
show: {
|
||||
get() {
|
||||
return this.modals.addTrackToPlaylistModal.show;
|
||||
},
|
||||
set(value) {
|
||||
this.updateModal({
|
||||
modalName: "addTrackToPlaylistModal",
|
||||
key: "show",
|
||||
modalName: 'addTrackToPlaylistModal',
|
||||
key: 'show',
|
||||
value,
|
||||
});
|
||||
},
|
||||
},
|
||||
ownPlaylists() {
|
||||
return this.playlists.filter(
|
||||
(p) =>
|
||||
p =>
|
||||
p.creator.userId === this.data.user.userId &&
|
||||
p.id !== this.data.likedSongPlaylistID
|
||||
);
|
||||
|
|
@ -69,8 +69,8 @@ export default {
|
|||
this.getUserPlaylists();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateModal"]),
|
||||
...mapActions(["showToast"]),
|
||||
...mapMutations(['updateModal']),
|
||||
...mapActions(['showToast']),
|
||||
close() {
|
||||
this.show = false;
|
||||
},
|
||||
|
|
@ -79,19 +79,19 @@ export default {
|
|||
timestamp: new Date().getTime(),
|
||||
limit: 1000,
|
||||
uid: this.data.user.userId,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
this.playlists = data.playlist;
|
||||
});
|
||||
},
|
||||
addTrackToPlaylist(playlistID) {
|
||||
addOrRemoveTrackFromPlaylist({
|
||||
op: "add",
|
||||
op: 'add',
|
||||
pid: playlistID,
|
||||
tracks: this.modals.addTrackToPlaylistModal.selectedTrackID,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
if (data.body.code === 200) {
|
||||
this.show = false;
|
||||
this.showToast("已添加到歌单");
|
||||
this.showToast('已添加到歌单');
|
||||
} else {
|
||||
this.showToast(data.body.message);
|
||||
}
|
||||
|
|
@ -99,14 +99,14 @@ export default {
|
|||
},
|
||||
newPlaylist() {
|
||||
this.updateModal({
|
||||
modalName: "newPlaylistModal",
|
||||
key: "afterCreateAddTrackID",
|
||||
modalName: 'newPlaylistModal',
|
||||
key: 'afterCreateAddTrackID',
|
||||
value: this.modals.addTrackToPlaylistModal.selectedTrackID,
|
||||
});
|
||||
this.close();
|
||||
this.updateModal({
|
||||
modalName: "newPlaylistModal",
|
||||
key: "show",
|
||||
modalName: 'newPlaylistModal',
|
||||
key: 'show',
|
||||
value: true,
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -8,16 +8,16 @@
|
|||
>
|
||||
<template slot="default">
|
||||
<input
|
||||
v-model="title"
|
||||
type="text"
|
||||
placeholder="歌单标题"
|
||||
maxlength="40"
|
||||
v-model="title"
|
||||
/>
|
||||
<div class="checkbox">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="checkbox-private"
|
||||
v-model="privatePlaylist"
|
||||
type="checkbox"
|
||||
/>
|
||||
<label for="checkbox-private">设置为隐私歌单</label>
|
||||
</div>
|
||||
|
|
@ -29,57 +29,57 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import Modal from "@/components/Modal.vue";
|
||||
import { mapMutations, mapState } from "vuex";
|
||||
import { createPlaylist, addOrRemoveTrackFromPlaylist } from "@/api/playlist";
|
||||
import Modal from '@/components/Modal.vue';
|
||||
import { mapMutations, mapState } from 'vuex';
|
||||
import { createPlaylist, addOrRemoveTrackFromPlaylist } from '@/api/playlist';
|
||||
|
||||
export default {
|
||||
name: "ModalNewPlaylist",
|
||||
name: 'ModalNewPlaylist',
|
||||
components: {
|
||||
Modal,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
title: "",
|
||||
title: '',
|
||||
privatePlaylist: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["modals"]),
|
||||
...mapState(['modals']),
|
||||
show: {
|
||||
get() {
|
||||
return this.modals.newPlaylistModal.show;
|
||||
},
|
||||
set(value) {
|
||||
this.updateModal({
|
||||
modalName: "newPlaylistModal",
|
||||
key: "show",
|
||||
modalName: 'newPlaylistModal',
|
||||
key: 'show',
|
||||
value,
|
||||
});
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateModal"]),
|
||||
...mapMutations(['updateModal']),
|
||||
close() {
|
||||
this.show = false;
|
||||
this.title = "";
|
||||
this.title = '';
|
||||
this.privatePlaylist = false;
|
||||
this.resetAfterCreateAddTrackID();
|
||||
},
|
||||
createPlaylist() {
|
||||
let params = { name: this.title };
|
||||
if (this.private) params.type = 10;
|
||||
createPlaylist(params).then((data) => {
|
||||
createPlaylist(params).then(data => {
|
||||
if (data.code === 200) {
|
||||
if (this.modals.newPlaylistModal.afterCreateAddTrackID !== 0) {
|
||||
addOrRemoveTrackFromPlaylist({
|
||||
op: "add",
|
||||
op: 'add',
|
||||
pid: data.id,
|
||||
tracks: this.modals.newPlaylistModal.afterCreateAddTrackID,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
if (data.body.code === 200) {
|
||||
this.showToast("已添加到歌单");
|
||||
this.showToast('已添加到歌单');
|
||||
} else {
|
||||
this.showToast(data.body.message);
|
||||
}
|
||||
|
|
@ -87,14 +87,14 @@ export default {
|
|||
});
|
||||
}
|
||||
this.close();
|
||||
this.showToast("成功创建歌单");
|
||||
this.showToast('成功创建歌单');
|
||||
}
|
||||
});
|
||||
},
|
||||
resetAfterCreateAddTrackID() {
|
||||
this.updateModal({
|
||||
modalName: "newPlaylistModal",
|
||||
key: "AfterCreateAddTrackID",
|
||||
modalName: 'newPlaylistModal',
|
||||
key: 'AfterCreateAddTrackID',
|
||||
value: 0,
|
||||
});
|
||||
},
|
||||
|
|
@ -110,7 +110,7 @@ export default {
|
|||
input {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
input[type="text"] {
|
||||
input[type='text'] {
|
||||
width: calc(100% - 24px);
|
||||
flex: 1;
|
||||
background: var(--color-secondary-bg-for-transparent);
|
||||
|
|
@ -125,12 +125,12 @@ export default {
|
|||
background: var(--color-primary-bg-for-transparent);
|
||||
opacity: 1;
|
||||
}
|
||||
[data-theme="light"] &:focus {
|
||||
[data-theme='light'] &:focus {
|
||||
color: var(--color-primary);
|
||||
}
|
||||
}
|
||||
.checkbox {
|
||||
input[type="checkbox" i] {
|
||||
input[type='checkbox' i] {
|
||||
margin: 3px 3px 3px 4px;
|
||||
}
|
||||
display: flex;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="mv-row" :class="{ 'without-padding': withoutPadding }">
|
||||
<div class="mv" v-for="mv in mvs" :key="getID(mv)">
|
||||
<div v-for="mv in mvs" :key="getID(mv)" class="mv">
|
||||
<div
|
||||
class="cover"
|
||||
@mouseover="hoverVideoID = getID(mv)"
|
||||
|
|
@ -10,8 +10,8 @@
|
|||
<img :src="getUrl(mv)" />
|
||||
<transition name="fade">
|
||||
<div
|
||||
class="shadow"
|
||||
v-show="hoverVideoID === getID(mv)"
|
||||
class="shadow"
|
||||
:style="{ background: 'url(' + getUrl(mv) + ')' }"
|
||||
></div>
|
||||
</transition>
|
||||
|
|
@ -28,12 +28,12 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "CoverVideo",
|
||||
name: 'CoverVideo',
|
||||
props: {
|
||||
mvs: Array,
|
||||
subtitle: {
|
||||
type: String,
|
||||
default: "artist",
|
||||
default: 'artist',
|
||||
},
|
||||
withoutPadding: { type: Boolean, default: false },
|
||||
},
|
||||
|
|
@ -48,11 +48,11 @@ export default {
|
|||
if (this.$parent.player !== undefined) {
|
||||
query = { autoplay: this.$parent.player.playing };
|
||||
}
|
||||
this.$router.push({ path: "/mv/" + id, query });
|
||||
this.$router.push({ path: '/mv/' + id, query });
|
||||
},
|
||||
getUrl(mv) {
|
||||
let url = mv.imgurl16v9 ?? mv.cover ?? mv.coverUrl;
|
||||
return url.replace(/^http:/, "https:") + "?param=464y260";
|
||||
return url.replace(/^http:/, 'https:') + '?param=464y260';
|
||||
},
|
||||
getID(mv) {
|
||||
if (mv.id !== undefined) return mv.id;
|
||||
|
|
@ -63,8 +63,8 @@ export default {
|
|||
if (mv.title !== undefined) return mv.title;
|
||||
},
|
||||
getSubtitle(mv) {
|
||||
if (this.subtitle === "artist") {
|
||||
let artistName = "null";
|
||||
if (this.subtitle === 'artist') {
|
||||
let artistName = 'null';
|
||||
let artistID = 0;
|
||||
if (mv.artistName !== undefined) {
|
||||
artistName = mv.artistName;
|
||||
|
|
@ -74,7 +74,7 @@ export default {
|
|||
artistID = mv.creator[0].userId;
|
||||
}
|
||||
return `<a href="/#/artist/${artistID}">${artistName}</a>`;
|
||||
} else if (this.subtitle === "publishTime") {
|
||||
} else if (this.subtitle === 'publishTime') {
|
||||
return mv.publishTime;
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@
|
|||
></div>
|
||||
<div
|
||||
class="button max-restore codicon"
|
||||
@click="windowMaxRestore"
|
||||
:class="{
|
||||
'codicon-chrome-restore': !isWindowMaximized,
|
||||
'codicon-chrome-maximize': isWindowMaximized,
|
||||
}"
|
||||
@click="windowMaxRestore"
|
||||
></div>
|
||||
<div
|
||||
class="button close codicon codicon-chrome-close"
|
||||
|
|
@ -32,17 +32,17 @@
|
|||
</div>
|
||||
<div class="navigation-links">
|
||||
<router-link to="/" :class="{ active: this.$route.name === 'home' }">{{
|
||||
$t("nav.home")
|
||||
$t('nav.home')
|
||||
}}</router-link>
|
||||
<router-link
|
||||
to="/explore"
|
||||
:class="{ active: this.$route.name === 'explore' }"
|
||||
>{{ $t("nav.explore") }}</router-link
|
||||
>{{ $t('nav.explore') }}</router-link
|
||||
>
|
||||
<router-link
|
||||
to="/library"
|
||||
:class="{ active: this.$route.name === 'library' }"
|
||||
>{{ $t("nav.library") }}</router-link
|
||||
>{{ $t('nav.library') }}</router-link
|
||||
>
|
||||
</div>
|
||||
<div class="right-part">
|
||||
|
|
@ -52,8 +52,8 @@
|
|||
<div class="input">
|
||||
<input
|
||||
ref="searchInput"
|
||||
:placeholder="inputFocus ? '' : $t('nav.search')"
|
||||
v-model="keywords"
|
||||
:placeholder="inputFocus ? '' : $t('nav.search')"
|
||||
@keydown.enter="doSearch"
|
||||
@focus="inputFocus = true"
|
||||
@blur="inputFocus = false"
|
||||
|
|
@ -68,43 +68,43 @@
|
|||
<ContextMenu ref="userProfileMenu">
|
||||
<div class="item" @click="toSettings">
|
||||
<svg-icon icon-class="settings" />
|
||||
{{ $t("library.userProfileMenu.settings") }}
|
||||
{{ $t('library.userProfileMenu.settings') }}
|
||||
</div>
|
||||
<div class="item" @click="toLogin" v-if="!isLooseLoggedIn">
|
||||
<div v-if="!isLooseLoggedIn" class="item" @click="toLogin">
|
||||
<svg-icon icon-class="login" />
|
||||
{{ $t("login.login") }}
|
||||
{{ $t('login.login') }}
|
||||
</div>
|
||||
<div class="item" @click="logout" v-if="isLooseLoggedIn">
|
||||
<div v-if="isLooseLoggedIn" class="item" @click="logout">
|
||||
<svg-icon icon-class="logout" />
|
||||
{{ $t("library.userProfileMenu.logout") }}
|
||||
{{ $t('library.userProfileMenu.logout') }}
|
||||
</div>
|
||||
<hr />
|
||||
<div class="item" @click="toGitHub">
|
||||
<svg-icon icon-class="github" />
|
||||
{{ $t("nav.github") }}
|
||||
{{ $t('nav.github') }}
|
||||
</div>
|
||||
</ContextMenu>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import { isLooseLoggedIn, doLogout } from "@/utils/auth";
|
||||
import { mapState } from 'vuex';
|
||||
import { isLooseLoggedIn, doLogout } from '@/utils/auth';
|
||||
|
||||
// import icons for win32 title bar
|
||||
// icons by https://github.com/microsoft/vscode-codicons
|
||||
import "vscode-codicons/dist/codicon.css";
|
||||
import 'vscode-codicons/dist/codicon.css';
|
||||
|
||||
import ContextMenu from "@/components/ContextMenu.vue";
|
||||
import ButtonIcon from "@/components/ButtonIcon.vue";
|
||||
import ContextMenu from '@/components/ContextMenu.vue';
|
||||
import ButtonIcon from '@/components/ButtonIcon.vue';
|
||||
|
||||
const electron =
|
||||
process.env.IS_ELECTRON === true ? window.require("electron") : null;
|
||||
process.env.IS_ELECTRON === true ? window.require('electron') : null;
|
||||
const ipcRenderer =
|
||||
process.env.IS_ELECTRON === true ? electron.ipcRenderer : null;
|
||||
|
||||
export default {
|
||||
name: "Navbar",
|
||||
name: 'Navbar',
|
||||
components: {
|
||||
ButtonIcon,
|
||||
ContextMenu,
|
||||
|
|
@ -112,44 +112,44 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
inputFocus: false,
|
||||
langs: ["zh-CN", "en", "tr"],
|
||||
keywords: "",
|
||||
langs: ['zh-CN', 'en', 'tr'],
|
||||
keywords: '',
|
||||
isWindowMaximized: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["settings", "data"]),
|
||||
...mapState(['settings', 'data']),
|
||||
isLooseLoggedIn() {
|
||||
return isLooseLoggedIn();
|
||||
},
|
||||
avatarUrl() {
|
||||
return this.data?.user?.avatarUrl && this.isLooseLoggedIn
|
||||
? `${this.data?.user?.avatarUrl}?param=512y512`
|
||||
: "http://s4.music.126.net/style/web2/img/default/default_avatar.jpg?param=60y60";
|
||||
: 'http://s4.music.126.net/style/web2/img/default/default_avatar.jpg?param=60y60';
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (process.env.IS_ELECTRON === true) {
|
||||
ipcRenderer.on("isMaximized", (event, value) => {
|
||||
ipcRenderer.on('isMaximized', (event, value) => {
|
||||
this.isWindowMaximized = value;
|
||||
});
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
go(where) {
|
||||
if (where === "back") this.$router.go(-1);
|
||||
if (where === 'back') this.$router.go(-1);
|
||||
else this.$router.go(1);
|
||||
},
|
||||
doSearch() {
|
||||
if (!this.keywords) return;
|
||||
if (
|
||||
this.$route.name === "search" &&
|
||||
this.$route.name === 'search' &&
|
||||
this.$route.params.keywords === this.keywords
|
||||
) {
|
||||
return;
|
||||
}
|
||||
this.$router.push({
|
||||
name: "search",
|
||||
name: 'search',
|
||||
params: { keywords: this.keywords },
|
||||
});
|
||||
},
|
||||
|
|
@ -157,31 +157,31 @@ export default {
|
|||
this.$refs.userProfileMenu.openMenu(e);
|
||||
},
|
||||
logout() {
|
||||
if (!confirm("确定要退出登录吗?")) return;
|
||||
if (!confirm('确定要退出登录吗?')) return;
|
||||
doLogout();
|
||||
this.$router.push({ name: "home" });
|
||||
this.$router.push({ name: 'home' });
|
||||
},
|
||||
toSettings() {
|
||||
this.$router.push({ name: "settings" });
|
||||
this.$router.push({ name: 'settings' });
|
||||
},
|
||||
toGitHub() {
|
||||
window.open("https://github.com/qier222/YesPlayMusic");
|
||||
window.open('https://github.com/qier222/YesPlayMusic');
|
||||
},
|
||||
toLogin() {
|
||||
if (process.env.IS_ELECTRON === true) {
|
||||
this.$router.push({ name: "loginAccount" });
|
||||
this.$router.push({ name: 'loginAccount' });
|
||||
} else {
|
||||
this.$router.push({ name: "login" });
|
||||
this.$router.push({ name: 'login' });
|
||||
}
|
||||
},
|
||||
windowMinimize() {
|
||||
ipcRenderer.send("minimize");
|
||||
ipcRenderer.send('minimize');
|
||||
},
|
||||
windowMaxRestore() {
|
||||
ipcRenderer.send("maximizeOrUnmaximize");
|
||||
ipcRenderer.send('maximizeOrUnmaximize');
|
||||
},
|
||||
windowClose() {
|
||||
ipcRenderer.send("close");
|
||||
ipcRenderer.send('close');
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -224,7 +224,7 @@ nav {
|
|||
display: none;
|
||||
}
|
||||
|
||||
[data-electron-os="win32"] {
|
||||
[data-electron-os='win32'] {
|
||||
nav {
|
||||
padding-top: 20px;
|
||||
-webkit-app-region: no-drag;
|
||||
|
|
@ -244,7 +244,7 @@ nav {
|
|||
.title {
|
||||
padding: 8px;
|
||||
font-size: 12px;
|
||||
font-family: "Segoe UI", "Microsoft YaHei UI", "Microsoft YaHei",
|
||||
font-family: 'Segoe UI', 'Microsoft YaHei UI', 'Microsoft YaHei',
|
||||
sans-serif;
|
||||
}
|
||||
.controls {
|
||||
|
|
@ -278,7 +278,7 @@ nav {
|
|||
}
|
||||
}
|
||||
}
|
||||
&[data-theme="dark"] .win32-titlebar {
|
||||
&[data-theme='dark'] .win32-titlebar {
|
||||
--hover: #191919;
|
||||
--active: #333333;
|
||||
}
|
||||
|
|
@ -387,7 +387,7 @@ nav {
|
|||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
.search-box {
|
||||
.active {
|
||||
input,
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
<script>
|
||||
export default {
|
||||
name: "SvgIcon",
|
||||
name: 'SvgIcon',
|
||||
props: {
|
||||
iconClass: {
|
||||
type: String,
|
||||
|
|
@ -14,7 +14,7 @@ export default {
|
|||
},
|
||||
className: {
|
||||
type: String,
|
||||
default: "",
|
||||
default: '',
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -23,9 +23,9 @@ export default {
|
|||
},
|
||||
svgClass() {
|
||||
if (this.className) {
|
||||
return "svg-icon " + this.className;
|
||||
return 'svg-icon ' + this.className;
|
||||
} else {
|
||||
return "svg-icon";
|
||||
return 'svg-icon';
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
<template>
|
||||
<transition name="fade">
|
||||
<div class="toast" v-show="toast.show">{{ toast.text }}</div>
|
||||
<div v-show="toast.show" class="toast">{{ toast.text }}</div>
|
||||
</transition>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } from "vuex";
|
||||
import { mapState } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "Toast",
|
||||
name: 'Toast',
|
||||
computed: {
|
||||
...mapState(["toast"]),
|
||||
...mapState(['toast']),
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
@ -33,7 +33,7 @@ export default {
|
|||
z-index: 100;
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
.toast {
|
||||
background: rgba(46, 46, 46, 0.68);
|
||||
backdrop-filter: blur(16px) contrast(120%);
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@
|
|||
@mouseleave="hover = false"
|
||||
>
|
||||
<img
|
||||
:src="imgUrl"
|
||||
v-if="!isAlbum"
|
||||
@click="goToAlbum"
|
||||
:src="imgUrl"
|
||||
:class="{ hover: focus }"
|
||||
@click="goToAlbum"
|
||||
/>
|
||||
<div class="no" v-if="isAlbum">
|
||||
<div v-if="isAlbum" class="no">
|
||||
<button v-show="focus && track.playable && !isPlaying" @click="playTrack">
|
||||
<svg-icon
|
||||
icon-class="play"
|
||||
|
|
@ -34,7 +34,7 @@
|
|||
<div class="container">
|
||||
<div class="title">
|
||||
{{ track.name }}
|
||||
<span class="featured" v-if="isAlbum">
|
||||
<span v-if="isAlbum" class="featured">
|
||||
<ArtistsInLine
|
||||
:artists="track.ar"
|
||||
:exclude="this.$parent.albumObject.artist.name"
|
||||
|
|
@ -44,7 +44,7 @@
|
|||
><ExplicitSymbol
|
||||
/></span>
|
||||
</div>
|
||||
<div class="artist" v-if="!isAlbum">
|
||||
<div v-if="!isAlbum" class="artist">
|
||||
<span
|
||||
v-if="track.mark === 1318912"
|
||||
class="explicit-symbol before-artist"
|
||||
|
|
@ -55,11 +55,11 @@
|
|||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="album" v-if="!isTracklist && !isAlbum">
|
||||
<div v-if="!isTracklist && !isAlbum" class="album">
|
||||
<router-link :to="`/album/${album.id}`">{{ album.name }}</router-link>
|
||||
<div></div>
|
||||
</div>
|
||||
<div class="actions" v-if="!isTracklist">
|
||||
<div v-if="!isTracklist" class="actions">
|
||||
<button @click="likeThisSong">
|
||||
<svg-icon
|
||||
icon-class="heart"
|
||||
|
|
@ -67,10 +67,10 @@
|
|||
visibility: focus && !isLiked ? 'visible' : 'hidden',
|
||||
}"
|
||||
></svg-icon>
|
||||
<svg-icon icon-class="heart-solid" v-show="isLiked"></svg-icon>
|
||||
<svg-icon v-show="isLiked" icon-class="heart-solid"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div class="time" v-if="!isTracklist">
|
||||
<div v-if="!isTracklist" class="time">
|
||||
{{ track.dt | formatTime }}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,24 +1,24 @@
|
|||
const { Menu } = require("electron");
|
||||
const { Menu } = require('electron');
|
||||
|
||||
export function createDockMenu(win) {
|
||||
return Menu.buildFromTemplate([
|
||||
{
|
||||
label: "Play",
|
||||
label: 'Play',
|
||||
click() {
|
||||
win.webContents.send("play");
|
||||
win.webContents.send('play');
|
||||
},
|
||||
},
|
||||
{ type: "separator" },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: "Next",
|
||||
label: 'Next',
|
||||
click() {
|
||||
win.webContents.send("next");
|
||||
win.webContents.send('next');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Previous",
|
||||
label: 'Previous',
|
||||
click() {
|
||||
win.webContents.send("previous");
|
||||
win.webContents.send('previous');
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
const { globalShortcut } = require("electron");
|
||||
const { globalShortcut } = require('electron');
|
||||
|
||||
export function registerGlobalShortcut(win) {
|
||||
globalShortcut.register("Alt+CommandOrControl+P", () => {
|
||||
win.webContents.send("play");
|
||||
globalShortcut.register('Alt+CommandOrControl+P', () => {
|
||||
win.webContents.send('play');
|
||||
});
|
||||
globalShortcut.register("Alt+CommandOrControl+Right", () => {
|
||||
win.webContents.send("next");
|
||||
globalShortcut.register('Alt+CommandOrControl+Right', () => {
|
||||
win.webContents.send('next');
|
||||
});
|
||||
globalShortcut.register("Alt+CommandOrControl+Left", () => {
|
||||
win.webContents.send("previous");
|
||||
globalShortcut.register('Alt+CommandOrControl+Left', () => {
|
||||
win.webContents.send('previous');
|
||||
});
|
||||
globalShortcut.register("Alt+CommandOrControl+Up", () => {
|
||||
win.webContents.send("increaseVolume");
|
||||
globalShortcut.register('Alt+CommandOrControl+Up', () => {
|
||||
win.webContents.send('increaseVolume');
|
||||
});
|
||||
globalShortcut.register("Alt+CommandOrControl+Down", () => {
|
||||
win.webContents.send("decreaseVolume");
|
||||
globalShortcut.register('Alt+CommandOrControl+Down', () => {
|
||||
win.webContents.send('decreaseVolume');
|
||||
});
|
||||
globalShortcut.register("Alt+CommandOrControl+L", () => {
|
||||
win.webContents.send("like");
|
||||
globalShortcut.register('Alt+CommandOrControl+L', () => {
|
||||
win.webContents.send('like');
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,48 +1,48 @@
|
|||
import { app, dialog, globalShortcut, ipcMain } from "electron";
|
||||
import match from "@njzy/unblockneteasemusic";
|
||||
import { registerGlobalShortcut } from "@/electron/globalShortcut";
|
||||
import { app, dialog, globalShortcut, ipcMain } from 'electron';
|
||||
import match from '@njzy/unblockneteasemusic';
|
||||
import { registerGlobalShortcut } from '@/electron/globalShortcut';
|
||||
|
||||
const client = require("discord-rich-presence")("818936529484906596");
|
||||
const client = require('discord-rich-presence')('818936529484906596');
|
||||
|
||||
export function initIpcMain(win, store) {
|
||||
ipcMain.on("unblock-music", (event, track) => {
|
||||
ipcMain.on('unblock-music', (event, track) => {
|
||||
// 兼容 unblockneteasemusic 所使用的 api 字段
|
||||
track.alias = track.alia || [];
|
||||
track.duration = track.dt || 0;
|
||||
track.album = track.al || [];
|
||||
track.artists = track.ar || [];
|
||||
|
||||
const matchPromise = match(track.id, ["qq", "kuwo", "migu"], track);
|
||||
const matchPromise = match(track.id, ['qq', 'kuwo', 'migu'], track);
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
setTimeout(() => {
|
||||
reject("timeout");
|
||||
reject('timeout');
|
||||
}, 3000);
|
||||
});
|
||||
Promise.race([matchPromise, timeoutPromise])
|
||||
.then((res) => {
|
||||
.then(res => {
|
||||
event.returnValue = res;
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log("unblock music error: ", err);
|
||||
.catch(err => {
|
||||
console.log('unblock music error: ', err);
|
||||
event.returnValue = null;
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("close", (e) => {
|
||||
if (process.platform == "darwin") {
|
||||
ipcMain.on('close', e => {
|
||||
if (process.platform == 'darwin') {
|
||||
win.hide();
|
||||
}
|
||||
e.preventDefault(); //阻止默认行为
|
||||
dialog
|
||||
.showMessageBox({
|
||||
type: "info",
|
||||
title: "Information",
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
cancelId: 2,
|
||||
defaultId: 0,
|
||||
message: "确定要关闭吗?",
|
||||
buttons: ["最小化", "直接退出"],
|
||||
message: '确定要关闭吗?',
|
||||
buttons: ['最小化', '直接退出'],
|
||||
})
|
||||
.then((result) => {
|
||||
.then(result => {
|
||||
if (result.response == 0) {
|
||||
e.preventDefault(); //阻止默认行为
|
||||
win.minimize(); //调用 最小化实例方法
|
||||
|
|
@ -52,25 +52,25 @@ export function initIpcMain(win, store) {
|
|||
app.exit(); //exit()直接关闭客户端,不会执行quit();
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
.catch(err => {
|
||||
console.log(err);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("minimize", () => {
|
||||
ipcMain.on('minimize', () => {
|
||||
win.minimize();
|
||||
});
|
||||
|
||||
ipcMain.on("maximizeOrUnmaximize", () => {
|
||||
ipcMain.on('maximizeOrUnmaximize', () => {
|
||||
const isMaximized = win.isMaximized();
|
||||
isMaximized ? win.unmaximize() : win.maximize();
|
||||
win.webContents.send("isMaximized", isMaximized);
|
||||
win.webContents.send('isMaximized', isMaximized);
|
||||
});
|
||||
|
||||
ipcMain.on("settings", (event, options) => {
|
||||
store.set("settings", options);
|
||||
ipcMain.on('settings', (event, options) => {
|
||||
store.set('settings', options);
|
||||
const isRegisterShortcut = globalShortcut.isRegistered(
|
||||
"Alt+CommandOrControl+P"
|
||||
'Alt+CommandOrControl+P'
|
||||
);
|
||||
if (options.enableGlobalShortcut) {
|
||||
!isRegisterShortcut && registerGlobalShortcut(win);
|
||||
|
|
@ -79,27 +79,27 @@ export function initIpcMain(win, store) {
|
|||
}
|
||||
});
|
||||
|
||||
ipcMain.on("playDiscordPresence", (event, track) => {
|
||||
ipcMain.on('playDiscordPresence', (event, track) => {
|
||||
client.updatePresence({
|
||||
details: track.name + " - " + track.ar.map((ar) => ar.name).join(","),
|
||||
details: track.name + ' - ' + track.ar.map(ar => ar.name).join(','),
|
||||
state: track.al.name,
|
||||
endTimestamp: Date.now() + track.dt,
|
||||
largeImageKey: "logo",
|
||||
largeImageText: "Listening " + track.name,
|
||||
smallImageKey: "play",
|
||||
smallImageText: "Playing",
|
||||
largeImageKey: 'logo',
|
||||
largeImageText: 'Listening ' + track.name,
|
||||
smallImageKey: 'play',
|
||||
smallImageText: 'Playing',
|
||||
instance: true,
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on("pauseDiscordPresence", (event, track) => {
|
||||
ipcMain.on('pauseDiscordPresence', (event, track) => {
|
||||
client.updatePresence({
|
||||
details: track.name + " - " + track.ar.map((ar) => ar.name).join(","),
|
||||
details: track.name + ' - ' + track.ar.map(ar => ar.name).join(','),
|
||||
state: track.al.name,
|
||||
largeImageKey: "logo",
|
||||
largeImageText: "YesPlayMusic",
|
||||
smallImageKey: "pause",
|
||||
smallImageText: "Pause",
|
||||
largeImageKey: 'logo',
|
||||
largeImageText: 'YesPlayMusic',
|
||||
smallImageKey: 'pause',
|
||||
smallImageText: 'Pause',
|
||||
instance: true,
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
const { app, Menu } = require("electron");
|
||||
const { app, Menu } = require('electron');
|
||||
// import { autoUpdater } from "electron-updater"
|
||||
// const version = app.getVersion();
|
||||
|
||||
const isMac = process.platform === "darwin";
|
||||
const isMac = process.platform === 'darwin';
|
||||
|
||||
export function createMenu(win) {
|
||||
let menu = null;
|
||||
|
|
@ -12,142 +12,142 @@ export function createMenu(win) {
|
|||
{
|
||||
label: app.name,
|
||||
submenu: [
|
||||
{ role: "about" },
|
||||
{ type: "separator" },
|
||||
{ role: "services" },
|
||||
{ type: "separator" },
|
||||
{ type: "separator" },
|
||||
{ role: 'about' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'services' },
|
||||
{ type: 'separator' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: "Preferences...",
|
||||
accelerator: (() => (isMac ? "CmdOrCtrl+," : "Ctrl+,"))(),
|
||||
label: 'Preferences...',
|
||||
accelerator: (() => (isMac ? 'CmdOrCtrl+,' : 'Ctrl+,'))(),
|
||||
click: () => {
|
||||
win.webContents.send("changeRouteTo", "/settings");
|
||||
win.webContents.send('changeRouteTo', '/settings');
|
||||
},
|
||||
role: "preferences",
|
||||
role: 'preferences',
|
||||
},
|
||||
{ type: "separator" },
|
||||
{ role: "hide" },
|
||||
{ role: "hideothers" },
|
||||
{ role: "unhide" },
|
||||
{ type: "separator" },
|
||||
{ role: "quit" },
|
||||
{ type: 'separator' },
|
||||
{ role: 'hide' },
|
||||
{ role: 'hideothers' },
|
||||
{ role: 'unhide' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'quit' },
|
||||
],
|
||||
},
|
||||
]
|
||||
: []),
|
||||
{
|
||||
label: "Edit",
|
||||
label: 'Edit',
|
||||
submenu: [
|
||||
{ role: "undo" },
|
||||
{ role: "redo" },
|
||||
{ type: "separator" },
|
||||
{ role: "cut" },
|
||||
{ role: "copy" },
|
||||
{ role: "paste" },
|
||||
{ role: 'undo' },
|
||||
{ role: 'redo' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'cut' },
|
||||
{ role: 'copy' },
|
||||
{ role: 'paste' },
|
||||
...(isMac
|
||||
? [
|
||||
{ role: "delete" },
|
||||
{ role: "selectAll" },
|
||||
{ type: "separator" },
|
||||
{ role: 'delete' },
|
||||
{ role: 'selectAll' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
label: "Speech",
|
||||
submenu: [{ role: "startspeaking" }, { role: "stopspeaking" }],
|
||||
label: 'Speech',
|
||||
submenu: [{ role: 'startspeaking' }, { role: 'stopspeaking' }],
|
||||
},
|
||||
]
|
||||
: [{ role: "delete" }, { type: "separator" }, { role: "selectAll" }]),
|
||||
: [{ role: 'delete' }, { type: 'separator' }, { role: 'selectAll' }]),
|
||||
{
|
||||
label: "Search",
|
||||
accelerator: "CmdOrCtrl+F",
|
||||
label: 'Search',
|
||||
accelerator: 'CmdOrCtrl+F',
|
||||
click: () => {
|
||||
win.webContents.send("search");
|
||||
win.webContents.send('search');
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Controls",
|
||||
label: 'Controls',
|
||||
submenu: [
|
||||
{
|
||||
label: "Play",
|
||||
label: 'Play',
|
||||
click: () => {
|
||||
win.webContents.send("play");
|
||||
win.webContents.send('play');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Next",
|
||||
accelerator: "CmdOrCtrl+Right",
|
||||
label: 'Next',
|
||||
accelerator: 'CmdOrCtrl+Right',
|
||||
click: () => {
|
||||
win.webContents.send("next");
|
||||
win.webContents.send('next');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Previous",
|
||||
accelerator: "CmdOrCtrl+Left",
|
||||
label: 'Previous',
|
||||
accelerator: 'CmdOrCtrl+Left',
|
||||
click: () => {
|
||||
win.webContents.send("previous");
|
||||
win.webContents.send('previous');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Increase Volume",
|
||||
accelerator: "CmdOrCtrl+Up",
|
||||
label: 'Increase Volume',
|
||||
accelerator: 'CmdOrCtrl+Up',
|
||||
click: () => {
|
||||
win.webContents.send("increaseVolume");
|
||||
win.webContents.send('increaseVolume');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Decrease Volume",
|
||||
accelerator: "CmdOrCtrl+Down",
|
||||
label: 'Decrease Volume',
|
||||
accelerator: 'CmdOrCtrl+Down',
|
||||
click: () => {
|
||||
win.webContents.send("decreaseVolume");
|
||||
win.webContents.send('decreaseVolume');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Like",
|
||||
accelerator: "CmdOrCtrl+L",
|
||||
label: 'Like',
|
||||
accelerator: 'CmdOrCtrl+L',
|
||||
click: () => {
|
||||
win.webContents.send("like");
|
||||
win.webContents.send('like');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Repeat",
|
||||
accelerator: "Alt+R",
|
||||
label: 'Repeat',
|
||||
accelerator: 'Alt+R',
|
||||
click: () => {
|
||||
win.webContents.send("repeat");
|
||||
win.webContents.send('repeat');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Shuffle",
|
||||
accelerator: "Alt+S",
|
||||
label: 'Shuffle',
|
||||
accelerator: 'Alt+S',
|
||||
click: () => {
|
||||
win.webContents.send("shuffle");
|
||||
win.webContents.send('shuffle');
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Window",
|
||||
label: 'Window',
|
||||
submenu: [
|
||||
{ role: "close" },
|
||||
{ role: "minimize" },
|
||||
{ role: "zoom" },
|
||||
{ role: "reload" },
|
||||
{ role: "forcereload" },
|
||||
{ role: "toggledevtools" },
|
||||
{ type: "separator" },
|
||||
{ role: "togglefullscreen" },
|
||||
{ role: 'close' },
|
||||
{ role: 'minimize' },
|
||||
{ role: 'zoom' },
|
||||
{ role: 'reload' },
|
||||
{ role: 'forcereload' },
|
||||
{ role: 'toggledevtools' },
|
||||
{ type: 'separator' },
|
||||
{ role: 'togglefullscreen' },
|
||||
...(isMac
|
||||
? [
|
||||
{ type: "separator" },
|
||||
{ role: "front" },
|
||||
{ type: "separator" },
|
||||
{ type: 'separator' },
|
||||
{ role: 'front' },
|
||||
{ type: 'separator' },
|
||||
{
|
||||
role: "window",
|
||||
id: "window",
|
||||
label: "YesPlayMusic",
|
||||
type: "checkbox",
|
||||
role: 'window',
|
||||
id: 'window',
|
||||
label: 'YesPlayMusic',
|
||||
type: 'checkbox',
|
||||
checked: true,
|
||||
click: () => {
|
||||
const current = menu.getMenuItemById("window");
|
||||
const current = menu.getMenuItemById('window');
|
||||
if (current.checked === false) {
|
||||
win.hide();
|
||||
} else {
|
||||
|
|
@ -156,29 +156,29 @@ export function createMenu(win) {
|
|||
},
|
||||
},
|
||||
]
|
||||
: [{ role: "close" }]),
|
||||
: [{ role: 'close' }]),
|
||||
],
|
||||
},
|
||||
{
|
||||
label: "Help",
|
||||
label: 'Help',
|
||||
submenu: [
|
||||
{
|
||||
label: "GitHub",
|
||||
label: 'GitHub',
|
||||
click: async () => {
|
||||
const { shell } = require("electron");
|
||||
await shell.openExternal("https://github.com/qier222/YesPlayMusic");
|
||||
const { shell } = require('electron');
|
||||
await shell.openExternal('https://github.com/qier222/YesPlayMusic');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "Electron",
|
||||
label: 'Electron',
|
||||
click: async () => {
|
||||
const { shell } = require("electron");
|
||||
await shell.openExternal("https://electronjs.org");
|
||||
const { shell } = require('electron');
|
||||
await shell.openExternal('https://electronjs.org');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "开发者工具",
|
||||
accelerator: "F12",
|
||||
label: '开发者工具',
|
||||
accelerator: 'F12',
|
||||
click: () => {
|
||||
win.webContents.openDevTools();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
const { TouchBar, nativeImage, ipcMain } = require("electron");
|
||||
const { TouchBar, nativeImage, ipcMain } = require('electron');
|
||||
const { TouchBarButton, TouchBarSpacer } = TouchBar;
|
||||
const path = require("path");
|
||||
const path = require('path');
|
||||
|
||||
export function createTouchBar(window) {
|
||||
const renderer = window.webContents;
|
||||
|
|
@ -11,72 +11,72 @@ export function createTouchBar(window) {
|
|||
function getNativeIcon(name) {
|
||||
return nativeImage.createFromPath(
|
||||
// eslint-disable-next-line no-undef
|
||||
path.join(__static, "img/touchbar/", name)
|
||||
path.join(__static, 'img/touchbar/', name)
|
||||
);
|
||||
}
|
||||
|
||||
const previousPage = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("routerGo", "back");
|
||||
renderer.send('routerGo', 'back');
|
||||
},
|
||||
icon: getNativeIcon("page_prev.png"),
|
||||
icon: getNativeIcon('page_prev.png'),
|
||||
});
|
||||
|
||||
const nextPage = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("routerGo", "forward");
|
||||
renderer.send('routerGo', 'forward');
|
||||
},
|
||||
icon: getNativeIcon("page_next.png"),
|
||||
icon: getNativeIcon('page_next.png'),
|
||||
});
|
||||
|
||||
const searchButton = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("search");
|
||||
renderer.send('search');
|
||||
},
|
||||
icon: getNativeIcon("search.png"),
|
||||
icon: getNativeIcon('search.png'),
|
||||
});
|
||||
|
||||
const playButton = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("play");
|
||||
renderer.send('play');
|
||||
},
|
||||
icon: getNativeIcon("play.png"),
|
||||
icon: getNativeIcon('play.png'),
|
||||
});
|
||||
|
||||
const previousTrackButton = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("previous");
|
||||
renderer.send('previous');
|
||||
},
|
||||
icon: getNativeIcon("backward.png"),
|
||||
icon: getNativeIcon('backward.png'),
|
||||
});
|
||||
|
||||
const nextTrackButton = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("next");
|
||||
renderer.send('next');
|
||||
},
|
||||
icon: getNativeIcon("forward.png"),
|
||||
icon: getNativeIcon('forward.png'),
|
||||
});
|
||||
|
||||
const likeButton = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("like");
|
||||
renderer.send('like');
|
||||
},
|
||||
icon: getNativeIcon("like.png"),
|
||||
icon: getNativeIcon('like.png'),
|
||||
});
|
||||
|
||||
const nextUpButton = new TouchBarButton({
|
||||
click: () => {
|
||||
renderer.send("nextUp");
|
||||
renderer.send('nextUp');
|
||||
},
|
||||
icon: getNativeIcon("next_up.png"),
|
||||
icon: getNativeIcon('next_up.png'),
|
||||
});
|
||||
|
||||
ipcMain.on("player", (e, { playing, likedCurrentTrack }) => {
|
||||
ipcMain.on('player', (e, { playing, likedCurrentTrack }) => {
|
||||
playButton.icon =
|
||||
playing === true ? getNativeIcon("pause.png") : getNativeIcon("play.png");
|
||||
playing === true ? getNativeIcon('pause.png') : getNativeIcon('play.png');
|
||||
likeButton.icon = likedCurrentTrack
|
||||
? getNativeIcon("like_fill.png")
|
||||
: getNativeIcon("like.png");
|
||||
? getNativeIcon('like_fill.png')
|
||||
: getNativeIcon('like.png');
|
||||
});
|
||||
|
||||
const touchBar = new TouchBar({
|
||||
|
|
@ -84,11 +84,11 @@ export function createTouchBar(window) {
|
|||
previousPage,
|
||||
nextPage,
|
||||
searchButton,
|
||||
new TouchBarSpacer({ size: "flexible" }),
|
||||
new TouchBarSpacer({ size: 'flexible' }),
|
||||
previousTrackButton,
|
||||
playButton,
|
||||
nextTrackButton,
|
||||
new TouchBarSpacer({ size: "flexible" }),
|
||||
new TouchBarSpacer({ size: 'flexible' }),
|
||||
likeButton,
|
||||
nextUpButton,
|
||||
],
|
||||
|
|
|
|||
|
|
@ -1,79 +1,79 @@
|
|||
/* global __static */
|
||||
import path from "path";
|
||||
import { app, nativeImage, Tray, Menu } from "electron";
|
||||
import path from 'path';
|
||||
import { app, nativeImage, Tray, Menu } from 'electron';
|
||||
|
||||
export function createTray(win) {
|
||||
let icon = nativeImage
|
||||
.createFromPath(path.join(__static, "img/icons/menu@88.png"))
|
||||
.createFromPath(path.join(__static, 'img/icons/menu@88.png'))
|
||||
.resize({
|
||||
height: 20,
|
||||
width: 20,
|
||||
});
|
||||
let tray = new Tray(icon);
|
||||
|
||||
tray.setToolTip("YesPlayMusic");
|
||||
tray.setToolTip('YesPlayMusic');
|
||||
|
||||
tray.on("click", () => {
|
||||
tray.on('click', () => {
|
||||
win.show();
|
||||
});
|
||||
|
||||
tray.on("right-click", () => {
|
||||
tray.on('right-click', () => {
|
||||
const contextMenu = Menu.buildFromTemplate([
|
||||
{
|
||||
label: "播放/暂停",
|
||||
label: '播放/暂停',
|
||||
icon: nativeImage.createFromPath(
|
||||
path.join(__static, "img/icons/play.png")
|
||||
path.join(__static, 'img/icons/play.png')
|
||||
),
|
||||
click: () => {
|
||||
win.webContents.send("play");
|
||||
win.webContents.send('play');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "上一首",
|
||||
label: '上一首',
|
||||
icon: nativeImage.createFromPath(
|
||||
path.join(__static, "img/icons/left.png")
|
||||
path.join(__static, 'img/icons/left.png')
|
||||
),
|
||||
accelerator: "CmdOrCtrl+Left",
|
||||
accelerator: 'CmdOrCtrl+Left',
|
||||
click: () => {
|
||||
win.webContents.send("previous");
|
||||
win.webContents.send('previous');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "下一首",
|
||||
label: '下一首',
|
||||
icon: nativeImage.createFromPath(
|
||||
path.join(__static, "img/icons/right.png")
|
||||
path.join(__static, 'img/icons/right.png')
|
||||
),
|
||||
accelerator: "CmdOrCtrl+Right",
|
||||
accelerator: 'CmdOrCtrl+Right',
|
||||
click: () => {
|
||||
win.webContents.send("next");
|
||||
win.webContents.send('next');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "循环播放",
|
||||
label: '循环播放',
|
||||
icon: nativeImage.createFromPath(
|
||||
path.join(__static, "img/icons/repeat.png")
|
||||
path.join(__static, 'img/icons/repeat.png')
|
||||
),
|
||||
accelerator: "Alt+R",
|
||||
accelerator: 'Alt+R',
|
||||
click: () => {
|
||||
win.webContents.send("repeat");
|
||||
win.webContents.send('repeat');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "加入喜欢",
|
||||
label: '加入喜欢',
|
||||
icon: nativeImage.createFromPath(
|
||||
path.join(__static, "img/icons/like.png")
|
||||
path.join(__static, 'img/icons/like.png')
|
||||
),
|
||||
accelerator: "CmdOrCtrl+L",
|
||||
accelerator: 'CmdOrCtrl+L',
|
||||
click: () => {
|
||||
win.webContents.send("like");
|
||||
win.webContents.send('like');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: "退出",
|
||||
label: '退出',
|
||||
icon: nativeImage.createFromPath(
|
||||
path.join(__static, "img/icons/exit.png")
|
||||
path.join(__static, 'img/icons/exit.png')
|
||||
),
|
||||
accelerator: "CmdOrCtrl+W",
|
||||
accelerator: 'CmdOrCtrl+W',
|
||||
click: () => {
|
||||
app.exit();
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import Vue from "vue";
|
||||
import VueI18n from "vue-i18n";
|
||||
import store from "@/store";
|
||||
import Vue from 'vue';
|
||||
import VueI18n from 'vue-i18n';
|
||||
import store from '@/store';
|
||||
|
||||
import en from "./lang/en.js";
|
||||
import zhCN from "./lang/zh-CN.js";
|
||||
import tr from "./lang/tr.js";
|
||||
import en from './lang/en.js';
|
||||
import zhCN from './lang/zh-CN.js';
|
||||
import tr from './lang/tr.js';
|
||||
|
||||
Vue.use(VueI18n);
|
||||
|
||||
|
|
@ -12,7 +12,7 @@ const i18n = new VueI18n({
|
|||
locale: store.state.settings.lang,
|
||||
messages: {
|
||||
en,
|
||||
"zh-CN": zhCN,
|
||||
'zh-CN': zhCN,
|
||||
tr,
|
||||
},
|
||||
silentTranslationWarn: true,
|
||||
|
|
|
|||
|
|
@ -1,81 +1,81 @@
|
|||
export default {
|
||||
common: {
|
||||
play: "PLAY",
|
||||
songs: "Songs",
|
||||
play: 'PLAY',
|
||||
songs: 'Songs',
|
||||
},
|
||||
nav: {
|
||||
home: "Home",
|
||||
explore: "Explore",
|
||||
library: "Library",
|
||||
search: "Search",
|
||||
github: "GitHub Repo",
|
||||
home: 'Home',
|
||||
explore: 'Explore',
|
||||
library: 'Library',
|
||||
search: 'Search',
|
||||
github: 'GitHub Repo',
|
||||
},
|
||||
footer: {
|
||||
settings: "Settings",
|
||||
settings: 'Settings',
|
||||
},
|
||||
home: {
|
||||
recommendPlaylist: "Recommended Playlists",
|
||||
recommendArtist: "Recommended Artists",
|
||||
newAlbum: "Latest Albums",
|
||||
seeMore: "SEE MORE",
|
||||
charts: "Charts",
|
||||
recommendPlaylist: 'Recommended Playlists',
|
||||
recommendArtist: 'Recommended Artists',
|
||||
newAlbum: 'Latest Albums',
|
||||
seeMore: 'SEE MORE',
|
||||
charts: 'Charts',
|
||||
},
|
||||
library: {
|
||||
sLibrary: "'s Library",
|
||||
likedSongs: "Liked Songs",
|
||||
likedSongs: 'Liked Songs',
|
||||
sLikedSongs: "'s Liked Songs",
|
||||
playlists: "Playlists",
|
||||
albums: "Albums",
|
||||
artists: "Artists",
|
||||
mvs: "MVs",
|
||||
newPlayList: "New Playlist",
|
||||
playlists: 'Playlists',
|
||||
albums: 'Albums',
|
||||
artists: 'Artists',
|
||||
mvs: 'MVs',
|
||||
newPlayList: 'New Playlist',
|
||||
userProfileMenu: {
|
||||
settings: "Settings",
|
||||
logout: "Logout",
|
||||
settings: 'Settings',
|
||||
logout: 'Logout',
|
||||
},
|
||||
},
|
||||
explore: {
|
||||
explore: "Explore",
|
||||
loadMore: "Load More",
|
||||
explore: 'Explore',
|
||||
loadMore: 'Load More',
|
||||
},
|
||||
artist: {
|
||||
latestRelease: "Latest Releases",
|
||||
popularSongs: "Popular Songs",
|
||||
showMore: "SHOW MORE",
|
||||
showLess: "SHOW LESS",
|
||||
EPsSingles: "EPs & Singles",
|
||||
albums: "Albums",
|
||||
withAlbums: "Albums",
|
||||
artist: "Artist",
|
||||
videos: "Music Videos",
|
||||
following: "Following",
|
||||
follow: "Follow",
|
||||
latestRelease: 'Latest Releases',
|
||||
popularSongs: 'Popular Songs',
|
||||
showMore: 'SHOW MORE',
|
||||
showLess: 'SHOW LESS',
|
||||
EPsSingles: 'EPs & Singles',
|
||||
albums: 'Albums',
|
||||
withAlbums: 'Albums',
|
||||
artist: 'Artist',
|
||||
videos: 'Music Videos',
|
||||
following: 'Following',
|
||||
follow: 'Follow',
|
||||
},
|
||||
album: {
|
||||
released: "Released",
|
||||
released: 'Released',
|
||||
},
|
||||
playlist: {
|
||||
playlist: "Playlists",
|
||||
updatedAt: "Updated at",
|
||||
search: "Search in playlist",
|
||||
playlist: 'Playlists',
|
||||
updatedAt: 'Updated at',
|
||||
search: 'Search in playlist',
|
||||
},
|
||||
login: {
|
||||
accessToAll: "Access to all data",
|
||||
loginText: "Login to Netease",
|
||||
search: "Search account",
|
||||
readonly: "Only access to public data",
|
||||
usernameLogin: "Username Login",
|
||||
searchHolder: "Your account username",
|
||||
accessToAll: 'Access to all data',
|
||||
loginText: 'Login to Netease',
|
||||
search: 'Search account',
|
||||
readonly: 'Only access to public data',
|
||||
usernameLogin: 'Username Login',
|
||||
searchHolder: 'Your account username',
|
||||
enterTip: "Press 'enter' to search",
|
||||
choose: "Choose your account",
|
||||
confirm: "Confirm",
|
||||
countryCode: "Country code",
|
||||
phone: "Phone",
|
||||
email: "Email address",
|
||||
password: "Password",
|
||||
login: "Login",
|
||||
loginWithEmail: "Login with Email",
|
||||
loginWithPhone: "Login with Phone",
|
||||
choose: 'Choose your account',
|
||||
confirm: 'Confirm',
|
||||
countryCode: 'Country code',
|
||||
phone: 'Phone',
|
||||
email: 'Email address',
|
||||
password: 'Password',
|
||||
login: 'Login',
|
||||
loginWithEmail: 'Login with Email',
|
||||
loginWithPhone: 'Login with Phone',
|
||||
notice: `YesPlayMusic promises not to save any of your account information to the cloud.<br />
|
||||
Your password will be MD5 encrypted locally and then transmitted to NetEase Music API.<br />
|
||||
YesPlayMusic is not the official website of NetEase Music, please consider carefully before entering account information. You can also go to <a href="https://github.com/qier222/YesPlayMusic">YesPlayMusic's GitHub repository</a> to build and use the self-hosted NetEase Music API.`,
|
||||
|
|
@ -83,85 +83,85 @@ export default {
|
|||
YesPlayMusic promises not to save any of your account information to the cloud.<br />`,
|
||||
},
|
||||
mv: {
|
||||
moreVideo: "More Videos",
|
||||
moreVideo: 'More Videos',
|
||||
},
|
||||
next: {
|
||||
nowPlaying: "Now Playing",
|
||||
nextUp: "Next Up",
|
||||
nowPlaying: 'Now Playing',
|
||||
nextUp: 'Next Up',
|
||||
},
|
||||
player: {
|
||||
like: "Like",
|
||||
previous: "Previous Song",
|
||||
next: "Next Song",
|
||||
repeat: "Repeat",
|
||||
repeatTrack: "Repeat Track",
|
||||
shuffle: "Shuffle",
|
||||
play: "Play",
|
||||
pause: "Pause",
|
||||
mute: "Mute",
|
||||
nextUp: "Next Up",
|
||||
like: 'Like',
|
||||
previous: 'Previous Song',
|
||||
next: 'Next Song',
|
||||
repeat: 'Repeat',
|
||||
repeatTrack: 'Repeat Track',
|
||||
shuffle: 'Shuffle',
|
||||
play: 'Play',
|
||||
pause: 'Pause',
|
||||
mute: 'Mute',
|
||||
nextUp: 'Next Up',
|
||||
},
|
||||
modal: {
|
||||
close: "Close",
|
||||
close: 'Close',
|
||||
},
|
||||
search: {
|
||||
artist: "Artists",
|
||||
album: "Albums",
|
||||
song: "Songs",
|
||||
mv: "Music Videos",
|
||||
playlist: "Playlists",
|
||||
noResult: "No Results",
|
||||
searchFor: "Search for",
|
||||
artist: 'Artists',
|
||||
album: 'Albums',
|
||||
song: 'Songs',
|
||||
mv: 'Music Videos',
|
||||
playlist: 'Playlists',
|
||||
noResult: 'No Results',
|
||||
searchFor: 'Search for',
|
||||
},
|
||||
settings: {
|
||||
settings: "Settings",
|
||||
logout: "LOGOUT",
|
||||
language: "Languages",
|
||||
settings: 'Settings',
|
||||
logout: 'LOGOUT',
|
||||
language: 'Languages',
|
||||
musicQuality: {
|
||||
text: "Music Quality",
|
||||
low: "Low",
|
||||
medium: "Medium",
|
||||
high: "High",
|
||||
lossless: "Lossless",
|
||||
text: 'Music Quality',
|
||||
low: 'Low',
|
||||
medium: 'Medium',
|
||||
high: 'High',
|
||||
lossless: 'Lossless',
|
||||
},
|
||||
cacheLimit: {
|
||||
text: "Songs Cache limit",
|
||||
none: "None",
|
||||
text: 'Songs Cache limit',
|
||||
none: 'None',
|
||||
},
|
||||
lyricFontSize: {
|
||||
text: "Lyric Font Size",
|
||||
small: "Small",
|
||||
medium: "Medium",
|
||||
large: "Large(Default)",
|
||||
xlarge: "X-Large",
|
||||
text: 'Lyric Font Size',
|
||||
small: 'Small',
|
||||
medium: 'Medium',
|
||||
large: 'Large(Default)',
|
||||
xlarge: 'X-Large',
|
||||
},
|
||||
deviceSelector: "Audio Output Device",
|
||||
permissionRequired: "Microphone Permission Required",
|
||||
deviceSelector: 'Audio Output Device',
|
||||
permissionRequired: 'Microphone Permission Required',
|
||||
appearance: {
|
||||
text: "Appearance",
|
||||
auto: "Auto",
|
||||
light: "Light",
|
||||
dark: "Dark",
|
||||
text: 'Appearance',
|
||||
auto: 'Auto',
|
||||
light: 'Light',
|
||||
dark: 'Dark',
|
||||
},
|
||||
automaticallyCacheSongs: "Automatically cache songs",
|
||||
clearSongsCache: "Clear Songs Cache",
|
||||
cacheCount: "Cached {song} songs ({size})",
|
||||
showLyricsTranslation: "Show lyrics translation",
|
||||
showLyricsDynamicBackground: "Show lyrics dynamic background",
|
||||
minimizeToTray: "Minimize to tray",
|
||||
showPlaylistsByAppleMusic: "Show playlists by Apple Music",
|
||||
enableDiscordRichPresence: "Enable Discord Rich Presence",
|
||||
enableGlobalShortcut: "Enable Global Shortcut",
|
||||
showLibraryDefault: "Show library default",
|
||||
automaticallyCacheSongs: 'Automatically cache songs',
|
||||
clearSongsCache: 'Clear Songs Cache',
|
||||
cacheCount: 'Cached {song} songs ({size})',
|
||||
showLyricsTranslation: 'Show lyrics translation',
|
||||
showLyricsDynamicBackground: 'Show lyrics dynamic background',
|
||||
minimizeToTray: 'Minimize to tray',
|
||||
showPlaylistsByAppleMusic: 'Show playlists by Apple Music',
|
||||
enableDiscordRichPresence: 'Enable Discord Rich Presence',
|
||||
enableGlobalShortcut: 'Enable Global Shortcut',
|
||||
showLibraryDefault: 'Show library default',
|
||||
},
|
||||
contextMenu: {
|
||||
play: "Play",
|
||||
playNext: "Play Next",
|
||||
saveToMyLikedSongs: "Save to my Liked Songs",
|
||||
removeFromMyLikedSongs: "Remove from my Liked Songs",
|
||||
play: 'Play',
|
||||
playNext: 'Play Next',
|
||||
saveToMyLikedSongs: 'Save to my Liked Songs',
|
||||
removeFromMyLikedSongs: 'Remove from my Liked Songs',
|
||||
},
|
||||
toast: {
|
||||
savedToMyLikedSongs: "Saved to my Liked Songs",
|
||||
removedFromMyLikedSongs: "Removed from my Liked Songs",
|
||||
savedToMyLikedSongs: 'Saved to my Liked Songs',
|
||||
removedFromMyLikedSongs: 'Removed from my Liked Songs',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,81 +1,81 @@
|
|||
export default {
|
||||
common: {
|
||||
play: "OYNAT",
|
||||
songs: "Müzikler",
|
||||
play: 'OYNAT',
|
||||
songs: 'Müzikler',
|
||||
},
|
||||
nav: {
|
||||
home: "Anasayfa",
|
||||
explore: "Keşfet",
|
||||
library: "Kitaplık",
|
||||
search: "Ara",
|
||||
github: "GitHub Repo",
|
||||
home: 'Anasayfa',
|
||||
explore: 'Keşfet',
|
||||
library: 'Kitaplık',
|
||||
search: 'Ara',
|
||||
github: 'GitHub Repo',
|
||||
},
|
||||
footer: {
|
||||
settings: "Ayarlar",
|
||||
settings: 'Ayarlar',
|
||||
},
|
||||
home: {
|
||||
recommendPlaylist: "Önerilen Çalma Listeier",
|
||||
recommendArtist: "Önerilen Sanatçılar",
|
||||
newAlbum: "Son Çıkan Albümler",
|
||||
seeMore: "DAHA FAZLASI",
|
||||
charts: "Listeler",
|
||||
recommendPlaylist: 'Önerilen Çalma Listeier',
|
||||
recommendArtist: 'Önerilen Sanatçılar',
|
||||
newAlbum: 'Son Çıkan Albümler',
|
||||
seeMore: 'DAHA FAZLASI',
|
||||
charts: 'Listeler',
|
||||
},
|
||||
library: {
|
||||
sLibrary: "'in Kütüphanesi",
|
||||
likedSongs: "Beğenilen Müzikler",
|
||||
likedSongs: 'Beğenilen Müzikler',
|
||||
sLikedSongs: "'in Beğendiği Müzikler",
|
||||
playlists: "Çalma Listeleri",
|
||||
albums: "Albümler",
|
||||
artists: "Sanatçılar",
|
||||
mvs: "MVs",
|
||||
newPlayList: "Yeni Çalma Listesi",
|
||||
playlists: 'Çalma Listeleri',
|
||||
albums: 'Albümler',
|
||||
artists: 'Sanatçılar',
|
||||
mvs: 'MVs',
|
||||
newPlayList: 'Yeni Çalma Listesi',
|
||||
userProfileMenu: {
|
||||
settings: "Ayarlar",
|
||||
logout: "Çıkış Yap",
|
||||
settings: 'Ayarlar',
|
||||
logout: 'Çıkış Yap',
|
||||
},
|
||||
},
|
||||
explore: {
|
||||
explore: "Keşfet",
|
||||
loadMore: "Daha Fazlası",
|
||||
explore: 'Keşfet',
|
||||
loadMore: 'Daha Fazlası',
|
||||
},
|
||||
artist: {
|
||||
latestRelease: "Son Çıkanlar",
|
||||
popularSongs: "Popüler Müzikler",
|
||||
showMore: "Daha Fazlası",
|
||||
showLess: "Daha Azı",
|
||||
EPsSingles: "EPs & Singles",
|
||||
albums: "Albümler",
|
||||
withAlbums: "Albümler",
|
||||
artist: "Sanatçı",
|
||||
videos: "Müzik Videoları",
|
||||
following: "Takip Ediyor",
|
||||
follow: "Takip Et",
|
||||
latestRelease: 'Son Çıkanlar',
|
||||
popularSongs: 'Popüler Müzikler',
|
||||
showMore: 'Daha Fazlası',
|
||||
showLess: 'Daha Azı',
|
||||
EPsSingles: 'EPs & Singles',
|
||||
albums: 'Albümler',
|
||||
withAlbums: 'Albümler',
|
||||
artist: 'Sanatçı',
|
||||
videos: 'Müzik Videoları',
|
||||
following: 'Takip Ediyor',
|
||||
follow: 'Takip Et',
|
||||
},
|
||||
album: {
|
||||
released: "Yayınlandı",
|
||||
released: 'Yayınlandı',
|
||||
},
|
||||
playlist: {
|
||||
playlist: "Çalma Listeleri",
|
||||
updatedAt: "Tarihinde Güncellendş",
|
||||
search: "Çalma Listesinde Ara",
|
||||
playlist: 'Çalma Listeleri',
|
||||
updatedAt: 'Tarihinde Güncellendş',
|
||||
search: 'Çalma Listesinde Ara',
|
||||
},
|
||||
login: {
|
||||
accessToAll: "Tüm verilere eriş",
|
||||
accessToAll: 'Tüm verilere eriş',
|
||||
loginText: "Netease'e giriş yap",
|
||||
search: "Hesap ara",
|
||||
readonly: "Sadece halka açık verilere erişir",
|
||||
usernameLogin: "Kullanıcı adı giriş",
|
||||
searchHolder: "Hesabının kullanıcı adı",
|
||||
search: 'Hesap ara',
|
||||
readonly: 'Sadece halka açık verilere erişir',
|
||||
usernameLogin: 'Kullanıcı adı giriş',
|
||||
searchHolder: 'Hesabının kullanıcı adı',
|
||||
enterTip: "Aramak için 'enter'e basınız",
|
||||
choose: "Hesabını seç",
|
||||
confirm: "Onayla",
|
||||
countryCode: "Ülke kodu",
|
||||
phone: "Telefon",
|
||||
email: "Email adresi",
|
||||
password: "Şifre",
|
||||
login: "Giriş Yap",
|
||||
loginWithEmail: "Email ile giriş yap",
|
||||
loginWithPhone: "Phone ile giriş yap",
|
||||
choose: 'Hesabını seç',
|
||||
confirm: 'Onayla',
|
||||
countryCode: 'Ülke kodu',
|
||||
phone: 'Telefon',
|
||||
email: 'Email adresi',
|
||||
password: 'Şifre',
|
||||
login: 'Giriş Yap',
|
||||
loginWithEmail: 'Email ile giriş yap',
|
||||
loginWithPhone: 'Phone ile giriş yap',
|
||||
notice: `YesPlayMusic hesabınızın hiçbir bilgisini kaydetmeyeceğine dair söz veriyor<br />
|
||||
Şifren MD5 şifreleme ile yerel olarak şifrelenir ve daha sonra NetEase Müzik API'sine gönderilir<br />
|
||||
YesPlayMusic, NetEase Music'in resmi websitesi değildir, lütfen hesap bilgilerinizi girmeden önce dikkatlice düşününüz. Aynı zamanda, Kendi NetEase Musix API'nızı host etmek için <a href="https://github.com/qier222/YesPlayMusic">YesPlayMusic'in GitHub Repo'suna</a> gidebilirsiniz.`,
|
||||
|
|
@ -83,84 +83,84 @@ export default {
|
|||
Şifren MD5 şifreleme ile yerel olarak şifrelenir ve daha sonra NetEase Müzik API'sine gönderilir<br />`,
|
||||
},
|
||||
mv: {
|
||||
moreVideo: "Daha Fazla Video",
|
||||
moreVideo: 'Daha Fazla Video',
|
||||
},
|
||||
next: {
|
||||
nowPlaying: "Şuan çalıyor",
|
||||
nextUp: "Sıradaki",
|
||||
nowPlaying: 'Şuan çalıyor',
|
||||
nextUp: 'Sıradaki',
|
||||
},
|
||||
player: {
|
||||
like: "Beğen",
|
||||
previous: "Önceki Müzik",
|
||||
next: "Sonraki Müzik",
|
||||
repeat: "Tekrarla",
|
||||
repeatTrack: "Parçayı Tekrarla",
|
||||
shuffle: "Karıştır",
|
||||
play: "Oynat",
|
||||
pause: "Durdur",
|
||||
mute: "Sesi kapat",
|
||||
nextUp: "Sıradaki",
|
||||
like: 'Beğen',
|
||||
previous: 'Önceki Müzik',
|
||||
next: 'Sonraki Müzik',
|
||||
repeat: 'Tekrarla',
|
||||
repeatTrack: 'Parçayı Tekrarla',
|
||||
shuffle: 'Karıştır',
|
||||
play: 'Oynat',
|
||||
pause: 'Durdur',
|
||||
mute: 'Sesi kapat',
|
||||
nextUp: 'Sıradaki',
|
||||
},
|
||||
modal: {
|
||||
close: "Kapat",
|
||||
close: 'Kapat',
|
||||
},
|
||||
search: {
|
||||
artist: "Sanatçılar",
|
||||
album: "Albümler",
|
||||
song: "Müzikler",
|
||||
mv: "Müzik Videoları",
|
||||
playlist: "Çalma Listeleri",
|
||||
noResult: "Sonuç Bulunamadı",
|
||||
searchFor: "Search for",
|
||||
artist: 'Sanatçılar',
|
||||
album: 'Albümler',
|
||||
song: 'Müzikler',
|
||||
mv: 'Müzik Videoları',
|
||||
playlist: 'Çalma Listeleri',
|
||||
noResult: 'Sonuç Bulunamadı',
|
||||
searchFor: 'Search for',
|
||||
},
|
||||
settings: {
|
||||
settings: "Ayarlar",
|
||||
logout: "ÇIKIŞ YAP",
|
||||
language: "Diller",
|
||||
settings: 'Ayarlar',
|
||||
logout: 'ÇIKIŞ YAP',
|
||||
language: 'Diller',
|
||||
musicQuality: {
|
||||
text: "Müzik Kalitesi",
|
||||
low: "Düşük",
|
||||
medium: "Orta",
|
||||
high: "Yüksek",
|
||||
lossless: "Kaliteli",
|
||||
text: 'Müzik Kalitesi',
|
||||
low: 'Düşük',
|
||||
medium: 'Orta',
|
||||
high: 'Yüksek',
|
||||
lossless: 'Kaliteli',
|
||||
},
|
||||
cacheLimit: {
|
||||
text: "Şarkılar Önbellek sınırı",
|
||||
none: "Yok",
|
||||
text: 'Şarkılar Önbellek sınırı',
|
||||
none: 'Yok',
|
||||
},
|
||||
lyricFontSize: {
|
||||
text: "Şarkı Sözleri Yazı Boyutu",
|
||||
small: "Küçük",
|
||||
medium: "Orta",
|
||||
large: "Büyük(Varsayılan)",
|
||||
xlarge: "Çok-Büyük",
|
||||
text: 'Şarkı Sözleri Yazı Boyutu',
|
||||
small: 'Küçük',
|
||||
medium: 'Orta',
|
||||
large: 'Büyük(Varsayılan)',
|
||||
xlarge: 'Çok-Büyük',
|
||||
},
|
||||
deviceSelector: "Ses Çıkış Cihazı",
|
||||
permissionRequired: "Mikrofon izni gerekiyor",
|
||||
deviceSelector: 'Ses Çıkış Cihazı',
|
||||
permissionRequired: 'Mikrofon izni gerekiyor',
|
||||
appearance: {
|
||||
text: "Görünüş",
|
||||
auto: "Otomatik",
|
||||
light: "Aydınlık",
|
||||
dark: "Karanlık",
|
||||
text: 'Görünüş',
|
||||
auto: 'Otomatik',
|
||||
light: 'Aydınlık',
|
||||
dark: 'Karanlık',
|
||||
},
|
||||
automaticallyCacheSongs: "Müzikleri otomatik çerezle",
|
||||
clearSongsCache: "Müzik çerezlerini temizle",
|
||||
cacheCount: "Çerezlenen {song} Müzikler ({size})",
|
||||
showLyricsTranslation: "Müzik sözlerinin çevirilerini göster",
|
||||
showLyricsDynamicBackground: "Dinamik arkaplanda müzik sözlerini gsöter",
|
||||
minimizeToTray: "Küçült",
|
||||
automaticallyCacheSongs: 'Müzikleri otomatik çerezle',
|
||||
clearSongsCache: 'Müzik çerezlerini temizle',
|
||||
cacheCount: 'Çerezlenen {song} Müzikler ({size})',
|
||||
showLyricsTranslation: 'Müzik sözlerinin çevirilerini göster',
|
||||
showLyricsDynamicBackground: 'Dinamik arkaplanda müzik sözlerini gsöter',
|
||||
minimizeToTray: 'Küçült',
|
||||
showPlaylistsByAppleMusic: "Apple Music'in Çalma Listelerini Göster",
|
||||
enableDiscordRichPresence: "Discord gösterimini aktifleştir",
|
||||
showLibraryDefault: "Kitaplık Varsayılanını göster",
|
||||
enableDiscordRichPresence: 'Discord gösterimini aktifleştir',
|
||||
showLibraryDefault: 'Kitaplık Varsayılanını göster',
|
||||
},
|
||||
contextMenu: {
|
||||
play: "Oynat",
|
||||
playNext: "Sonrakini Oynat",
|
||||
saveToMyLikedSongs: "Beğendiğim Müziklere Kaydet",
|
||||
removeFromMyLikedMüzikler: "Beğendiğim Müziklerden Kaldır",
|
||||
play: 'Oynat',
|
||||
playNext: 'Sonrakini Oynat',
|
||||
saveToMyLikedSongs: 'Beğendiğim Müziklere Kaydet',
|
||||
removeFromMyLikedMüzikler: 'Beğendiğim Müziklerden Kaldır',
|
||||
},
|
||||
toast: {
|
||||
savedToMyLikedSongs: "Beğendiğim Müziklere Kaydet",
|
||||
removedFromMyLikedSongs: "Beğendiğim Müziklerden Kaldır",
|
||||
savedToMyLikedSongs: 'Beğendiğim Müziklere Kaydet',
|
||||
removedFromMyLikedSongs: 'Beğendiğim Müziklerden Kaldır',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,78 +1,78 @@
|
|||
export default {
|
||||
common: {
|
||||
play: "播放",
|
||||
songs: "首歌",
|
||||
play: '播放',
|
||||
songs: '首歌',
|
||||
},
|
||||
nav: {
|
||||
home: "首页",
|
||||
explore: "发现",
|
||||
library: "音乐库",
|
||||
search: "搜索",
|
||||
github: "GitHub 仓库",
|
||||
home: '首页',
|
||||
explore: '发现',
|
||||
library: '音乐库',
|
||||
search: '搜索',
|
||||
github: 'GitHub 仓库',
|
||||
},
|
||||
home: {
|
||||
recommendPlaylist: "推荐歌单",
|
||||
recommendArtist: "推荐艺人",
|
||||
newAlbum: "新专速递",
|
||||
seeMore: "查看全部",
|
||||
charts: "排行榜",
|
||||
recommendPlaylist: '推荐歌单',
|
||||
recommendArtist: '推荐艺人',
|
||||
newAlbum: '新专速递',
|
||||
seeMore: '查看全部',
|
||||
charts: '排行榜',
|
||||
},
|
||||
library: {
|
||||
sLibrary: "的音乐库",
|
||||
likedSongs: "我喜欢的音乐",
|
||||
sLikedSongs: "喜欢的音乐",
|
||||
playlists: "歌单",
|
||||
albums: "专辑",
|
||||
artists: "艺人",
|
||||
mvs: "MV",
|
||||
newPlayList: "新建歌单",
|
||||
sLibrary: '的音乐库',
|
||||
likedSongs: '我喜欢的音乐',
|
||||
sLikedSongs: '喜欢的音乐',
|
||||
playlists: '歌单',
|
||||
albums: '专辑',
|
||||
artists: '艺人',
|
||||
mvs: 'MV',
|
||||
newPlayList: '新建歌单',
|
||||
userProfileMenu: {
|
||||
settings: "设置",
|
||||
logout: "登出",
|
||||
settings: '设置',
|
||||
logout: '登出',
|
||||
},
|
||||
},
|
||||
explore: {
|
||||
explore: "发现",
|
||||
loadMore: "加载更多",
|
||||
explore: '发现',
|
||||
loadMore: '加载更多',
|
||||
},
|
||||
artist: {
|
||||
latestRelease: "最新发布",
|
||||
popularSongs: "热门歌曲",
|
||||
showMore: "显示更多",
|
||||
showLess: "收起",
|
||||
EPsSingles: "EP和单曲",
|
||||
albums: "专辑",
|
||||
withAlbums: "张专辑",
|
||||
artist: "艺人",
|
||||
videos: "个MV",
|
||||
following: "已关注",
|
||||
follow: "关注",
|
||||
latestRelease: '最新发布',
|
||||
popularSongs: '热门歌曲',
|
||||
showMore: '显示更多',
|
||||
showLess: '收起',
|
||||
EPsSingles: 'EP和单曲',
|
||||
albums: '专辑',
|
||||
withAlbums: '张专辑',
|
||||
artist: '艺人',
|
||||
videos: '个MV',
|
||||
following: '已关注',
|
||||
follow: '关注',
|
||||
},
|
||||
album: {
|
||||
released: "发行于",
|
||||
released: '发行于',
|
||||
},
|
||||
playlist: {
|
||||
playlist: "歌单",
|
||||
updatedAt: "最后更新于",
|
||||
search: "搜索歌单音乐",
|
||||
playlist: '歌单',
|
||||
updatedAt: '最后更新于',
|
||||
search: '搜索歌单音乐',
|
||||
},
|
||||
login: {
|
||||
accessToAll: "可访问全部数据",
|
||||
loginText: "登录网易云账号",
|
||||
search: "搜索网易云账号",
|
||||
readonly: "只能读取账号公开数据",
|
||||
usernameLogin: "用户名登录",
|
||||
searchHolder: "请输入你的网易云用户名",
|
||||
enterTip: "按 Enter 搜索",
|
||||
choose: "在列表中选中你的账号",
|
||||
confirm: "确认",
|
||||
countryCode: "国际区号",
|
||||
phone: "手机号",
|
||||
email: "邮箱",
|
||||
password: "密码",
|
||||
login: "登录",
|
||||
loginWithEmail: "使用邮箱登录",
|
||||
loginWithPhone: "使用手机号登录",
|
||||
accessToAll: '可访问全部数据',
|
||||
loginText: '登录网易云账号',
|
||||
search: '搜索网易云账号',
|
||||
readonly: '只能读取账号公开数据',
|
||||
usernameLogin: '用户名登录',
|
||||
searchHolder: '请输入你的网易云用户名',
|
||||
enterTip: '按 Enter 搜索',
|
||||
choose: '在列表中选中你的账号',
|
||||
confirm: '确认',
|
||||
countryCode: '国际区号',
|
||||
phone: '手机号',
|
||||
email: '邮箱',
|
||||
password: '密码',
|
||||
login: '登录',
|
||||
loginWithEmail: '使用邮箱登录',
|
||||
loginWithPhone: '使用手机号登录',
|
||||
notice: `YesPlayMusic 承诺不会保存你的任何账号信息到云端。<br />
|
||||
你的密码会在本地进行 MD5 加密后再传输到网易云 API。<br />
|
||||
YesPlayMusic 并非网易云官方网站,输入账号信息前请慎重考虑。 你也可以前往
|
||||
|
|
@ -84,85 +84,85 @@ export default {
|
|||
YesPlayMusic 不会传输你的账号数据到任何非网易云音乐官方的服务器。<br />`,
|
||||
},
|
||||
mv: {
|
||||
moreVideo: "更多视频",
|
||||
moreVideo: '更多视频',
|
||||
},
|
||||
next: {
|
||||
nowPlaying: "正在播放",
|
||||
nextUp: "即将播放",
|
||||
nowPlaying: '正在播放',
|
||||
nextUp: '即将播放',
|
||||
},
|
||||
player: {
|
||||
like: "喜欢",
|
||||
previous: "上一首",
|
||||
next: "下一首",
|
||||
repeat: "循环播放",
|
||||
repeatTrack: "单曲循环",
|
||||
shuffle: "随机播放",
|
||||
play: "播放",
|
||||
pause: "暂停",
|
||||
mute: "静音",
|
||||
nextUp: "播放列表",
|
||||
like: '喜欢',
|
||||
previous: '上一首',
|
||||
next: '下一首',
|
||||
repeat: '循环播放',
|
||||
repeatTrack: '单曲循环',
|
||||
shuffle: '随机播放',
|
||||
play: '播放',
|
||||
pause: '暂停',
|
||||
mute: '静音',
|
||||
nextUp: '播放列表',
|
||||
},
|
||||
modal: {
|
||||
close: "关闭",
|
||||
close: '关闭',
|
||||
},
|
||||
search: {
|
||||
artist: "艺人",
|
||||
album: "专辑",
|
||||
song: "歌曲",
|
||||
mv: "视频",
|
||||
playlist: "歌单",
|
||||
noResult: "暂无结果",
|
||||
searchFor: "搜索",
|
||||
artist: '艺人',
|
||||
album: '专辑',
|
||||
song: '歌曲',
|
||||
mv: '视频',
|
||||
playlist: '歌单',
|
||||
noResult: '暂无结果',
|
||||
searchFor: '搜索',
|
||||
},
|
||||
settings: {
|
||||
settings: "设置",
|
||||
logout: "登出",
|
||||
language: "语言",
|
||||
settings: '设置',
|
||||
logout: '登出',
|
||||
language: '语言',
|
||||
musicQuality: {
|
||||
text: "音质选择",
|
||||
low: "普通",
|
||||
medium: "较高",
|
||||
high: "极高",
|
||||
lossless: "无损",
|
||||
text: '音质选择',
|
||||
low: '普通',
|
||||
medium: '较高',
|
||||
high: '极高',
|
||||
lossless: '无损',
|
||||
},
|
||||
cacheLimit: {
|
||||
text: "歌曲缓存上限",
|
||||
none: "无限制",
|
||||
text: '歌曲缓存上限',
|
||||
none: '无限制',
|
||||
},
|
||||
lyricFontSize: {
|
||||
text: "歌词字体大小",
|
||||
small: "小",
|
||||
medium: "中",
|
||||
large: "大(默认)",
|
||||
xlarge: "超大",
|
||||
text: '歌词字体大小',
|
||||
small: '小',
|
||||
medium: '中',
|
||||
large: '大(默认)',
|
||||
xlarge: '超大',
|
||||
},
|
||||
deviceSelector: "音频输出设备",
|
||||
permissionRequired: "需要麦克风权限",
|
||||
deviceSelector: '音频输出设备',
|
||||
permissionRequired: '需要麦克风权限',
|
||||
appearance: {
|
||||
text: "外观",
|
||||
auto: "自动",
|
||||
light: "浅色",
|
||||
dark: "深色",
|
||||
text: '外观',
|
||||
auto: '自动',
|
||||
light: '浅色',
|
||||
dark: '深色',
|
||||
},
|
||||
automaticallyCacheSongs: "自动缓存歌曲",
|
||||
clearSongsCache: "清除歌曲缓存",
|
||||
cacheCount: "已缓存 {song} 首 ({size})",
|
||||
showLyricsTranslation: "显示歌词翻译",
|
||||
showLyricsDynamicBackground: "显示歌词动态背景",
|
||||
minimizeToTray: "最小化到托盘",
|
||||
showPlaylistsByAppleMusic: "首页显示来自 Apple Music 的歌单",
|
||||
enableDiscordRichPresence: "启用 Discord Rich Presence",
|
||||
enableGlobalShortcut: "启用全局快捷键",
|
||||
showLibraryDefault: "启动后显示音乐库",
|
||||
automaticallyCacheSongs: '自动缓存歌曲',
|
||||
clearSongsCache: '清除歌曲缓存',
|
||||
cacheCount: '已缓存 {song} 首 ({size})',
|
||||
showLyricsTranslation: '显示歌词翻译',
|
||||
showLyricsDynamicBackground: '显示歌词动态背景',
|
||||
minimizeToTray: '最小化到托盘',
|
||||
showPlaylistsByAppleMusic: '首页显示来自 Apple Music 的歌单',
|
||||
enableDiscordRichPresence: '启用 Discord Rich Presence',
|
||||
enableGlobalShortcut: '启用全局快捷键',
|
||||
showLibraryDefault: '启动后显示音乐库',
|
||||
},
|
||||
contextMenu: {
|
||||
play: "播放",
|
||||
playNext: "下一首播放",
|
||||
saveToMyLikedSongs: "添加到我喜欢的音乐",
|
||||
removeFromMyLikedSongs: "从喜欢的音乐中删除",
|
||||
play: '播放',
|
||||
playNext: '下一首播放',
|
||||
saveToMyLikedSongs: '添加到我喜欢的音乐',
|
||||
removeFromMyLikedSongs: '从喜欢的音乐中删除',
|
||||
},
|
||||
toast: {
|
||||
savedToMyLikedSongs: "已添加到我喜欢的音乐",
|
||||
removedFromMyLikedSongs: "已从喜欢的音乐中删除",
|
||||
savedToMyLikedSongs: '已添加到我喜欢的音乐',
|
||||
removedFromMyLikedSongs: '已从喜欢的音乐中删除',
|
||||
},
|
||||
};
|
||||
|
|
|
|||
42
src/main.js
42
src/main.js
|
|
@ -1,33 +1,33 @@
|
|||
import Vue from "vue";
|
||||
import VueAnalytics from "vue-analytics";
|
||||
import App from "./App.vue";
|
||||
import router from "./router";
|
||||
import store from "./store";
|
||||
import i18n from "@/locale";
|
||||
import "@/assets/icons";
|
||||
import "@/utils/filters";
|
||||
import "./registerServiceWorker";
|
||||
import { dailyTask } from "@/utils/common";
|
||||
import Vue from 'vue';
|
||||
import VueAnalytics from 'vue-analytics';
|
||||
import App from './App.vue';
|
||||
import router from './router';
|
||||
import store from './store';
|
||||
import i18n from '@/locale';
|
||||
import '@/assets/icons';
|
||||
import '@/utils/filters';
|
||||
import './registerServiceWorker';
|
||||
import { dailyTask } from '@/utils/common';
|
||||
|
||||
window.resetApp = () => {
|
||||
localStorage.clear();
|
||||
indexedDB.deleteDatabase("yesplaymusic");
|
||||
document.cookie.split(";").forEach(function (c) {
|
||||
indexedDB.deleteDatabase('yesplaymusic');
|
||||
document.cookie.split(';').forEach(function (c) {
|
||||
document.cookie = c
|
||||
.replace(/^ +/, "")
|
||||
.replace(/=.*/, "=;expires=" + new Date().toUTCString() + ";path=/");
|
||||
.replace(/^ +/, '')
|
||||
.replace(/=.*/, '=;expires=' + new Date().toUTCString() + ';path=/');
|
||||
});
|
||||
return "已重置应用,请刷新页面(按Ctrl/Command + R)";
|
||||
return '已重置应用,请刷新页面(按Ctrl/Command + R)';
|
||||
};
|
||||
|
||||
console.log(
|
||||
"如出现问题,可尝试在本页输入 %cresetApp()%c 然后按回车重置应用。",
|
||||
"background: #eaeffd;color:#335eea;padding: 4px 6px;border-radius:3px;",
|
||||
"background:unset;color:unset;"
|
||||
'如出现问题,可尝试在本页输入 %cresetApp()%c 然后按回车重置应用。',
|
||||
'background: #eaeffd;color:#335eea;padding: 4px 6px;border-radius:3px;',
|
||||
'background:unset;color:unset;'
|
||||
);
|
||||
|
||||
Vue.use(VueAnalytics, {
|
||||
id: "UA-180189423-1",
|
||||
id: 'UA-180189423-1',
|
||||
router,
|
||||
});
|
||||
|
||||
|
|
@ -39,5 +39,5 @@ new Vue({
|
|||
i18n,
|
||||
store,
|
||||
router,
|
||||
render: (h) => h(App),
|
||||
}).$mount("#app");
|
||||
render: h => h(App),
|
||||
}).$mount('#app');
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable no-console */
|
||||
|
||||
import { register } from "register-service-worker";
|
||||
import { register } from 'register-service-worker';
|
||||
|
||||
register(`${process.env.BASE_URL}service-worker.js`, {
|
||||
ready() {
|
||||
|
|
@ -27,6 +27,6 @@ register(`${process.env.BASE_URL}service-worker.js`, {
|
|||
// );
|
||||
},
|
||||
error(error) {
|
||||
console.error("Error during service worker registration:", error);
|
||||
console.error('Error during service worker registration:', error);
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,135 +1,135 @@
|
|||
import Vue from "vue";
|
||||
import VueRouter from "vue-router";
|
||||
import NProgress from "nprogress";
|
||||
import "@/assets/css/nprogress.css";
|
||||
import { isLooseLoggedIn, isAccountLoggedIn } from "@/utils/auth";
|
||||
import Vue from 'vue';
|
||||
import VueRouter from 'vue-router';
|
||||
import NProgress from 'nprogress';
|
||||
import '@/assets/css/nprogress.css';
|
||||
import { isLooseLoggedIn, isAccountLoggedIn } from '@/utils/auth';
|
||||
|
||||
NProgress.configure({ showSpinner: false, trickleSpeed: 100 });
|
||||
|
||||
Vue.use(VueRouter);
|
||||
const routes = [
|
||||
{
|
||||
path: "/",
|
||||
name: "home",
|
||||
component: () => import("@/views/home.vue"),
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: () => import('@/views/home.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/login",
|
||||
name: "login",
|
||||
component: () => import("@/views/login.vue"),
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: () => import('@/views/login.vue'),
|
||||
},
|
||||
{
|
||||
path: "/login/username",
|
||||
name: "loginUsername",
|
||||
component: () => import("@/views/loginUsername.vue"),
|
||||
path: '/login/username',
|
||||
name: 'loginUsername',
|
||||
component: () => import('@/views/loginUsername.vue'),
|
||||
},
|
||||
{
|
||||
path: "/login/account",
|
||||
name: "loginAccount",
|
||||
component: () => import("@/views/loginAccount.vue"),
|
||||
path: '/login/account',
|
||||
name: 'loginAccount',
|
||||
component: () => import('@/views/loginAccount.vue'),
|
||||
},
|
||||
{
|
||||
path: "/playlist/:id",
|
||||
name: "playlist",
|
||||
component: () => import("@/views/playlist.vue"),
|
||||
path: '/playlist/:id',
|
||||
name: 'playlist',
|
||||
component: () => import('@/views/playlist.vue'),
|
||||
},
|
||||
{
|
||||
path: "/album/:id",
|
||||
name: "album",
|
||||
component: () => import("@/views/album.vue"),
|
||||
path: '/album/:id',
|
||||
name: 'album',
|
||||
component: () => import('@/views/album.vue'),
|
||||
},
|
||||
{
|
||||
path: "/artist/:id",
|
||||
name: "artist",
|
||||
component: () => import("@/views/artist.vue"),
|
||||
path: '/artist/:id',
|
||||
name: 'artist',
|
||||
component: () => import('@/views/artist.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/artist/:id/mv",
|
||||
name: "artistMV",
|
||||
component: () => import("@/views/artistMV.vue"),
|
||||
path: '/artist/:id/mv',
|
||||
name: 'artistMV',
|
||||
component: () => import('@/views/artistMV.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/mv/:id",
|
||||
name: "mv",
|
||||
component: () => import("@/views/mv.vue"),
|
||||
path: '/mv/:id',
|
||||
name: 'mv',
|
||||
component: () => import('@/views/mv.vue'),
|
||||
},
|
||||
{
|
||||
path: "/next",
|
||||
name: "next",
|
||||
component: () => import("@/views/next.vue"),
|
||||
path: '/next',
|
||||
name: 'next',
|
||||
component: () => import('@/views/next.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/search/:keywords?",
|
||||
name: "search",
|
||||
component: () => import("@/views/search.vue"),
|
||||
path: '/search/:keywords?',
|
||||
name: 'search',
|
||||
component: () => import('@/views/search.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/search/:keywords/:type",
|
||||
name: "searchType",
|
||||
component: () => import("@/views/searchType.vue"),
|
||||
path: '/search/:keywords/:type',
|
||||
name: 'searchType',
|
||||
component: () => import('@/views/searchType.vue'),
|
||||
},
|
||||
{
|
||||
path: "/new-album",
|
||||
name: "newAlbum",
|
||||
component: () => import("@/views/newAlbum.vue"),
|
||||
path: '/new-album',
|
||||
name: 'newAlbum',
|
||||
component: () => import('@/views/newAlbum.vue'),
|
||||
},
|
||||
{
|
||||
path: "/explore",
|
||||
name: "explore",
|
||||
component: () => import("@/views/explore.vue"),
|
||||
path: '/explore',
|
||||
name: 'explore',
|
||||
component: () => import('@/views/explore.vue'),
|
||||
meta: {
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/library",
|
||||
name: "library",
|
||||
component: () => import("@/views/library.vue"),
|
||||
path: '/library',
|
||||
name: 'library',
|
||||
component: () => import('@/views/library.vue'),
|
||||
meta: {
|
||||
requireLogin: true,
|
||||
keepAlive: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/library/liked-songs",
|
||||
name: "likedSongs",
|
||||
component: () => import("@/views/playlist.vue"),
|
||||
path: '/library/liked-songs',
|
||||
name: 'likedSongs',
|
||||
component: () => import('@/views/playlist.vue'),
|
||||
meta: {
|
||||
requireLogin: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/settings",
|
||||
name: "settings",
|
||||
component: () => import("@/views/settings.vue"),
|
||||
path: '/settings',
|
||||
name: 'settings',
|
||||
component: () => import('@/views/settings.vue'),
|
||||
},
|
||||
{
|
||||
path: "/daily/songs",
|
||||
name: "dailySongs",
|
||||
component: () => import("@/views/dailyTracks.vue"),
|
||||
path: '/daily/songs',
|
||||
name: 'dailySongs',
|
||||
component: () => import('@/views/dailyTracks.vue'),
|
||||
meta: {
|
||||
requireAccountLogin: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
path: "/lastfm/callback",
|
||||
name: "lastfmCallback",
|
||||
component: () => import("@/views/lastfmCallback.vue"),
|
||||
path: '/lastfm/callback',
|
||||
name: 'lastfmCallback',
|
||||
component: () => import('@/views/lastfmCallback.vue'),
|
||||
},
|
||||
];
|
||||
const router = new VueRouter({
|
||||
|
|
@ -145,7 +145,7 @@ const router = new VueRouter({
|
|||
|
||||
const originalPush = VueRouter.prototype.push;
|
||||
VueRouter.prototype.push = function push(location) {
|
||||
return originalPush.call(this, location).catch((err) => err);
|
||||
return originalPush.call(this, location).catch(err => err);
|
||||
};
|
||||
|
||||
router.beforeEach((to, from, next) => {
|
||||
|
|
@ -154,7 +154,7 @@ router.beforeEach((to, from, next) => {
|
|||
if (isAccountLoggedIn()) {
|
||||
next();
|
||||
} else {
|
||||
next({ path: "/login/account" });
|
||||
next({ path: '/login/account' });
|
||||
}
|
||||
}
|
||||
if (to.meta.requireLogin) {
|
||||
|
|
@ -162,9 +162,9 @@ router.beforeEach((to, from, next) => {
|
|||
next();
|
||||
} else {
|
||||
if (process.env.IS_ELECTRON === true) {
|
||||
next({ path: "/login/account" });
|
||||
next({ path: '/login/account' });
|
||||
} else {
|
||||
next({ path: "/login" });
|
||||
next({ path: '/login' });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
|
@ -172,10 +172,10 @@ router.beforeEach((to, from, next) => {
|
|||
}
|
||||
});
|
||||
|
||||
router.afterEach((to) => {
|
||||
router.afterEach(to => {
|
||||
if (
|
||||
to.matched.some((record) => !record.meta.keepAlive) &&
|
||||
!["settings", "dailySongs", "lastfmCallback"].includes(to.name)
|
||||
to.matched.some(record => !record.meta.keepAlive) &&
|
||||
!['settings', 'dailySongs', 'lastfmCallback'].includes(to.name)
|
||||
) {
|
||||
NProgress.start();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import Vue from "vue";
|
||||
import Vuex from "vuex";
|
||||
import state from "./state";
|
||||
import mutations from "./mutations";
|
||||
import actions from "./actions";
|
||||
import { changeAppearance } from "@/utils/common";
|
||||
import Player from "@/utils/Player";
|
||||
import Vue from 'vue';
|
||||
import Vuex from 'vuex';
|
||||
import state from './state';
|
||||
import mutations from './mutations';
|
||||
import actions from './actions';
|
||||
import { changeAppearance } from '@/utils/common';
|
||||
import Player from '@/utils/Player';
|
||||
// vuex 自定义插件
|
||||
import saveToLocalStorage from "./plugins/localStorage";
|
||||
import { getSendSettingsPlugin } from "./plugins/sendSettings";
|
||||
import saveToLocalStorage from './plugins/localStorage';
|
||||
import { getSendSettingsPlugin } from './plugins/sendSettings';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
|
|
@ -26,22 +26,22 @@ const options = {
|
|||
const store = new Vuex.Store(options);
|
||||
|
||||
if ([undefined, null].includes(store.state.settings.lang)) {
|
||||
const defaultLang = "en";
|
||||
const defaultLang = 'en';
|
||||
const langMapper = new Map()
|
||||
.set("zh", "zh-CN")
|
||||
.set("en", "en")
|
||||
.set("tr", "tr");
|
||||
.set('zh', 'zh-CN')
|
||||
.set('en', 'en')
|
||||
.set('tr', 'tr');
|
||||
store.state.settings.lang =
|
||||
langMapper.get(navigator.language.slice(0, 2)) || defaultLang;
|
||||
localStorage.setItem("settings", JSON.stringify(store.state.settings));
|
||||
localStorage.setItem('settings', JSON.stringify(store.state.settings));
|
||||
}
|
||||
|
||||
changeAppearance(store.state.settings.appearance);
|
||||
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", () => {
|
||||
if (store.state.settings.appearance === "auto") {
|
||||
.matchMedia('(prefers-color-scheme: dark)')
|
||||
.addEventListener('change', () => {
|
||||
if (store.state.settings.appearance === 'auto') {
|
||||
changeAppearance(store.state.settings.appearance);
|
||||
}
|
||||
});
|
||||
|
|
@ -51,7 +51,7 @@ player = new Proxy(player, {
|
|||
set(target, prop, val) {
|
||||
// console.log({ prop, val });
|
||||
target[prop] = val;
|
||||
if (prop === "_howler") return true;
|
||||
if (prop === '_howler') return true;
|
||||
target.saveSelfToLocalStorage();
|
||||
target.sendSelfToIpcMain();
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -1,18 +1,18 @@
|
|||
import { playlistCategories } from "@/utils/staticData";
|
||||
import { playlistCategories } from '@/utils/staticData';
|
||||
|
||||
console.log("[debug][initLocalStorage.js]");
|
||||
console.log('[debug][initLocalStorage.js]');
|
||||
const enabledPlaylistCategories = playlistCategories
|
||||
.filter((c) => c.enable)
|
||||
.map((c) => c.name);
|
||||
.filter(c => c.enable)
|
||||
.map(c => c.name);
|
||||
|
||||
let localStorage = {
|
||||
player: {},
|
||||
settings: {
|
||||
lang: null,
|
||||
appearance: "auto",
|
||||
appearance: 'auto',
|
||||
musicQuality: 320000,
|
||||
lyricFontSize: 28,
|
||||
outputDevice: "default",
|
||||
outputDevice: 'default',
|
||||
showPlaylistsByAppleMusic: true,
|
||||
enableUnblockNeteaseMusic: true,
|
||||
automaticallyCacheSongs: false,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
export default (store) => {
|
||||
export default store => {
|
||||
store.subscribe((mutation, state) => {
|
||||
// console.log(mutation);
|
||||
localStorage.setItem("settings", JSON.stringify(state.settings));
|
||||
localStorage.setItem("data", JSON.stringify(state.data));
|
||||
localStorage.setItem('settings', JSON.stringify(state.settings));
|
||||
localStorage.setItem('data', JSON.stringify(state.data));
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
export function getSendSettingsPlugin() {
|
||||
const electron = window.require("electron");
|
||||
const electron = window.require('electron');
|
||||
const ipcRenderer = electron.ipcRenderer;
|
||||
return (store) => {
|
||||
return store => {
|
||||
store.subscribe((mutation, state) => {
|
||||
// console.log(mutation);
|
||||
if (mutation.type !== "updateSettings") return;
|
||||
ipcRenderer.send("settings", {
|
||||
if (mutation.type !== 'updateSettings') return;
|
||||
ipcRenderer.send('settings', {
|
||||
minimizeToTray: state.settings.minimizeToTray,
|
||||
enableGlobalShortcut: state.settings.enableGlobalShortcut,
|
||||
appearance: state.settings.appearance,
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
import Cookies from "js-cookie";
|
||||
import { logout } from "@/api/auth";
|
||||
import store from "@/store";
|
||||
import Cookies from 'js-cookie';
|
||||
import { logout } from '@/api/auth';
|
||||
import store from '@/store';
|
||||
|
||||
export function doLogout() {
|
||||
logout();
|
||||
// 网易云的接口会自动移除该 cookies
|
||||
// Cookies.remove("MUSIC_U");
|
||||
// 更新状态仓库中的用户信息
|
||||
store.commit("updateData", { key: "user", value: {} });
|
||||
store.commit('updateData', { key: 'user', value: {} });
|
||||
// 更新状态仓库中的登录状态
|
||||
store.commit("updateData", { key: "loginMode", value: null });
|
||||
store.commit('updateData', { key: 'loginMode', value: null });
|
||||
// 更新状态仓库中的喜欢列表
|
||||
store.commit("updateData", { key: "likedSongPlaylistID", value: undefined });
|
||||
store.commit('updateData', { key: 'likedSongPlaylistID', value: undefined });
|
||||
}
|
||||
|
||||
// MUSIC_U 只有在账户登录的情况下才有
|
||||
export function isLoggedIn() {
|
||||
return Cookies.get("MUSIC_U") !== undefined ? true : false;
|
||||
return Cookies.get('MUSIC_U') !== undefined ? true : false;
|
||||
}
|
||||
|
||||
// 账号登录
|
||||
export function isAccountLoggedIn() {
|
||||
return (
|
||||
Cookies.get("MUSIC_U") !== undefined &&
|
||||
store.state.data.loginMode === "account"
|
||||
Cookies.get('MUSIC_U') !== undefined &&
|
||||
store.state.data.loginMode === 'account'
|
||||
);
|
||||
}
|
||||
|
||||
// 用户名搜索(用户数据为只读)
|
||||
export function isUsernameLoggedIn() {
|
||||
return store.state.data.loginMode === "username";
|
||||
return store.state.data.loginMode === 'username';
|
||||
}
|
||||
|
||||
// 账户登录或者用户名搜索都判断为登录,宽松检查
|
||||
|
|
@ -38,15 +38,15 @@ export function isLooseLoggedIn() {
|
|||
}
|
||||
|
||||
export function getMusicU(string) {
|
||||
const temp = string.split(";");
|
||||
const temp = string.split(';');
|
||||
if (!temp.length) {
|
||||
return undefined;
|
||||
}
|
||||
const MUSIC_U = temp.find((item) => item.includes("MUSIC_U"));
|
||||
const MUSIC_U = temp.find(item => item.includes('MUSIC_U'));
|
||||
if (MUSIC_U) {
|
||||
return MUSIC_U.split("=")[1];
|
||||
return MUSIC_U.split('=')[1];
|
||||
}
|
||||
return "";
|
||||
return '';
|
||||
}
|
||||
|
||||
export function setMusicU(key, value) {
|
||||
|
|
@ -54,8 +54,8 @@ export function setMusicU(key, value) {
|
|||
}
|
||||
|
||||
export function setCookies(string) {
|
||||
const cookies = string.split(";;");
|
||||
cookies.map((cookie) => {
|
||||
const cookies = string.split(';;');
|
||||
cookies.map(cookie => {
|
||||
document.cookie = cookie;
|
||||
console.log(cookie);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { isAccountLoggedIn } from "./auth";
|
||||
import { refreshCookie } from "@/api/auth";
|
||||
import { dailySignin } from "@/api/user";
|
||||
import dayjs from "dayjs";
|
||||
import store from "@/store";
|
||||
import { isAccountLoggedIn } from './auth';
|
||||
import { refreshCookie } from '@/api/auth';
|
||||
import { dailySignin } from '@/api/user';
|
||||
import dayjs from 'dayjs';
|
||||
import store from '@/store';
|
||||
|
||||
export function isTrackPlayable(track) {
|
||||
let result = {
|
||||
playable: true,
|
||||
reason: "",
|
||||
reason: '',
|
||||
};
|
||||
// cloud storage judgement logic
|
||||
if (isAccountLoggedIn() && track?.privilege?.cs) {
|
||||
|
|
@ -18,27 +18,27 @@ export function isTrackPlayable(track) {
|
|||
result.playable = true;
|
||||
} else {
|
||||
result.playable = false;
|
||||
result.reason = "VIP Only";
|
||||
result.reason = 'VIP Only';
|
||||
}
|
||||
} else if (track.fee === 4 || track.privilege?.fee === 4) {
|
||||
result.playable = false;
|
||||
result.reason = "付费专辑";
|
||||
result.reason = '付费专辑';
|
||||
} else if (
|
||||
track.noCopyrightRcmd !== null &&
|
||||
track.noCopyrightRcmd !== undefined
|
||||
) {
|
||||
result.playable = false;
|
||||
result.reason = "无版权";
|
||||
result.reason = '无版权';
|
||||
} else if (track.privilege?.st < 0 && isAccountLoggedIn()) {
|
||||
result.playable = false;
|
||||
result.reason = "已下架";
|
||||
result.reason = '已下架';
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function mapTrackPlayableStatus(tracks, privileges = []) {
|
||||
return tracks.map((t) => {
|
||||
const privilege = privileges.find((item) => item.id === t.id) || {};
|
||||
return tracks.map(t => {
|
||||
const privilege = privileges.find(item => item.id === t.id) || {};
|
||||
if (t.privilege) {
|
||||
Object.assign(t.privilege, privilege);
|
||||
} else {
|
||||
|
|
@ -63,13 +63,13 @@ export function randomNum(minNum, maxNum) {
|
|||
}
|
||||
|
||||
export function shuffleAList(list) {
|
||||
let sortsList = list.map((t) => t.sort);
|
||||
let sortsList = list.map(t => t.sort);
|
||||
for (let i = 1; i < sortsList.length; i++) {
|
||||
const random = Math.floor(Math.random() * (i + 1));
|
||||
[sortsList[i], sortsList[random]] = [sortsList[random], sortsList[i]];
|
||||
}
|
||||
let newSorts = {};
|
||||
list.map((track) => {
|
||||
list.map(track => {
|
||||
newSorts[track.id] = sortsList.pop();
|
||||
});
|
||||
return newSorts;
|
||||
|
|
@ -88,8 +88,8 @@ export function throttle(fn, time) {
|
|||
}
|
||||
|
||||
export function updateHttps(url) {
|
||||
if (!url) return "";
|
||||
return url.replace(/^http:/, "https:");
|
||||
if (!url) return '';
|
||||
return url.replace(/^http:/, 'https:');
|
||||
}
|
||||
|
||||
export function dailyTask() {
|
||||
|
|
@ -98,9 +98,9 @@ export function dailyTask() {
|
|||
isAccountLoggedIn() &&
|
||||
(lastDate === undefined || lastDate !== dayjs().date())
|
||||
) {
|
||||
console.log("execute dailyTask");
|
||||
store.commit("updateData", {
|
||||
key: "lastRefreshCookieDate",
|
||||
console.log('execute dailyTask');
|
||||
store.commit('updateData', {
|
||||
key: 'lastRefreshCookieDate',
|
||||
value: dayjs().date(),
|
||||
});
|
||||
refreshCookie();
|
||||
|
|
@ -110,85 +110,85 @@ export function dailyTask() {
|
|||
}
|
||||
|
||||
export function changeAppearance(appearance) {
|
||||
if (appearance === "auto" || appearance === undefined) {
|
||||
appearance = window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
? "dark"
|
||||
: "light";
|
||||
if (appearance === 'auto' || appearance === undefined) {
|
||||
appearance = window.matchMedia('(prefers-color-scheme: dark)').matches
|
||||
? 'dark'
|
||||
: 'light';
|
||||
}
|
||||
document.body.setAttribute("data-theme", appearance);
|
||||
document.body.setAttribute('data-theme', appearance);
|
||||
document
|
||||
.querySelector('meta[name="theme-color"]')
|
||||
.setAttribute("content", appearance === "dark" ? "#222" : "#fff");
|
||||
.setAttribute('content', appearance === 'dark' ? '#222' : '#fff');
|
||||
}
|
||||
|
||||
export function splitSoundtrackAlbumTitle(title) {
|
||||
let keywords = [
|
||||
"Music from the Original Motion Picture Score",
|
||||
"The Original Motion Picture Soundtrack",
|
||||
"Original MGM Motion Picture Soundtrack",
|
||||
"Complete Original Motion Picture Score",
|
||||
"Original Music From The Motion Picture",
|
||||
"Music From The Disney+ Original Movie",
|
||||
"Original Music From The Netflix Film",
|
||||
"Original Score to the Motion Picture",
|
||||
"Original Motion Picture Soundtrack",
|
||||
"Soundtrack from the Motion Picture",
|
||||
"Original Television Soundtrack",
|
||||
"Original Motion Picture Score",
|
||||
"Music From the Motion Picture",
|
||||
"Music From The Motion Picture",
|
||||
"Complete Motion Picture Score",
|
||||
"Music from the Motion Picture",
|
||||
"Original Videogame Soundtrack",
|
||||
"La Bande Originale du Film",
|
||||
"Music from the Miniseries",
|
||||
"Bande Originale du Film",
|
||||
"Die Original Filmmusik",
|
||||
"Original Soundtrack",
|
||||
"Complete Score",
|
||||
"Original Score",
|
||||
'Music from the Original Motion Picture Score',
|
||||
'The Original Motion Picture Soundtrack',
|
||||
'Original MGM Motion Picture Soundtrack',
|
||||
'Complete Original Motion Picture Score',
|
||||
'Original Music From The Motion Picture',
|
||||
'Music From The Disney+ Original Movie',
|
||||
'Original Music From The Netflix Film',
|
||||
'Original Score to the Motion Picture',
|
||||
'Original Motion Picture Soundtrack',
|
||||
'Soundtrack from the Motion Picture',
|
||||
'Original Television Soundtrack',
|
||||
'Original Motion Picture Score',
|
||||
'Music From the Motion Picture',
|
||||
'Music From The Motion Picture',
|
||||
'Complete Motion Picture Score',
|
||||
'Music from the Motion Picture',
|
||||
'Original Videogame Soundtrack',
|
||||
'La Bande Originale du Film',
|
||||
'Music from the Miniseries',
|
||||
'Bande Originale du Film',
|
||||
'Die Original Filmmusik',
|
||||
'Original Soundtrack',
|
||||
'Complete Score',
|
||||
'Original Score',
|
||||
];
|
||||
for (let keyword of keywords) {
|
||||
if (title.includes(keyword) === false) continue;
|
||||
return {
|
||||
title: title
|
||||
.replace(`(${keyword})`, "")
|
||||
.replace(`: ${keyword}`, "")
|
||||
.replace(`[${keyword}]`, "")
|
||||
.replace(`- ${keyword}`, "")
|
||||
.replace(`${keyword}`, ""),
|
||||
.replace(`(${keyword})`, '')
|
||||
.replace(`: ${keyword}`, '')
|
||||
.replace(`[${keyword}]`, '')
|
||||
.replace(`- ${keyword}`, '')
|
||||
.replace(`${keyword}`, ''),
|
||||
subtitle: keyword,
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: title,
|
||||
subtitle: "",
|
||||
subtitle: '',
|
||||
};
|
||||
}
|
||||
|
||||
export function splitAlbumTitle(title) {
|
||||
let keywords = [
|
||||
"Bonus Tracks Edition",
|
||||
"Complete Edition",
|
||||
"Deluxe Edition",
|
||||
"Deluxe Version",
|
||||
"Tour Edition",
|
||||
'Bonus Tracks Edition',
|
||||
'Complete Edition',
|
||||
'Deluxe Edition',
|
||||
'Deluxe Version',
|
||||
'Tour Edition',
|
||||
];
|
||||
for (let keyword of keywords) {
|
||||
if (title.includes(keyword) === false) continue;
|
||||
return {
|
||||
title: title
|
||||
.replace(`(${keyword})`, "")
|
||||
.replace(`: ${keyword}`, "")
|
||||
.replace(`[${keyword}]`, "")
|
||||
.replace(`- ${keyword}`, "")
|
||||
.replace(`${keyword}`, ""),
|
||||
.replace(`(${keyword})`, '')
|
||||
.replace(`: ${keyword}`, '')
|
||||
.replace(`[${keyword}]`, '')
|
||||
.replace(`- ${keyword}`, '')
|
||||
.replace(`${keyword}`, ''),
|
||||
subtitle: keyword,
|
||||
};
|
||||
}
|
||||
return {
|
||||
title: title,
|
||||
subtitle: "",
|
||||
subtitle: '',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -201,17 +201,17 @@ export function bytesToSize(bytes) {
|
|||
|
||||
let lang = store.state.settings.lang;
|
||||
|
||||
if (bytes < kiloBytes) return bytes + (lang === "en" ? " Bytes" : "字节");
|
||||
if (bytes < kiloBytes) return bytes + (lang === 'en' ? ' Bytes' : '字节');
|
||||
else if (bytes < megaBytes)
|
||||
return (bytes / kiloBytes).toFixed(decimal) + " KB";
|
||||
return (bytes / kiloBytes).toFixed(decimal) + ' KB';
|
||||
else if (bytes < gigaBytes)
|
||||
return (bytes / megaBytes).toFixed(decimal) + " MB";
|
||||
else return (bytes / gigaBytes).toFixed(decimal) + " GB";
|
||||
return (bytes / megaBytes).toFixed(decimal) + ' MB';
|
||||
else return (bytes / gigaBytes).toFixed(decimal) + ' GB';
|
||||
}
|
||||
|
||||
export function formatTrackTime(value) {
|
||||
if (!value) return "";
|
||||
if (!value) return '';
|
||||
let min = ~~((value / 60) % 60);
|
||||
let sec = (~~(value % 60)).toString().padStart(2, "0");
|
||||
let sec = (~~(value % 60)).toString().padStart(2, '0');
|
||||
return `${min}:${sec}`;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,25 @@
|
|||
import axios from "axios";
|
||||
import Dexie from "dexie";
|
||||
import store from "@/store";
|
||||
import axios from 'axios';
|
||||
import Dexie from 'dexie';
|
||||
import store from '@/store';
|
||||
// import pkg from "../../package.json";
|
||||
|
||||
const db = new Dexie("yesplaymusic");
|
||||
const db = new Dexie('yesplaymusic');
|
||||
|
||||
db.version(2)
|
||||
.stores({
|
||||
trackSources: "&id",
|
||||
trackSources: '&id',
|
||||
})
|
||||
.upgrade((tx) =>
|
||||
.upgrade(tx =>
|
||||
tx
|
||||
.table("trackSources")
|
||||
.table('trackSources')
|
||||
.toCollection()
|
||||
.modify(
|
||||
(track) =>
|
||||
!track.createTime && (track.createTime = new Date().getTime())
|
||||
track => !track.createTime && (track.createTime = new Date().getTime())
|
||||
)
|
||||
);
|
||||
|
||||
db.version(1).stores({
|
||||
trackSources: "&id",
|
||||
trackSources: '&id',
|
||||
});
|
||||
|
||||
let tracksCacheBytes = 0;
|
||||
|
|
@ -33,7 +32,7 @@ async function deleteExcessCache() {
|
|||
return;
|
||||
}
|
||||
try {
|
||||
const delCache = await db.trackSources.orderBy("createTime").first();
|
||||
const delCache = await db.trackSources.orderBy('createTime').first();
|
||||
await db.trackSources.delete(delCache.id);
|
||||
tracksCacheBytes -= delCache.source.byteLength;
|
||||
console.debug(
|
||||
|
|
@ -41,18 +40,18 @@ async function deleteExcessCache() {
|
|||
);
|
||||
deleteExcessCache();
|
||||
} catch (error) {
|
||||
console.debug("[debug][db.js] deleteExcessCacheFailed", error);
|
||||
console.debug('[debug][db.js] deleteExcessCacheFailed', error);
|
||||
}
|
||||
}
|
||||
|
||||
export function cacheTrackSource(trackInfo, url, bitRate, from = "netease") {
|
||||
export function cacheTrackSource(trackInfo, url, bitRate, from = 'netease') {
|
||||
const name = trackInfo.name;
|
||||
const artist = trackInfo.ar[0]?.name || trackInfo.artists[0]?.name;
|
||||
return axios
|
||||
.get(url, {
|
||||
responseType: "arraybuffer",
|
||||
responseType: 'arraybuffer',
|
||||
})
|
||||
.then((response) => {
|
||||
.then(response => {
|
||||
db.trackSources.put({
|
||||
id: trackInfo.id,
|
||||
source: response.data,
|
||||
|
|
@ -70,7 +69,7 @@ export function cacheTrackSource(trackInfo, url, bitRate, from = "netease") {
|
|||
}
|
||||
|
||||
export function getTrackSource(id) {
|
||||
return db.trackSources.get(Number(id)).then((track) => {
|
||||
return db.trackSources.get(Number(id)).then(track => {
|
||||
if (!track) return null;
|
||||
console.debug(
|
||||
`[debug][db.js] get track from cache 👉 ${track.name} by ${track.artist}`
|
||||
|
|
@ -82,7 +81,7 @@ export function getTrackSource(id) {
|
|||
export function countDBSize() {
|
||||
const trackSizes = [];
|
||||
return db.trackSources
|
||||
.each((track) => {
|
||||
.each(track => {
|
||||
trackSizes.push(track.source.byteLength);
|
||||
})
|
||||
.then(() => {
|
||||
|
|
@ -99,7 +98,7 @@ export function countDBSize() {
|
|||
}
|
||||
|
||||
export function clearDB() {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
db.tables.forEach(function (table) {
|
||||
table.clear();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,63 +1,63 @@
|
|||
import Vue from "vue";
|
||||
import dayjs from "dayjs";
|
||||
import duration from "dayjs/plugin/duration";
|
||||
import relativeTime from "dayjs/plugin/relativeTime";
|
||||
import locale from "@/locale";
|
||||
import Vue from 'vue';
|
||||
import dayjs from 'dayjs';
|
||||
import duration from 'dayjs/plugin/duration';
|
||||
import relativeTime from 'dayjs/plugin/relativeTime';
|
||||
import locale from '@/locale';
|
||||
|
||||
Vue.filter("formatTime", (Milliseconds, format = "HH:MM:SS") => {
|
||||
if (!Milliseconds) return "";
|
||||
Vue.filter('formatTime', (Milliseconds, format = 'HH:MM:SS') => {
|
||||
if (!Milliseconds) return '';
|
||||
dayjs.extend(duration);
|
||||
dayjs.extend(relativeTime);
|
||||
|
||||
let time = dayjs.duration(Milliseconds);
|
||||
let hours = time.hours().toString();
|
||||
let mins = time.minutes().toString();
|
||||
let seconds = time.seconds().toString().padStart(2, "0");
|
||||
let seconds = time.seconds().toString().padStart(2, '0');
|
||||
|
||||
if (format === "HH:MM:SS") {
|
||||
return hours !== "0"
|
||||
? `${hours}:${mins.padStart(2, "0")}:${seconds}`
|
||||
if (format === 'HH:MM:SS') {
|
||||
return hours !== '0'
|
||||
? `${hours}:${mins.padStart(2, '0')}:${seconds}`
|
||||
: `${mins}:${seconds}`;
|
||||
} else if (format === "Human") {
|
||||
const hoursUnit = locale.locale === "zh-CN" ? "小时" : "hr";
|
||||
const minitesUnit = locale.locale === "zh-CN" ? "分钟" : "min";
|
||||
return hours !== "0"
|
||||
} else if (format === 'Human') {
|
||||
const hoursUnit = locale.locale === 'zh-CN' ? '小时' : 'hr';
|
||||
const minitesUnit = locale.locale === 'zh-CN' ? '分钟' : 'min';
|
||||
return hours !== '0'
|
||||
? `${hours} ${hoursUnit} ${mins} ${minitesUnit}`
|
||||
: `${mins} ${minitesUnit}`;
|
||||
}
|
||||
});
|
||||
|
||||
Vue.filter("formatDate", (timestamp, format = "MMM D, YYYY") => {
|
||||
if (!timestamp) return "";
|
||||
if (locale.locale === "zh-CN") format = "YYYY年MM月DD日";
|
||||
Vue.filter('formatDate', (timestamp, format = 'MMM D, YYYY') => {
|
||||
if (!timestamp) return '';
|
||||
if (locale.locale === 'zh-CN') format = 'YYYY年MM月DD日';
|
||||
return dayjs(timestamp).format(format);
|
||||
});
|
||||
|
||||
Vue.filter("formatAlbumType", (type, album) => {
|
||||
if (!type) return "";
|
||||
if (type === "EP/Single") {
|
||||
return album.size === 1 ? "Single" : "EP";
|
||||
} else if (type === "Single") {
|
||||
return "Single";
|
||||
} else if (type === "专辑") {
|
||||
return "Album";
|
||||
Vue.filter('formatAlbumType', (type, album) => {
|
||||
if (!type) return '';
|
||||
if (type === 'EP/Single') {
|
||||
return album.size === 1 ? 'Single' : 'EP';
|
||||
} else if (type === 'Single') {
|
||||
return 'Single';
|
||||
} else if (type === '专辑') {
|
||||
return 'Album';
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
});
|
||||
|
||||
Vue.filter("resizeImage", (imgUrl, size = 512) => {
|
||||
if (!imgUrl) return "";
|
||||
Vue.filter('resizeImage', (imgUrl, size = 512) => {
|
||||
if (!imgUrl) return '';
|
||||
let httpsImgUrl = imgUrl;
|
||||
if (imgUrl.slice(0, 5) !== "https") {
|
||||
httpsImgUrl = "https" + imgUrl.slice(4);
|
||||
if (imgUrl.slice(0, 5) !== 'https') {
|
||||
httpsImgUrl = 'https' + imgUrl.slice(4);
|
||||
}
|
||||
return `${httpsImgUrl}?param=${size}y${size}`;
|
||||
});
|
||||
|
||||
Vue.filter("formatPlayCount", (count) => {
|
||||
if (!count) return "";
|
||||
if (locale.locale === "zh-CN") {
|
||||
Vue.filter('formatPlayCount', count => {
|
||||
if (!count) return '';
|
||||
if (locale.locale === 'zh-CN') {
|
||||
if (count > 100000000) {
|
||||
return `${Math.floor((count / 100000000) * 100) / 100}亿`; // 2.32 亿
|
||||
}
|
||||
|
|
@ -82,7 +82,7 @@ Vue.filter("formatPlayCount", (count) => {
|
|||
}
|
||||
});
|
||||
|
||||
Vue.filter("toHttps", (url) => {
|
||||
if (!url) return "";
|
||||
return url.replace(/^http:/, "https:");
|
||||
Vue.filter('toHttps', url => {
|
||||
if (!url) return '';
|
||||
return url.replace(/^http:/, 'https:');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,29 +2,29 @@
|
|||
|
||||
export function lyricParser(lrc) {
|
||||
return {
|
||||
lyric: parseLyric(lrc?.lrc?.lyric || ""),
|
||||
tlyric: parseLyric(lrc?.tlyric?.lyric || ""),
|
||||
lyric: parseLyric(lrc?.lrc?.lyric || ''),
|
||||
tlyric: parseLyric(lrc?.tlyric?.lyric || ''),
|
||||
lyricuser: lrc.lyricUser,
|
||||
transuser: lrc.transUser,
|
||||
};
|
||||
}
|
||||
|
||||
export function parseLyric(lrc) {
|
||||
const lyrics = lrc.split("\n");
|
||||
const lyrics = lrc.split('\n');
|
||||
const lrcObj = [];
|
||||
for (let i = 0; i < lyrics.length; i++) {
|
||||
const lyric = decodeURIComponent(lyrics[i]);
|
||||
const timeReg = /\[\d*:\d*((\.|:)\d*)*\]/g;
|
||||
const timeRegExpArr = lyric.match(timeReg);
|
||||
if (!timeRegExpArr) continue;
|
||||
const content = lyric.replace(timeReg, "");
|
||||
const content = lyric.replace(timeReg, '');
|
||||
for (let k = 0, h = timeRegExpArr.length; k < h; k++) {
|
||||
const t = timeRegExpArr[k];
|
||||
const min = Number(String(t.match(/\[\d*/i)).slice(1));
|
||||
const sec = Number(String(t.match(/:\d*/i)).slice(1));
|
||||
const ms = Number(t.match(/\d*\]/i)[0].slice(0, 2)) / 100;
|
||||
const time = min * 60 + sec + ms;
|
||||
if (content !== "") {
|
||||
if (content !== '') {
|
||||
lrcObj.push({ time: time, rawTime: timeRegExpArr[0], content });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,11 +15,11 @@ const nativeAlert = (() => {
|
|||
if (process.env.IS_ELECTRON === true) {
|
||||
const {
|
||||
remote: { dialog },
|
||||
} = require("electron");
|
||||
} = require('electron');
|
||||
if (dialog) {
|
||||
return (message) => {
|
||||
return message => {
|
||||
var options = {
|
||||
type: "warning",
|
||||
type: 'warning',
|
||||
detail: message,
|
||||
};
|
||||
dialog.showMessageBoxSync(null, options);
|
||||
|
|
|
|||
|
|
@ -1,41 +1,41 @@
|
|||
export const byAppleMusic = [
|
||||
{
|
||||
coverImgUrl:
|
||||
"https://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg",
|
||||
name: "Happy Hits",
|
||||
'https://p2.music.126.net/GvYQoflE99eoeGi9jG4Bsw==/109951165375336156.jpg',
|
||||
name: 'Happy Hits',
|
||||
id: 5278068783,
|
||||
},
|
||||
{
|
||||
coverImgUrl:
|
||||
"https://p2.music.126.net/5CJeYN35LnzRDsv5Lcs0-Q==/109951165374966765.jpg",
|
||||
name: "\u4e2d\u563b\u5408\u74a7",
|
||||
'https://p2.music.126.net/5CJeYN35LnzRDsv5Lcs0-Q==/109951165374966765.jpg',
|
||||
name: '\u4e2d\u563b\u5408\u74a7',
|
||||
id: 5277771961,
|
||||
},
|
||||
{
|
||||
coverImgUrl:
|
||||
"https://p1.music.126.net/cPaBXr1wZSg86ddl47AK7Q==/109951165375130918.jpg",
|
||||
name: "Heartbreak Pop",
|
||||
'https://p1.music.126.net/cPaBXr1wZSg86ddl47AK7Q==/109951165375130918.jpg',
|
||||
name: 'Heartbreak Pop',
|
||||
id: 5277965913,
|
||||
},
|
||||
{
|
||||
coverImgUrl:
|
||||
"https://p2.music.126.net/FDtX55P2NjccDna-LBj9PA==/109951165375065973.jpg",
|
||||
name: "Festival Bangers",
|
||||
'https://p2.music.126.net/FDtX55P2NjccDna-LBj9PA==/109951165375065973.jpg',
|
||||
name: 'Festival Bangers',
|
||||
id: 5277969451,
|
||||
},
|
||||
{
|
||||
coverImgUrl:
|
||||
"https://p2.music.126.net/hC0q2dGbOWHVfg4nkhIXPg==/109951165374881177.jpg",
|
||||
name: "Bedtime Beats",
|
||||
'https://p2.music.126.net/hC0q2dGbOWHVfg4nkhIXPg==/109951165374881177.jpg',
|
||||
name: 'Bedtime Beats',
|
||||
id: 5277778542,
|
||||
},
|
||||
];
|
||||
|
||||
export const playlistCategories = [
|
||||
{
|
||||
name: "全部",
|
||||
name: '全部',
|
||||
enable: true,
|
||||
bigCat: "static",
|
||||
bigCat: 'static',
|
||||
},
|
||||
// {
|
||||
// name: "For You",
|
||||
|
|
@ -43,9 +43,9 @@ export const playlistCategories = [
|
|||
// bigCat: "static",
|
||||
// },
|
||||
{
|
||||
name: "推荐歌单",
|
||||
name: '推荐歌单',
|
||||
enable: true,
|
||||
bigCat: "static",
|
||||
bigCat: 'static',
|
||||
},
|
||||
// {
|
||||
// name: "最新专辑",
|
||||
|
|
@ -53,368 +53,368 @@ export const playlistCategories = [
|
|||
// bigCat: "static",
|
||||
// },
|
||||
{
|
||||
name: "精品歌单",
|
||||
name: '精品歌单',
|
||||
enable: true,
|
||||
bigCat: "static",
|
||||
bigCat: 'static',
|
||||
},
|
||||
{
|
||||
name: "官方",
|
||||
name: '官方',
|
||||
enable: true,
|
||||
bigCat: "static",
|
||||
bigCat: 'static',
|
||||
},
|
||||
{
|
||||
name: "排行榜",
|
||||
name: '排行榜',
|
||||
enable: true,
|
||||
bigCat: "static",
|
||||
bigCat: 'static',
|
||||
},
|
||||
{
|
||||
name: "华语",
|
||||
name: '华语',
|
||||
enable: false,
|
||||
bigCat: "语种",
|
||||
bigCat: '语种',
|
||||
},
|
||||
{
|
||||
name: "欧美",
|
||||
name: '欧美',
|
||||
enable: true,
|
||||
bigCat: "语种",
|
||||
bigCat: '语种',
|
||||
},
|
||||
{
|
||||
name: "日语",
|
||||
name: '日语',
|
||||
enable: false,
|
||||
bigCat: "语种",
|
||||
bigCat: '语种',
|
||||
},
|
||||
{
|
||||
name: "韩语",
|
||||
name: '韩语',
|
||||
enable: false,
|
||||
bigCat: "语种",
|
||||
bigCat: '语种',
|
||||
},
|
||||
{
|
||||
name: "粤语",
|
||||
name: '粤语',
|
||||
enable: false,
|
||||
bigCat: "语种",
|
||||
bigCat: '语种',
|
||||
},
|
||||
{
|
||||
name: "流行",
|
||||
name: '流行',
|
||||
enable: true,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "摇滚",
|
||||
name: '摇滚',
|
||||
enable: true,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "民谣",
|
||||
name: '民谣',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "电子",
|
||||
name: '电子',
|
||||
enable: true,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "舞曲",
|
||||
name: '舞曲',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "说唱",
|
||||
name: '说唱',
|
||||
enable: true,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "轻音乐",
|
||||
name: '轻音乐',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "爵士",
|
||||
name: '爵士',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "乡村",
|
||||
name: '乡村',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "R&B/Soul",
|
||||
name: 'R&B/Soul',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "古典",
|
||||
name: '古典',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "民族",
|
||||
name: '民族',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "英伦",
|
||||
name: '英伦',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "金属",
|
||||
name: '金属',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "朋克",
|
||||
name: '朋克',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "蓝调",
|
||||
name: '蓝调',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "雷鬼",
|
||||
name: '雷鬼',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "世界音乐",
|
||||
name: '世界音乐',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "拉丁",
|
||||
name: '拉丁',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "New Age",
|
||||
name: 'New Age',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "古风",
|
||||
name: '古风',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "后摇",
|
||||
name: '后摇',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "Bossa Nova",
|
||||
name: 'Bossa Nova',
|
||||
enable: false,
|
||||
bigCat: "风格",
|
||||
bigCat: '风格',
|
||||
},
|
||||
{
|
||||
name: "清晨",
|
||||
name: '清晨',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "夜晚",
|
||||
name: '夜晚',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "学习",
|
||||
name: '学习',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "工作",
|
||||
name: '工作',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "午休",
|
||||
name: '午休',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "下午茶",
|
||||
name: '下午茶',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "地铁",
|
||||
name: '地铁',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "驾车",
|
||||
name: '驾车',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "运动",
|
||||
name: '运动',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "旅行",
|
||||
name: '旅行',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "散步",
|
||||
name: '散步',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "酒吧",
|
||||
name: '酒吧',
|
||||
enable: false,
|
||||
bigCat: "场景",
|
||||
bigCat: '场景',
|
||||
},
|
||||
{
|
||||
name: "怀旧",
|
||||
name: '怀旧',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "清新",
|
||||
name: '清新',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "浪漫",
|
||||
name: '浪漫',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "伤感",
|
||||
name: '伤感',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "治愈",
|
||||
name: '治愈',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "放松",
|
||||
name: '放松',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "孤独",
|
||||
name: '孤独',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "感动",
|
||||
name: '感动',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "兴奋",
|
||||
name: '兴奋',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "快乐",
|
||||
name: '快乐',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "安静",
|
||||
name: '安静',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "思念",
|
||||
name: '思念',
|
||||
enable: false,
|
||||
bigCat: "情感",
|
||||
bigCat: '情感',
|
||||
},
|
||||
{
|
||||
name: "综艺",
|
||||
name: '综艺',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "影视原声",
|
||||
name: '影视原声',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "ACG",
|
||||
name: 'ACG',
|
||||
enable: true,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "儿童",
|
||||
name: '儿童',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "校园",
|
||||
name: '校园',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "游戏",
|
||||
name: '游戏',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "70后",
|
||||
name: '70后',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "80后",
|
||||
name: '80后',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "90后",
|
||||
name: '90后',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "网络歌曲",
|
||||
name: '网络歌曲',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "KTV",
|
||||
name: 'KTV',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "经典",
|
||||
name: '经典',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "翻唱",
|
||||
name: '翻唱',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "吉他",
|
||||
name: '吉他',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "钢琴",
|
||||
name: '钢琴',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "器乐",
|
||||
name: '器乐',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "榜单",
|
||||
name: '榜单',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
{
|
||||
name: "00后",
|
||||
name: '00后',
|
||||
enable: false,
|
||||
bigCat: "主题",
|
||||
bigCat: '主题',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
import initLocalStorage from "@/store/initLocalStorage.js";
|
||||
import pkg from "../../package.json";
|
||||
import initLocalStorage from '@/store/initLocalStorage.js';
|
||||
import pkg from '../../package.json';
|
||||
|
||||
const updateSetting = () => {
|
||||
const parsedSettings = JSON.parse(localStorage.getItem("settings"));
|
||||
const parsedSettings = JSON.parse(localStorage.getItem('settings'));
|
||||
const settings = {
|
||||
...initLocalStorage.settings,
|
||||
...parsedSettings,
|
||||
};
|
||||
|
||||
localStorage.setItem("settings", JSON.stringify(settings));
|
||||
localStorage.setItem('settings', JSON.stringify(settings));
|
||||
};
|
||||
|
||||
const updateData = () => {
|
||||
const parsedData = JSON.parse(localStorage.getItem("data"));
|
||||
const parsedData = JSON.parse(localStorage.getItem('data'));
|
||||
const data = {
|
||||
...parsedData,
|
||||
};
|
||||
localStorage.setItem("data", JSON.stringify(data));
|
||||
localStorage.setItem('data', JSON.stringify(data));
|
||||
};
|
||||
|
||||
const updatePlayer = () => {
|
||||
let parsedData = JSON.parse(localStorage.getItem("player"));
|
||||
let appVersion = localStorage.getItem("appVersion");
|
||||
let parsedData = JSON.parse(localStorage.getItem('player'));
|
||||
let appVersion = localStorage.getItem('appVersion');
|
||||
if (appVersion === `"0.2.5"`) parsedData = {}; // 0.2.6版本重构了player
|
||||
const data = {
|
||||
_repeatMode: "off",
|
||||
_repeatMode: 'off',
|
||||
_shuffle: false,
|
||||
_list: [],
|
||||
_current: 0,
|
||||
|
|
@ -38,12 +38,12 @@ const updatePlayer = () => {
|
|||
_shuffledCurrent: 0,
|
||||
...parsedData,
|
||||
};
|
||||
localStorage.setItem("player", JSON.stringify(data));
|
||||
localStorage.setItem('player', JSON.stringify(data));
|
||||
};
|
||||
|
||||
const removeOldStuff = () => {
|
||||
// remove old indexedDB databases created by localforage
|
||||
indexedDB.deleteDatabase("tracks");
|
||||
indexedDB.deleteDatabase('tracks');
|
||||
};
|
||||
|
||||
export default function () {
|
||||
|
|
@ -51,5 +51,5 @@ export default function () {
|
|||
updateData();
|
||||
updatePlayer();
|
||||
removeOldStuff();
|
||||
localStorage.setItem("appVersion", JSON.stringify(pkg.version));
|
||||
localStorage.setItem('appVersion', JSON.stringify(pkg.version));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,21 @@
|
|||
<template>
|
||||
<div class="album" v-show="show">
|
||||
<div v-show="show" class="album">
|
||||
<div class="playlist-info">
|
||||
<Cover
|
||||
:imageUrl="album.picUrl | resizeImage(1024)"
|
||||
:showPlayButton="true"
|
||||
:alwaysShowShadow="true"
|
||||
:clickCoverToPlay="true"
|
||||
:fixedSize="288"
|
||||
type="album"
|
||||
:id="album.id"
|
||||
:coverHover="false"
|
||||
:playButtonSize="18"
|
||||
:image-url="album.picUrl | resizeImage(1024)"
|
||||
:show-play-button="true"
|
||||
:always-show-shadow="true"
|
||||
:click-cover-to-play="true"
|
||||
:fixed-size="288"
|
||||
type="album"
|
||||
:cover-hover="false"
|
||||
:play-button-size="18"
|
||||
@click.right.native="openMenu"
|
||||
/>
|
||||
<div class="info">
|
||||
<div class="title" @click.right="openMenu"> {{ title }}</div>
|
||||
<div class="subtitle" v-if="subtitle !== ''" @click.right="openMenu">{{
|
||||
<div v-if="subtitle !== ''" class="subtitle" @click.right="openMenu">{{
|
||||
subtitle
|
||||
}}</div>
|
||||
<div class="artist">
|
||||
|
|
@ -28,42 +28,42 @@
|
|||
<span v-else>Compilation by Various Artists</span>
|
||||
</div>
|
||||
<div class="date-and-count">
|
||||
<span class="explicit-symbol" v-if="album.mark === 1056768"
|
||||
<span v-if="album.mark === 1056768" class="explicit-symbol"
|
||||
><ExplicitSymbol
|
||||
/></span>
|
||||
<span :title="album.publishTime | formatDate">{{
|
||||
new Date(album.publishTime).getFullYear()
|
||||
}}</span>
|
||||
<span> · {{ album.size }} {{ $t("common.songs") }}</span
|
||||
<span> · {{ album.size }} {{ $t('common.songs') }}</span
|
||||
>,
|
||||
{{ albumTime | formatTime("Human") }}
|
||||
{{ albumTime | formatTime('Human') }}
|
||||
</div>
|
||||
<div class="description" @click="showFullDescription = true">
|
||||
{{ album.description }}
|
||||
</div>
|
||||
<div class="buttons" style="margin-top: 32px">
|
||||
<ButtonTwoTone
|
||||
icon-class="play"
|
||||
@click.native="playAlbumByID(album.id)"
|
||||
iconClass="play"
|
||||
>
|
||||
{{ $t("common.play") }}
|
||||
{{ $t('common.play') }}
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
:iconClass="dynamicDetail.isSub ? 'heart-solid' : 'heart'"
|
||||
:iconButton="true"
|
||||
:horizontalPadding="0"
|
||||
:icon-class="dynamicDetail.isSub ? 'heart-solid' : 'heart'"
|
||||
:icon-button="true"
|
||||
:horizontal-padding="0"
|
||||
:color="dynamicDetail.isSub ? 'blue' : 'grey'"
|
||||
:textColor="dynamicDetail.isSub ? '#335eea' : ''"
|
||||
:backgroundColor="
|
||||
:text-color="dynamicDetail.isSub ? '#335eea' : ''"
|
||||
:background-color="
|
||||
dynamicDetail.isSub ? 'var(--color-secondary-bg)' : ''
|
||||
"
|
||||
@click.native="likeAlbum"
|
||||
>
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
iconClass="more"
|
||||
:iconButton="true"
|
||||
:horizontalPadding="0"
|
||||
icon-class="more"
|
||||
:icon-button="true"
|
||||
:horizontal-padding="0"
|
||||
color="grey"
|
||||
@click.native="openMenu"
|
||||
>
|
||||
|
|
@ -72,22 +72,22 @@
|
|||
</div>
|
||||
</div>
|
||||
<TrackList
|
||||
:id="album.id"
|
||||
:tracks="tracks"
|
||||
:type="'album'"
|
||||
:id="album.id"
|
||||
:albumObject="album"
|
||||
:album-object="album"
|
||||
/>
|
||||
<div class="extra-info">
|
||||
<div class="album-time"></div>
|
||||
<div class="release-date">
|
||||
{{ $t("album.released") }}
|
||||
{{ album.publishTime | formatDate("MMMM D, YYYY") }}
|
||||
{{ $t('album.released') }}
|
||||
{{ album.publishTime | formatDate('MMMM D, YYYY') }}
|
||||
</div>
|
||||
<div class="copyright" v-if="album.company !== null">
|
||||
<div v-if="album.company !== null" class="copyright">
|
||||
© {{ album.company }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="more-by" v-if="filteredMoreAlbums.length !== 0">
|
||||
<div v-if="filteredMoreAlbums.length !== 0" class="more-by">
|
||||
<div class="section-title">
|
||||
More by
|
||||
<router-link :to="`/artist/${album.artist.id}`"
|
||||
|
|
@ -98,15 +98,15 @@
|
|||
<CoverRow
|
||||
type="album"
|
||||
:items="filteredMoreAlbums"
|
||||
subText="albumType+releaseYear"
|
||||
sub-text="albumType+releaseYear"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Modal
|
||||
:show="showFullDescription"
|
||||
:close="() => (showFullDescription = false)"
|
||||
:showFooter="false"
|
||||
:clickOutsideHide="true"
|
||||
:show-footer="false"
|
||||
:click-outside-hide="true"
|
||||
title="专辑介绍"
|
||||
>
|
||||
<p class="description-fulltext">
|
||||
|
|
@ -114,9 +114,9 @@
|
|||
</p>
|
||||
</Modal>
|
||||
<ContextMenu ref="albumMenu">
|
||||
<div class="item">{{ $t("contextMenu.playNext") }}</div>
|
||||
<div class="item">{{ $t('contextMenu.playNext') }}</div>
|
||||
<div class="item" @click="likeAlbum(true)">{{
|
||||
dynamicDetail.isSub ? "从音乐库删除" : "保存到音乐库"
|
||||
dynamicDetail.isSub ? '从音乐库删除' : '保存到音乐库'
|
||||
}}</div>
|
||||
<div class="item">添加到歌单</div>
|
||||
</ContextMenu>
|
||||
|
|
@ -124,24 +124,24 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapActions, mapState } from "vuex";
|
||||
import { getArtistAlbum } from "@/api/artist";
|
||||
import { getTrackDetail } from "@/api/track";
|
||||
import { getAlbum, albumDynamicDetail, likeAAlbum } from "@/api/album";
|
||||
import { splitSoundtrackAlbumTitle, splitAlbumTitle } from "@/utils/common";
|
||||
import NProgress from "nprogress";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import { mapMutations, mapActions, mapState } from 'vuex';
|
||||
import { getArtistAlbum } from '@/api/artist';
|
||||
import { getTrackDetail } from '@/api/track';
|
||||
import { getAlbum, albumDynamicDetail, likeAAlbum } from '@/api/album';
|
||||
import { splitSoundtrackAlbumTitle, splitAlbumTitle } from '@/utils/common';
|
||||
import NProgress from 'nprogress';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
|
||||
import ExplicitSymbol from "@/components/ExplicitSymbol.vue";
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import ContextMenu from "@/components/ContextMenu.vue";
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import Cover from "@/components/Cover.vue";
|
||||
import Modal from "@/components/Modal.vue";
|
||||
import ExplicitSymbol from '@/components/ExplicitSymbol.vue';
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
import ContextMenu from '@/components/ContextMenu.vue';
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
import Cover from '@/components/Cover.vue';
|
||||
import Modal from '@/components/Modal.vue';
|
||||
|
||||
export default {
|
||||
name: "Album",
|
||||
name: 'Album',
|
||||
components: {
|
||||
Cover,
|
||||
ButtonTwoTone,
|
||||
|
|
@ -151,11 +151,16 @@ export default {
|
|||
Modal,
|
||||
ContextMenu,
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
NProgress.start();
|
||||
this.loadData(to.params.id);
|
||||
next();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
album: {
|
||||
id: 0,
|
||||
picUrl: "",
|
||||
picUrl: '',
|
||||
artist: {
|
||||
id: 0,
|
||||
},
|
||||
|
|
@ -165,27 +170,27 @@ export default {
|
|||
show: false,
|
||||
moreAlbums: [],
|
||||
dynamicDetail: {},
|
||||
subtitle: "",
|
||||
title: "",
|
||||
subtitle: '',
|
||||
title: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player", "data"]),
|
||||
...mapState(['player', 'data']),
|
||||
albumTime() {
|
||||
let time = 0;
|
||||
this.tracks.map((t) => (time = time + t.dt));
|
||||
this.tracks.map(t => (time = time + t.dt));
|
||||
return time;
|
||||
},
|
||||
filteredMoreAlbums() {
|
||||
let moreAlbums = this.moreAlbums.filter((a) => a.id !== this.album.id);
|
||||
let realAlbums = moreAlbums.filter((a) => a.type === "专辑");
|
||||
let moreAlbums = this.moreAlbums.filter(a => a.id !== this.album.id);
|
||||
let realAlbums = moreAlbums.filter(a => a.type === '专辑');
|
||||
let eps = moreAlbums.filter(
|
||||
(a) => a.type === "EP" || (a.type === "EP/Single" && a.size > 1)
|
||||
a => a.type === 'EP' || (a.type === 'EP/Single' && a.size > 1)
|
||||
);
|
||||
let restItems = moreAlbums.filter(
|
||||
(a) =>
|
||||
realAlbums.find((a1) => a1.id === a.id) === undefined &&
|
||||
eps.find((a1) => a1.id === a.id) === undefined
|
||||
a =>
|
||||
realAlbums.find(a1 => a1.id === a.id) === undefined &&
|
||||
eps.find(a1 => a1.id === a.id) === undefined
|
||||
);
|
||||
if (realAlbums.length === 0) {
|
||||
return [...realAlbums, ...eps, ...restItems].slice(0, 5);
|
||||
|
|
@ -198,31 +203,31 @@ export default {
|
|||
this.loadData(this.$route.params.id);
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["appendTrackToPlayerList"]),
|
||||
...mapActions(["playFirstTrackOnList", "playTrackOnListByID", "showToast"]),
|
||||
playAlbumByID(id, trackID = "first") {
|
||||
...mapMutations(['appendTrackToPlayerList']),
|
||||
...mapActions(['playFirstTrackOnList', 'playTrackOnListByID', 'showToast']),
|
||||
playAlbumByID(id, trackID = 'first') {
|
||||
this.$store.state.player.playAlbumByID(id, trackID);
|
||||
},
|
||||
likeAlbum(toast = false) {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
likeAAlbum({
|
||||
id: this.album.id,
|
||||
t: this.dynamicDetail.isSub ? 0 : 1,
|
||||
})
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
if (data.code === 200) {
|
||||
this.dynamicDetail.isSub = !this.dynamicDetail.isSub;
|
||||
if (toast === true)
|
||||
this.showToast(
|
||||
this.dynamicDetail.isSub ? "已保存到音乐库" : "已从音乐库删除"
|
||||
this.dynamicDetail.isSub ? '已保存到音乐库' : '已从音乐库删除'
|
||||
);
|
||||
}
|
||||
console.log(data);
|
||||
})
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
this.showToast(`${error.response.data.message || error}`);
|
||||
});
|
||||
},
|
||||
|
|
@ -230,17 +235,17 @@ export default {
|
|||
let splitTitle = splitSoundtrackAlbumTitle(this.album.name);
|
||||
let splitTitle2 = splitAlbumTitle(splitTitle.title);
|
||||
this.title = splitTitle2.title;
|
||||
if (splitTitle.subtitle !== "" && splitTitle2.subtitle !== "") {
|
||||
this.subtitle = splitTitle.subtitle + " · " + splitTitle2.subtitle;
|
||||
if (splitTitle.subtitle !== '' && splitTitle2.subtitle !== '') {
|
||||
this.subtitle = splitTitle.subtitle + ' · ' + splitTitle2.subtitle;
|
||||
} else {
|
||||
this.subtitle =
|
||||
splitTitle.subtitle === ""
|
||||
splitTitle.subtitle === ''
|
||||
? splitTitle2.subtitle
|
||||
: splitTitle.subtitle;
|
||||
}
|
||||
},
|
||||
loadData(id) {
|
||||
getAlbum(id).then((data) => {
|
||||
getAlbum(id).then(data => {
|
||||
this.album = data.album;
|
||||
this.tracks = data.songs;
|
||||
this.formatTitle();
|
||||
|
|
@ -248,19 +253,17 @@ export default {
|
|||
this.show = true;
|
||||
|
||||
// to get explicit mark
|
||||
let trackIDs = this.tracks.map((t) => t.id);
|
||||
getTrackDetail(trackIDs.join(",")).then((data) => {
|
||||
let trackIDs = this.tracks.map(t => t.id);
|
||||
getTrackDetail(trackIDs.join(',')).then(data => {
|
||||
this.tracks = data.songs;
|
||||
});
|
||||
|
||||
// get more album by this artist
|
||||
getArtistAlbum({ id: this.album.artist.id, limit: 100 }).then(
|
||||
(data) => {
|
||||
getArtistAlbum({ id: this.album.artist.id, limit: 100 }).then(data => {
|
||||
this.moreAlbums = data.hotAlbums;
|
||||
}
|
||||
);
|
||||
});
|
||||
albumDynamicDetail(id).then((data) => {
|
||||
});
|
||||
albumDynamicDetail(id).then(data => {
|
||||
this.dynamicDetail = data;
|
||||
});
|
||||
},
|
||||
|
|
@ -268,11 +271,6 @@ export default {
|
|||
this.$refs.albumMenu.openMenu(e);
|
||||
},
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
NProgress.start();
|
||||
this.loadData(to.params.id);
|
||||
next();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,46 +1,46 @@
|
|||
<template>
|
||||
<div class="artist" v-show="show">
|
||||
<div v-show="show" class="artist">
|
||||
<div class="artist-info">
|
||||
<div class="head">
|
||||
<img :src="artist.img1v1Url | resizeImage(1024)" />
|
||||
</div>
|
||||
<div>
|
||||
<div class="name">{{ artist.name }}</div>
|
||||
<div class="artist">{{ $t("artist.artist") }}</div>
|
||||
<div class="artist">{{ $t('artist.artist') }}</div>
|
||||
<div class="statistics">
|
||||
<a @click="scrollTo('popularTracks')"
|
||||
>{{ artist.musicSize }} {{ $t("common.songs") }}</a
|
||||
>{{ artist.musicSize }} {{ $t('common.songs') }}</a
|
||||
>
|
||||
·
|
||||
<a @click="scrollTo('seeMore', 'start')"
|
||||
>{{ artist.albumSize }} {{ $t("artist.withAlbums") }}</a
|
||||
>{{ artist.albumSize }} {{ $t('artist.withAlbums') }}</a
|
||||
>
|
||||
·
|
||||
<a @click="scrollTo('mvs')"
|
||||
>{{ artist.mvSize }} {{ $t("artist.videos") }}</a
|
||||
>{{ artist.mvSize }} {{ $t('artist.videos') }}</a
|
||||
>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<ButtonTwoTone @click.native="playPopularSongs()" :iconClass="`play`">
|
||||
{{ $t("common.play") }}
|
||||
<ButtonTwoTone :icon-class="play" @click.native="playPopularSongs()">
|
||||
{{ $t('common.play') }}
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone @click.native="followArtist" color="grey">
|
||||
<span v-if="artist.followed">{{ $t("artist.following") }}</span>
|
||||
<span v-else>{{ $t("artist.follow") }}</span>
|
||||
<ButtonTwoTone color="grey" @click.native="followArtist">
|
||||
<span v-if="artist.followed">{{ $t('artist.following') }}</span>
|
||||
<span v-else>{{ $t('artist.follow') }}</span>
|
||||
</ButtonTwoTone>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="latest-release">
|
||||
<div class="section-title">{{ $t("artist.latestRelease") }}</div>
|
||||
<div class="section-title">{{ $t('artist.latestRelease') }}</div>
|
||||
<div class="release">
|
||||
<div class="container">
|
||||
<Cover
|
||||
:imageUrl="latestRelease.picUrl | resizeImage"
|
||||
type="album"
|
||||
:id="latestRelease.id"
|
||||
:fixedSize="128"
|
||||
:playButtonSize="30"
|
||||
:image-url="latestRelease.picUrl | resizeImage"
|
||||
type="album"
|
||||
:fixed-size="128"
|
||||
:play-button-size="30"
|
||||
/>
|
||||
<div class="info">
|
||||
<div class="name">
|
||||
|
|
@ -53,60 +53,60 @@
|
|||
</div>
|
||||
<div class="type">
|
||||
{{ latestRelease.type | formatAlbumType(latestRelease) }} ·
|
||||
{{ latestRelease.size }} {{ $t("common.songs") }}
|
||||
{{ latestRelease.size }} {{ $t('common.songs') }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="popular-tracks" id="popularTracks">
|
||||
<div class="section-title">{{ $t("artist.popularSongs") }}</div>
|
||||
<div id="popularTracks" class="popular-tracks">
|
||||
<div class="section-title">{{ $t('artist.popularSongs') }}</div>
|
||||
<TrackList
|
||||
:tracks="popularTracks.slice(0, showMorePopTracks ? 24 : 12)"
|
||||
:type="'tracklist'"
|
||||
/>
|
||||
|
||||
<div class="show-more" id="seeMore">
|
||||
<div id="seeMore" class="show-more">
|
||||
<button @click="showMorePopTracks = !showMorePopTracks">
|
||||
<span v-show="!showMorePopTracks">{{ $t("artist.showMore") }}</span>
|
||||
<span v-show="showMorePopTracks">{{ $t("artist.showLess") }}</span>
|
||||
<span v-show="!showMorePopTracks">{{ $t('artist.showMore') }}</span>
|
||||
<span v-show="showMorePopTracks">{{ $t('artist.showLess') }}</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="albums" id="albums" v-if="albums.length !== 0">
|
||||
<div class="section-title">{{ $t("artist.albums") }}</div>
|
||||
<div v-if="albums.length !== 0" id="albums" class="albums">
|
||||
<div class="section-title">{{ $t('artist.albums') }}</div>
|
||||
<CoverRow
|
||||
:type="'album'"
|
||||
:items="albums"
|
||||
:subText="'releaseYear'"
|
||||
:showPlayButton="true"
|
||||
:sub-text="'releaseYear'"
|
||||
:show-play-button="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="mvs" id="mvs" v-if="mvs.length !== 0">
|
||||
<div v-if="mvs.length !== 0" id="mvs" class="mvs">
|
||||
<div class="section-title"
|
||||
>MVs
|
||||
<router-link v-show="hasMoreMV" :to="`/artist/${this.artist.id}/mv`">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link>
|
||||
</div>
|
||||
<MvRow :mvs="mvs" subtitle="publishTime" />
|
||||
</div>
|
||||
<div class="eps" v-if="eps.length !== 0">
|
||||
<div class="section-title">{{ $t("artist.EPsSingles") }}</div>
|
||||
<div v-if="eps.length !== 0" class="eps">
|
||||
<div class="section-title">{{ $t('artist.EPsSingles') }}</div>
|
||||
<CoverRow
|
||||
:type="'album'"
|
||||
:items="eps"
|
||||
:subText="'albumType+releaseYear'"
|
||||
:showPlayButton="true"
|
||||
:sub-text="'albumType+releaseYear'"
|
||||
:show-play-button="true"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="similar-artists" v-if="similarArtists.length !== 0">
|
||||
<div v-if="similarArtists.length !== 0" class="similar-artists">
|
||||
<div class="section-title">相似艺人</div>
|
||||
<CoverRow
|
||||
type="artist"
|
||||
:columnNumber="6"
|
||||
:column-number="6"
|
||||
gap="36px 28px"
|
||||
:items="similarArtists.slice(0, 12)"
|
||||
/>
|
||||
|
|
@ -115,42 +115,48 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapActions, mapState } from "vuex";
|
||||
import { mapMutations, mapActions, mapState } from 'vuex';
|
||||
import {
|
||||
getArtist,
|
||||
getArtistAlbum,
|
||||
artistMv,
|
||||
followAArtist,
|
||||
similarArtists,
|
||||
} from "@/api/artist";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import NProgress from "nprogress";
|
||||
} from '@/api/artist';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import Cover from "@/components/Cover.vue";
|
||||
import MvRow from "@/components/MvRow.vue";
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
import Cover from '@/components/Cover.vue';
|
||||
import MvRow from '@/components/MvRow.vue';
|
||||
|
||||
export default {
|
||||
name: "Artist",
|
||||
name: 'Artist',
|
||||
components: { Cover, ButtonTwoTone, TrackList, CoverRow, MvRow },
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
NProgress.start();
|
||||
this.artist.img1v1Url =
|
||||
'https://p1.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg';
|
||||
this.loadData(to.params.id, next);
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
artist: {
|
||||
img1v1Url:
|
||||
"https://p1.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg",
|
||||
'https://p1.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg',
|
||||
},
|
||||
popularTracks: [],
|
||||
albumsData: [],
|
||||
latestRelease: {
|
||||
picUrl: "",
|
||||
picUrl: '',
|
||||
publishTime: 0,
|
||||
id: 0,
|
||||
name: "",
|
||||
type: "",
|
||||
size: "",
|
||||
name: '',
|
||||
type: '',
|
||||
size: '',
|
||||
},
|
||||
showMorePopTracks: false,
|
||||
mvs: [],
|
||||
|
|
@ -159,73 +165,16 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player"]),
|
||||
...mapState(['player']),
|
||||
albums() {
|
||||
return this.albumsData.filter((a) => a.type === "专辑");
|
||||
return this.albumsData.filter(a => a.type === '专辑');
|
||||
},
|
||||
eps() {
|
||||
return this.albumsData.filter((a) =>
|
||||
["EP/Single", "EP", "Single"].includes(a.type)
|
||||
return this.albumsData.filter(a =>
|
||||
['EP/Single', 'EP', 'Single'].includes(a.type)
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["appendTrackToPlayerList"]),
|
||||
...mapActions(["playFirstTrackOnList", "playTrackOnListByID"]),
|
||||
loadData(id, next = undefined) {
|
||||
getArtist(id).then((data) => {
|
||||
this.artist = data.artist;
|
||||
this.popularTracks = data.hotSongs;
|
||||
if (next !== undefined) next();
|
||||
NProgress.done();
|
||||
this.show = true;
|
||||
});
|
||||
getArtistAlbum({ id: id, limit: 200 }).then((data) => {
|
||||
this.albumsData = data.hotAlbums;
|
||||
this.latestRelease = data.hotAlbums[0];
|
||||
});
|
||||
artistMv({ id }).then((data) => {
|
||||
this.mvs = data.mvs;
|
||||
this.hasMoreMV = data.hasMore;
|
||||
});
|
||||
similarArtists(id).then((data) => {
|
||||
this.similarArtists = data.artists;
|
||||
});
|
||||
},
|
||||
goToAlbum(id) {
|
||||
this.$router.push({
|
||||
name: "album",
|
||||
params: { id },
|
||||
});
|
||||
},
|
||||
playPopularSongs(trackID = "first") {
|
||||
let trackIDs = this.popularTracks.map((t) => t.id);
|
||||
this.$store.state.player.replacePlaylist(
|
||||
trackIDs,
|
||||
this.artist.id,
|
||||
"artist",
|
||||
trackID
|
||||
);
|
||||
},
|
||||
followArtist() {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
return;
|
||||
}
|
||||
followAArtist({
|
||||
id: this.artist.id,
|
||||
t: this.artist.followed ? 0 : 1,
|
||||
}).then((data) => {
|
||||
if (data.code === 200) this.artist.followed = !this.artist.followed;
|
||||
});
|
||||
},
|
||||
scrollTo(div, block = "center") {
|
||||
document.getElementById(div).scrollIntoView({
|
||||
behavior: "smooth",
|
||||
block,
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.loadData(this.$route.params.id);
|
||||
},
|
||||
|
|
@ -238,11 +187,62 @@ export default {
|
|||
}
|
||||
}
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
NProgress.start();
|
||||
this.artist.img1v1Url =
|
||||
"https://p1.music.126.net/VnZiScyynLG7atLIZ2YPkw==/18686200114669622.jpg";
|
||||
this.loadData(to.params.id, next);
|
||||
methods: {
|
||||
...mapMutations(['appendTrackToPlayerList']),
|
||||
...mapActions(['playFirstTrackOnList', 'playTrackOnListByID']),
|
||||
loadData(id, next = undefined) {
|
||||
getArtist(id).then(data => {
|
||||
this.artist = data.artist;
|
||||
this.popularTracks = data.hotSongs;
|
||||
if (next !== undefined) next();
|
||||
NProgress.done();
|
||||
this.show = true;
|
||||
});
|
||||
getArtistAlbum({ id: id, limit: 200 }).then(data => {
|
||||
this.albumsData = data.hotAlbums;
|
||||
this.latestRelease = data.hotAlbums[0];
|
||||
});
|
||||
artistMv({ id }).then(data => {
|
||||
this.mvs = data.mvs;
|
||||
this.hasMoreMV = data.hasMore;
|
||||
});
|
||||
similarArtists(id).then(data => {
|
||||
this.similarArtists = data.artists;
|
||||
});
|
||||
},
|
||||
goToAlbum(id) {
|
||||
this.$router.push({
|
||||
name: 'album',
|
||||
params: { id },
|
||||
});
|
||||
},
|
||||
playPopularSongs(trackID = 'first') {
|
||||
let trackIDs = this.popularTracks.map(t => t.id);
|
||||
this.$store.state.player.replacePlaylist(
|
||||
trackIDs,
|
||||
this.artist.id,
|
||||
'artist',
|
||||
trackID
|
||||
);
|
||||
},
|
||||
followArtist() {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
followAArtist({
|
||||
id: this.artist.id,
|
||||
t: this.artist.followed ? 0 : 1,
|
||||
}).then(data => {
|
||||
if (data.code === 200) this.artist.followed = !this.artist.followed;
|
||||
});
|
||||
},
|
||||
scrollTo(div, block = 'center') {
|
||||
document.getElementById(div).scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block,
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -7,26 +7,32 @@
|
|||
</h1>
|
||||
<MvRow :mvs="mvs" subtitle="publishTime" />
|
||||
<div class="load-more">
|
||||
<ButtonTwoTone v-show="hasMore" @click.native="loadMVs" color="grey">{{
|
||||
$t("explore.loadMore")
|
||||
<ButtonTwoTone v-show="hasMore" color="grey" @click.native="loadMVs">{{
|
||||
$t('explore.loadMore')
|
||||
}}</ButtonTwoTone>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { artistMv, getArtist } from "@/api/artist";
|
||||
import NProgress from "nprogress";
|
||||
import { artistMv, getArtist } from '@/api/artist';
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import MvRow from "@/components/MvRow.vue";
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
import MvRow from '@/components/MvRow.vue';
|
||||
|
||||
export default {
|
||||
name: "artistMV",
|
||||
name: 'artistMV',
|
||||
components: {
|
||||
MvRow,
|
||||
ButtonTwoTone,
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
NProgress.start();
|
||||
this.id = to.params.id;
|
||||
this.loadData();
|
||||
next();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
id: 0,
|
||||
|
|
@ -36,24 +42,6 @@ export default {
|
|||
mvs: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
loadData() {
|
||||
getArtist(this.id).then((data) => {
|
||||
this.artist = data.artist;
|
||||
});
|
||||
this.loadMVs();
|
||||
},
|
||||
loadMVs() {
|
||||
artistMv({ id: this.id, limit: 100, offset: this.mvs.length }).then(
|
||||
(data) => {
|
||||
this.mvs.push(...data.mvs);
|
||||
this.hasMore = data.hasMore;
|
||||
NProgress.done();
|
||||
this.show = true;
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.id = this.$route.params.id;
|
||||
this.loadData();
|
||||
|
|
@ -68,11 +56,23 @@ export default {
|
|||
this.loadData();
|
||||
}
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
NProgress.start();
|
||||
this.id = to.params.id;
|
||||
this.loadData();
|
||||
next();
|
||||
methods: {
|
||||
loadData() {
|
||||
getArtist(this.id).then(data => {
|
||||
this.artist = data.artist;
|
||||
});
|
||||
this.loadMVs();
|
||||
},
|
||||
loadMVs() {
|
||||
artistMv({ id: this.id, limit: 100, offset: this.mvs.length }).then(
|
||||
data => {
|
||||
this.mvs.push(...data.mvs);
|
||||
this.hasMore = data.hasMore;
|
||||
NProgress.done();
|
||||
this.show = true;
|
||||
}
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -8,20 +8,20 @@
|
|||
<TrackList
|
||||
:tracks="dailyTracks"
|
||||
type="playlist"
|
||||
dbclickTrackFunc="dailyTracks"
|
||||
dbclick-track-func="dailyTracks"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapState } from "vuex";
|
||||
import NProgress from "nprogress";
|
||||
import { dailyRecommendTracks } from "@/api/playlist";
|
||||
import { mapMutations, mapState } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import { dailyRecommendTracks } from '@/api/playlist';
|
||||
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
|
||||
export default {
|
||||
name: "dailyTracks",
|
||||
name: 'dailyTracks',
|
||||
components: {
|
||||
TrackList,
|
||||
},
|
||||
|
|
@ -30,6 +30,9 @@ export default {
|
|||
show: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(['player', 'data', 'dailyTracks']),
|
||||
},
|
||||
created() {
|
||||
if (this.dailyTracks.length === 0) {
|
||||
NProgress.start();
|
||||
|
|
@ -38,13 +41,10 @@ export default {
|
|||
this.show = true;
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player", "data", "dailyTracks"]),
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateDailyTracks"]),
|
||||
...mapMutations(['updateDailyTracks']),
|
||||
loadDailyTracks() {
|
||||
dailyRecommendTracks().then((result) => {
|
||||
dailyRecommendTracks().then(result => {
|
||||
this.updateDailyTracks(result.data.dailySongs);
|
||||
NProgress.done();
|
||||
this.show = true;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div class="explore">
|
||||
<h1>{{ $t("explore.explore") }}</h1>
|
||||
<h1>{{ $t('explore.explore') }}</h1>
|
||||
<div class="buttons">
|
||||
<div
|
||||
v-for="category in settings.enabledPlaylistCategories"
|
||||
|
|
@ -57,29 +57,29 @@
|
|||
color="grey"
|
||||
:loading="loadingMore"
|
||||
@click.native="getPlaylist"
|
||||
>{{ $t("explore.loadMore") }}</ButtonTwoTone
|
||||
>{{ $t('explore.loadMore') }}</ButtonTwoTone
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapMutations } from "vuex";
|
||||
import NProgress from "nprogress";
|
||||
import { mapState, mapMutations } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import {
|
||||
topPlaylist,
|
||||
highQualityPlaylist,
|
||||
recommendPlaylist,
|
||||
toplists,
|
||||
} from "@/api/playlist";
|
||||
import { playlistCategories } from "@/utils/staticData";
|
||||
} from '@/api/playlist';
|
||||
import { playlistCategories } from '@/utils/staticData';
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import SvgIcon from "@/components/SvgIcon.vue";
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
import SvgIcon from '@/components/SvgIcon.vue';
|
||||
|
||||
export default {
|
||||
name: "Explore",
|
||||
name: 'Explore',
|
||||
components: {
|
||||
CoverRow,
|
||||
ButtonTwoTone,
|
||||
|
|
@ -99,38 +99,38 @@ export default {
|
|||
return {
|
||||
show: false,
|
||||
playlists: [],
|
||||
activeCategory: "全部",
|
||||
activeCategory: '全部',
|
||||
loadingMore: false,
|
||||
showLoadMoreButton: false,
|
||||
hasMore: true,
|
||||
allBigCats: ["语种", "风格", "场景", "情感", "主题"],
|
||||
allBigCats: ['语种', '风格', '场景', '情感', '主题'],
|
||||
showCatOptions: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
...mapState(['settings']),
|
||||
subText() {
|
||||
if (this.activeCategory === "排行榜") return "updateFrequency";
|
||||
if (this.activeCategory === "推荐歌单") return "copywriter";
|
||||
return "none";
|
||||
if (this.activeCategory === '排行榜') return 'updateFrequency';
|
||||
if (this.activeCategory === '推荐歌单') return 'copywriter';
|
||||
return 'none';
|
||||
},
|
||||
},
|
||||
activated() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["togglePlaylistCategory"]),
|
||||
...mapMutations(['togglePlaylistCategory']),
|
||||
loadData() {
|
||||
if (!this.show) NProgress.start();
|
||||
this.activeCategory =
|
||||
this.$route.query.category === undefined
|
||||
? "全部"
|
||||
? '全部'
|
||||
: this.$route.query.category;
|
||||
this.getPlaylist();
|
||||
},
|
||||
goToCategory(Category) {
|
||||
this.showCatOptions = false;
|
||||
this.$router.push({ path: "/explore?category=" + Category });
|
||||
this.$router.push({ path: '/explore?category=' + Category });
|
||||
},
|
||||
updatePlaylist(playlists) {
|
||||
this.playlists.push(...playlists);
|
||||
|
|
@ -141,19 +141,19 @@ export default {
|
|||
},
|
||||
getPlaylist() {
|
||||
this.loadingMore = true;
|
||||
if (this.activeCategory === "推荐歌单") {
|
||||
if (this.activeCategory === '推荐歌单') {
|
||||
return this.getRecommendPlayList();
|
||||
}
|
||||
if (this.activeCategory === "精品歌单") {
|
||||
if (this.activeCategory === '精品歌单') {
|
||||
return this.getHighQualityPlaylist();
|
||||
}
|
||||
if (this.activeCategory === "排行榜") {
|
||||
if (this.activeCategory === '排行榜') {
|
||||
return this.getTopLists();
|
||||
}
|
||||
return this.getTopPlayList();
|
||||
},
|
||||
getRecommendPlayList() {
|
||||
recommendPlaylist({ limit: 100 }).then((data) => {
|
||||
recommendPlaylist({ limit: 100 }).then(data => {
|
||||
this.playlists = [];
|
||||
this.updatePlaylist(data.result);
|
||||
});
|
||||
|
|
@ -162,13 +162,13 @@ export default {
|
|||
let playlists = this.playlists;
|
||||
let before =
|
||||
playlists.length !== 0 ? playlists[playlists.length - 1].updateTime : 0;
|
||||
highQualityPlaylist({ limit: 50, before }).then((data) => {
|
||||
highQualityPlaylist({ limit: 50, before }).then(data => {
|
||||
this.updatePlaylist(data.playlists);
|
||||
this.hasMore = data.more;
|
||||
});
|
||||
},
|
||||
getTopLists() {
|
||||
toplists().then((data) => {
|
||||
toplists().then(data => {
|
||||
this.playlists = [];
|
||||
this.updatePlaylist(data.list);
|
||||
});
|
||||
|
|
@ -177,13 +177,13 @@ export default {
|
|||
topPlaylist({
|
||||
cat: this.activeCategory,
|
||||
offset: this.playlists.length,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
this.updatePlaylist(data.playlists);
|
||||
this.hasMore = data.more;
|
||||
});
|
||||
},
|
||||
getCatsByBigCat(name) {
|
||||
return playlistCategories.filter((c) => c.bigCat === name);
|
||||
return playlistCategories.filter(c => c.bigCat === name);
|
||||
},
|
||||
toggleCat(name) {
|
||||
this.togglePlaylistCategory(name);
|
||||
|
|
|
|||
|
|
@ -1,25 +1,25 @@
|
|||
<template>
|
||||
<div class="home" v-show="show">
|
||||
<div class="index-row" v-if="settings.showPlaylistsByAppleMusic !== false">
|
||||
<div v-show="show" class="home">
|
||||
<div v-if="settings.showPlaylistsByAppleMusic !== false" class="index-row">
|
||||
<div class="title"> by Apple Music </div>
|
||||
<CoverRow
|
||||
:type="'playlist'"
|
||||
:items="byAppleMusic"
|
||||
:subText="'appleMusic'"
|
||||
:imageSize="1024"
|
||||
sub-text="appleMusic"
|
||||
:image-size="1024"
|
||||
/>
|
||||
</div>
|
||||
<div class="index-row">
|
||||
<div class="title">
|
||||
{{ $t("home.recommendPlaylist") }}
|
||||
{{ $t('home.recommendPlaylist') }}
|
||||
<router-link to="/explore?category=推荐歌单">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link>
|
||||
</div>
|
||||
<CoverRow
|
||||
:type="'playlist'"
|
||||
:items="recommendPlaylist.items"
|
||||
:subText="'copywriter'"
|
||||
sub-text="copywriter"
|
||||
/>
|
||||
</div>
|
||||
<div class="index-row">
|
||||
|
|
@ -30,51 +30,55 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="index-row">
|
||||
<div class="title">{{ $t("home.recommendArtist") }}</div>
|
||||
<div class="title">{{ $t('home.recommendArtist') }}</div>
|
||||
<CoverRow
|
||||
type="artist"
|
||||
:columnNumber="6"
|
||||
:column-number="6"
|
||||
:items="recommendArtists.items"
|
||||
/>
|
||||
</div>
|
||||
<div class="index-row">
|
||||
<div class="title">
|
||||
{{ $t("home.newAlbum") }}
|
||||
<router-link to="/new-album">{{ $t("home.seeMore") }}</router-link>
|
||||
{{ $t('home.newAlbum') }}
|
||||
<router-link to="/new-album">{{ $t('home.seeMore') }}</router-link>
|
||||
</div>
|
||||
<CoverRow type="album" :items="newReleasesAlbum.items" subText="artist" />
|
||||
<CoverRow
|
||||
type="album"
|
||||
:items="newReleasesAlbum.items"
|
||||
sub-text="artist"
|
||||
/>
|
||||
</div>
|
||||
<div class="index-row">
|
||||
<div class="title">
|
||||
{{ $t("home.charts") }}
|
||||
{{ $t('home.charts') }}
|
||||
<router-link to="/explore?category=排行榜">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link>
|
||||
</div>
|
||||
<CoverRow
|
||||
type="playlist"
|
||||
:items="topList.items"
|
||||
:subText="'updateFrequency'"
|
||||
:imageSize="1024"
|
||||
sub-text="updateFrequency"
|
||||
:image-size="1024"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { toplists, recommendPlaylist } from "@/api/playlist";
|
||||
import { toplistOfArtists } from "@/api/artist";
|
||||
import { byAppleMusic } from "@/utils/staticData";
|
||||
import { countDBSize } from "@/utils/db";
|
||||
import { newAlbums } from "@/api/album";
|
||||
import NProgress from "nprogress";
|
||||
import { mapState } from "vuex";
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import FMCard from "@/components/FMCard.vue";
|
||||
import DailyTracksCard from "@/components/DailyTracksCard.vue";
|
||||
import { toplists, recommendPlaylist } from '@/api/playlist';
|
||||
import { toplistOfArtists } from '@/api/artist';
|
||||
import { byAppleMusic } from '@/utils/staticData';
|
||||
import { countDBSize } from '@/utils/db';
|
||||
import { newAlbums } from '@/api/album';
|
||||
import NProgress from 'nprogress';
|
||||
import { mapState } from 'vuex';
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
import FMCard from '@/components/FMCard.vue';
|
||||
import DailyTracksCard from '@/components/DailyTracksCard.vue';
|
||||
|
||||
export default {
|
||||
name: "Home",
|
||||
name: 'Home',
|
||||
components: { CoverRow, FMCard, DailyTracksCard },
|
||||
data() {
|
||||
return {
|
||||
|
|
@ -92,28 +96,31 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["settings"]),
|
||||
...mapState(['settings']),
|
||||
byAppleMusic() {
|
||||
return byAppleMusic;
|
||||
},
|
||||
},
|
||||
activated() {
|
||||
this.loadData();
|
||||
},
|
||||
methods: {
|
||||
loadData() {
|
||||
if (!this.show) NProgress.start();
|
||||
recommendPlaylist({
|
||||
limit: 10,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
this.recommendPlaylist.items = data.result;
|
||||
NProgress.done();
|
||||
this.show = true;
|
||||
});
|
||||
newAlbums({
|
||||
area: "EA",
|
||||
area: 'EA',
|
||||
limit: 10,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
this.newReleasesAlbum.items = data.albums;
|
||||
});
|
||||
toplistOfArtists(2).then((data) => {
|
||||
toplistOfArtists(2).then(data => {
|
||||
let indexs = [];
|
||||
while (indexs.length < 6) {
|
||||
let tmp = ~~(Math.random() * 100);
|
||||
|
|
@ -124,17 +131,14 @@ export default {
|
|||
indexs.includes(index)
|
||||
);
|
||||
});
|
||||
toplists().then((data) => {
|
||||
this.topList.items = data.list.filter((l) =>
|
||||
toplists().then(data => {
|
||||
this.topList.items = data.list.filter(l =>
|
||||
this.topList.ids.includes(l.id)
|
||||
);
|
||||
});
|
||||
countDBSize();
|
||||
},
|
||||
},
|
||||
activated() {
|
||||
this.loadData();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -6,36 +6,36 @@
|
|||
<img src="/img/logos/lastfm.png" />
|
||||
</div>
|
||||
<div class="message">{{ message }}</div>
|
||||
<button @click="close" v-show="done"> 完成 </button>
|
||||
<button v-show="done" @click="close"> 完成 </button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { authGetSession } from "@/api/lastfm";
|
||||
import { authGetSession } from '@/api/lastfm';
|
||||
|
||||
export default {
|
||||
name: "lastfmCallback",
|
||||
name: 'LastfmCallback',
|
||||
data() {
|
||||
return { message: "请稍等...", done: false };
|
||||
return { message: '请稍等...', done: false };
|
||||
},
|
||||
created() {
|
||||
const token = new URLSearchParams(window.location.search).get("token");
|
||||
const token = new URLSearchParams(window.location.search).get('token');
|
||||
if (!token) {
|
||||
this.message = "连接失败,请重试或联系开发者(无Token)";
|
||||
this.message = '连接失败,请重试或联系开发者(无Token)';
|
||||
this.done = true;
|
||||
return;
|
||||
}
|
||||
console.log(token);
|
||||
authGetSession(token).then((result) => {
|
||||
authGetSession(token).then(result => {
|
||||
console.log(result);
|
||||
if (!result.data.session) {
|
||||
this.message = "连接失败,请重试或联系开发者(无Session)";
|
||||
this.message = '连接失败,请重试或联系开发者(无Session)';
|
||||
this.done = true;
|
||||
return;
|
||||
}
|
||||
localStorage.setItem("lastfm", JSON.stringify(result.data.session));
|
||||
this.$store.commit("updateLastfm", result.data.session);
|
||||
this.message = "已成功连接到 Last.fm";
|
||||
localStorage.setItem('lastfm', JSON.stringify(result.data.session));
|
||||
this.$store.commit('updateLastfm', result.data.session);
|
||||
this.message = '已成功连接到 Last.fm';
|
||||
this.done = true;
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -14,8 +14,8 @@
|
|||
>
|
||||
<div class="container" :class="{ active: activeCard === 1 }">
|
||||
<div class="title-info">
|
||||
<div class="title">{{ $t("login.loginText") }}</div>
|
||||
<div class="info">{{ $t("login.accessToAll") }}</div>
|
||||
<div class="title">{{ $t('login.loginText') }}</div>
|
||||
<div class="info">{{ $t('login.accessToAll') }}</div>
|
||||
</div>
|
||||
<svg-icon icon-class="arrow-right"></svg-icon>
|
||||
</div>
|
||||
|
|
@ -28,8 +28,8 @@
|
|||
>
|
||||
<div class="container" :class="{ active: activeCard === 2 }">
|
||||
<div class="title-info">
|
||||
<div class="title">{{ $t("login.search") }}</div>
|
||||
<div class="info">{{ $t("login.readonly") }}</div>
|
||||
<div class="title">{{ $t('login.search') }}</div>
|
||||
<div class="info">{{ $t('login.readonly') }}</div>
|
||||
</div>
|
||||
<svg-icon icon-class="arrow-right"></svg-icon>
|
||||
</div>
|
||||
|
|
@ -39,12 +39,12 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import NProgress from "nprogress";
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
import SvgIcon from "@/components/SvgIcon.vue";
|
||||
import SvgIcon from '@/components/SvgIcon.vue';
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
name: 'Login',
|
||||
components: {
|
||||
SvgIcon,
|
||||
},
|
||||
|
|
@ -58,7 +58,7 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
goTo(path) {
|
||||
this.$router.push({ path: "/login/" + path });
|
||||
this.$router.push({ path: '/login/' + path });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -3,26 +3,26 @@
|
|||
<div class="section-1">
|
||||
<img src="/img/logos/netease-music.png" />
|
||||
</div>
|
||||
<div class="title">{{ $t("login.loginText") }}</div>
|
||||
<div class="title">{{ $t('login.loginText') }}</div>
|
||||
<div class="section-2">
|
||||
<div class="input-box" v-show="mode === 'phone'">
|
||||
<div v-show="mode === 'phone'" class="input-box">
|
||||
<div class="container" :class="{ active: inputFocus === 'phone' }">
|
||||
<svg-icon icon-class="mobile" />
|
||||
<div class="inputs">
|
||||
<input
|
||||
id="countryCode"
|
||||
v-model="countryCode"
|
||||
:placeholder="
|
||||
inputFocus === 'phone' ? '' : $t('login.countryCode')
|
||||
"
|
||||
v-model="countryCode"
|
||||
@focus="inputFocus = 'phone'"
|
||||
@blur="inputFocus = ''"
|
||||
@keyup.enter="login"
|
||||
/>
|
||||
<input
|
||||
id="phoneNumber"
|
||||
:placeholder="inputFocus === 'phone' ? '' : $t('login.phone')"
|
||||
v-model="phoneNumber"
|
||||
:placeholder="inputFocus === 'phone' ? '' : $t('login.phone')"
|
||||
@focus="inputFocus = 'phone'"
|
||||
@blur="inputFocus = ''"
|
||||
@keyup.enter="login"
|
||||
|
|
@ -30,15 +30,15 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="input-box" v-show="mode === 'email'">
|
||||
<div v-show="mode === 'email'" class="input-box">
|
||||
<div class="container" :class="{ active: inputFocus === 'email' }">
|
||||
<svg-icon icon-class="mail" />
|
||||
<div class="inputs">
|
||||
<input
|
||||
type="email"
|
||||
id="email"
|
||||
:placeholder="inputFocus === 'email' ? '' : $t('login.email')"
|
||||
v-model="email"
|
||||
type="email"
|
||||
:placeholder="inputFocus === 'email' ? '' : $t('login.email')"
|
||||
@focus="inputFocus = 'email'"
|
||||
@blur="inputFocus = ''"
|
||||
@keyup.enter="login"
|
||||
|
|
@ -51,12 +51,12 @@
|
|||
<svg-icon icon-class="lock" />
|
||||
<div class="inputs">
|
||||
<input
|
||||
type="password"
|
||||
id="password"
|
||||
v-model="password"
|
||||
type="password"
|
||||
:placeholder="
|
||||
inputFocus === 'password' ? '' : $t('login.password')
|
||||
"
|
||||
v-model="password"
|
||||
@focus="inputFocus = 'password'"
|
||||
@blur="inputFocus = ''"
|
||||
@keyup.enter="login"
|
||||
|
|
@ -66,8 +66,8 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="confirm">
|
||||
<button @click="login" v-show="!processing">
|
||||
{{ $t("login.login") }}
|
||||
<button v-show="!processing" @click="login">
|
||||
{{ $t('login.login') }}
|
||||
</button>
|
||||
<button v-show="processing" class="loading" disabled>
|
||||
<span></span>
|
||||
|
|
@ -77,10 +77,10 @@
|
|||
</div>
|
||||
<div class="other-login">
|
||||
<a v-show="mode === 'phone'" @click="mode = 'email'">{{
|
||||
$t("login.loginWithEmail")
|
||||
$t('login.loginWithEmail')
|
||||
}}</a>
|
||||
<a v-show="mode === 'email'" @click="mode = 'phone'">{{
|
||||
$t("login.loginWithPhone")
|
||||
$t('login.loginWithPhone')
|
||||
}}</a>
|
||||
</div>
|
||||
<div
|
||||
|
|
@ -91,25 +91,25 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import NProgress from "nprogress";
|
||||
import { loginWithPhone, loginWithEmail } from "@/api/auth";
|
||||
import { setCookies } from "@/utils/auth";
|
||||
import md5 from "crypto-js/md5";
|
||||
import { mapMutations } from "vuex";
|
||||
import nativeAlert from "@/utils/nativeAlert";
|
||||
import NProgress from 'nprogress';
|
||||
import { loginWithPhone, loginWithEmail } from '@/api/auth';
|
||||
import { setCookies } from '@/utils/auth';
|
||||
import md5 from 'crypto-js/md5';
|
||||
import { mapMutations } from 'vuex';
|
||||
import nativeAlert from '@/utils/nativeAlert';
|
||||
|
||||
export default {
|
||||
name: "Login",
|
||||
name: 'Login',
|
||||
data() {
|
||||
return {
|
||||
processing: false,
|
||||
mode: "email",
|
||||
countryCode: "+86",
|
||||
phoneNumber: "",
|
||||
email: "",
|
||||
password: "",
|
||||
smsCode: "",
|
||||
inputFocus: "",
|
||||
mode: 'email',
|
||||
countryCode: '+86',
|
||||
phoneNumber: '',
|
||||
email: '',
|
||||
password: '',
|
||||
smsCode: '',
|
||||
inputFocus: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -118,20 +118,20 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
if (this.$route.query.mode === "phone") {
|
||||
this.mode = "phone";
|
||||
if (this.$route.query.mode === 'phone') {
|
||||
this.mode = 'phone';
|
||||
}
|
||||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateData"]),
|
||||
...mapMutations(['updateData']),
|
||||
validatePhone() {
|
||||
if (
|
||||
this.countryCode === "" ||
|
||||
this.phone === "" ||
|
||||
this.password === ""
|
||||
this.countryCode === '' ||
|
||||
this.phone === '' ||
|
||||
this.password === ''
|
||||
) {
|
||||
nativeAlert("国家区号或手机号不正确");
|
||||
nativeAlert('国家区号或手机号不正确');
|
||||
this.processing = false;
|
||||
return false;
|
||||
}
|
||||
|
|
@ -140,27 +140,27 @@ export default {
|
|||
validateEmail() {
|
||||
const emailReg = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
if (
|
||||
this.email === "" ||
|
||||
this.password === "" ||
|
||||
this.email === '' ||
|
||||
this.password === '' ||
|
||||
!emailReg.test(this.email)
|
||||
) {
|
||||
nativeAlert("邮箱不正确");
|
||||
nativeAlert('邮箱不正确');
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
login() {
|
||||
if (this.mode === "phone") {
|
||||
if (this.mode === 'phone') {
|
||||
this.processing = this.validatePhone();
|
||||
if (!this.processing) return;
|
||||
loginWithPhone({
|
||||
countrycode: this.countryCode.replace("+", "").replace(/\s/g, ""),
|
||||
phone: this.phoneNumber.replace(/\s/g, ""),
|
||||
password: "fakePassword",
|
||||
countrycode: this.countryCode.replace('+', '').replace(/\s/g, ''),
|
||||
phone: this.phoneNumber.replace(/\s/g, ''),
|
||||
password: 'fakePassword',
|
||||
md5_password: md5(this.password).toString(),
|
||||
})
|
||||
.then(this.handleLoginResponse)
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
this.processing = false;
|
||||
nativeAlert(`发生错误,请检查你的账号密码是否正确\n${error}`);
|
||||
});
|
||||
|
|
@ -168,12 +168,12 @@ export default {
|
|||
this.processing = this.validateEmail();
|
||||
if (!this.processing) return;
|
||||
loginWithEmail({
|
||||
email: this.email.replace(/\s/g, ""),
|
||||
password: "fakePassword",
|
||||
email: this.email.replace(/\s/g, ''),
|
||||
password: 'fakePassword',
|
||||
md5_password: md5(this.password).toString(),
|
||||
})
|
||||
.then(this.handleLoginResponse)
|
||||
.catch((error) => {
|
||||
.catch(error => {
|
||||
this.processing = false;
|
||||
nativeAlert(`发生错误,请检查你的账号密码是否正确\n${error}`);
|
||||
});
|
||||
|
|
@ -186,13 +186,13 @@ export default {
|
|||
}
|
||||
if (data.code === 200) {
|
||||
setCookies(data.cookie);
|
||||
this.updateData({ key: "user", value: data.profile });
|
||||
this.updateData({ key: "loginMode", value: "account" });
|
||||
this.$router.push({ path: "/library" });
|
||||
this.updateData({ key: 'user', value: data.profile });
|
||||
this.updateData({ key: 'loginMode', value: 'account' });
|
||||
this.$router.push({ path: '/library' });
|
||||
} else {
|
||||
this.processing = false;
|
||||
console.log(data.msg);
|
||||
nativeAlert(data.msg ?? data.message ?? "账号或密码错误,请检查");
|
||||
nativeAlert(data.msg ?? data.message ?? '账号或密码错误,请检查');
|
||||
}
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
<template>
|
||||
<div class="login">
|
||||
<div>
|
||||
<div class="title">{{ $t("login.usernameLogin") }}</div>
|
||||
<div class="sestion">
|
||||
<div class="title">{{ $t('login.usernameLogin') }}</div>
|
||||
<div class="section">
|
||||
<div class="search-box">
|
||||
<div class="container">
|
||||
<svg-icon icon-class="search" />
|
||||
<div class="input">
|
||||
<input
|
||||
:placeholder="$t('login.searchHolder')"
|
||||
v-model="keyword"
|
||||
:placeholder="$t('login.searchHolder')"
|
||||
@keydown.enter="throttleSearch"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -17,17 +17,17 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="sestion">
|
||||
<div class="name" v-show="activeUser.nickname === undefined">
|
||||
{{ $t("login.enterTip") }}
|
||||
<div v-show="activeUser.nickname === undefined" class="name">
|
||||
{{ $t('login.enterTip') }}
|
||||
</div>
|
||||
<div class="name" v-show="activeUser.nickname !== undefined">
|
||||
{{ $t("login.choose") }}
|
||||
<div v-show="activeUser.nickname !== undefined" class="name">
|
||||
{{ $t('login.choose') }}
|
||||
</div>
|
||||
<div class="user-list">
|
||||
<div
|
||||
class="user"
|
||||
v-for="user in result"
|
||||
:key="user.id"
|
||||
class="user"
|
||||
:class="{ active: user.nickname === activeUser.nickname }"
|
||||
@click="activeUser = user"
|
||||
>
|
||||
|
|
@ -39,32 +39,32 @@
|
|||
</div>
|
||||
</div>
|
||||
<ButtonTwoTone
|
||||
@click.native="confirm"
|
||||
v-show="activeUser.nickname !== undefined"
|
||||
@click.native="confirm"
|
||||
>
|
||||
{{ $t("login.confirm") }}
|
||||
{{ $t('login.confirm') }}
|
||||
</ButtonTwoTone>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations } from "vuex";
|
||||
import NProgress from "nprogress";
|
||||
import { search } from "@/api/others";
|
||||
import { userPlaylist } from "@/api/user";
|
||||
import { throttle } from "@/utils/common";
|
||||
import { mapMutations } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import { search } from '@/api/others';
|
||||
import { userPlaylist } from '@/api/user';
|
||||
import { throttle } from '@/utils/common';
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
|
||||
export default {
|
||||
name: "loginUsername",
|
||||
name: 'LoginUsername',
|
||||
components: {
|
||||
ButtonTwoTone,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
keyword: "",
|
||||
keyword: '',
|
||||
result: [],
|
||||
activeUser: {},
|
||||
};
|
||||
|
|
@ -73,26 +73,26 @@ export default {
|
|||
NProgress.done();
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["updateData"]),
|
||||
...mapMutations(['updateData']),
|
||||
search() {
|
||||
if (!this.keyword) return;
|
||||
search({ keywords: this.keyword, limit: 9, type: 1002 }).then((data) => {
|
||||
search({ keywords: this.keyword, limit: 9, type: 1002 }).then(data => {
|
||||
this.result = data.result.userprofiles;
|
||||
this.activeUser = this.result[0];
|
||||
});
|
||||
},
|
||||
confirm() {
|
||||
this.updateData({ key: "user", value: this.activeUser });
|
||||
this.updateData({ key: "loginMode", value: "username" });
|
||||
this.updateData({ key: 'user', value: this.activeUser });
|
||||
this.updateData({ key: 'loginMode', value: 'username' });
|
||||
userPlaylist({
|
||||
uid: this.activeUser.userId,
|
||||
limit: 1,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
this.updateData({
|
||||
key: "likedSongPlaylistID",
|
||||
key: 'likedSongPlaylistID',
|
||||
value: data.playlist[0].id,
|
||||
});
|
||||
this.$router.push({ path: "/library" });
|
||||
this.$router.push({ path: '/library' });
|
||||
});
|
||||
},
|
||||
throttleSearch: throttle(function () {
|
||||
|
|
|
|||
|
|
@ -215,7 +215,7 @@ export default {
|
|||
return this.player.currentTrack?.al?.picUrl + '?param=1024y1024';
|
||||
},
|
||||
bgImageUrl() {
|
||||
return this.player.currentTrack?.al?.picUrl + "?param=500y500";
|
||||
return this.player.currentTrack?.al?.picUrl + '?param=500y500';
|
||||
},
|
||||
progress: {
|
||||
get() {
|
||||
|
|
|
|||
132
src/views/mv.vue
132
src/views/mv.vue
|
|
@ -13,8 +13,8 @@
|
|||
{{ mv.data.name }}
|
||||
<div class="like-button">
|
||||
<button-icon @click.native="likeMV">
|
||||
<svg-icon icon-class="heart-solid" v-if="mv.subed"></svg-icon>
|
||||
<svg-icon icon-class="heart" v-else></svg-icon>
|
||||
<svg-icon v-if="mv.subed" icon-class="heart-solid"></svg-icon>
|
||||
<svg-icon v-else icon-class="heart"></svg-icon>
|
||||
</button-icon>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -25,107 +25,107 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="more-video">
|
||||
<div class="section-title">{{ $t("mv.moreVideo") }}</div>
|
||||
<div class="section-title">{{ $t('mv.moreVideo') }}</div>
|
||||
<MvRow :mvs="simiMvs" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mvDetail, mvUrl, simiMv, likeAMV } from "@/api/mv";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import NProgress from "nprogress";
|
||||
import "@/assets/css/plyr.css";
|
||||
import Plyr from "plyr";
|
||||
import { mvDetail, mvUrl, simiMv, likeAMV } from '@/api/mv';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
import NProgress from 'nprogress';
|
||||
import '@/assets/css/plyr.css';
|
||||
import Plyr from 'plyr';
|
||||
|
||||
import ButtonIcon from "@/components/ButtonIcon.vue";
|
||||
import MvRow from "@/components/MvRow.vue";
|
||||
import { mapActions } from "vuex";
|
||||
import ButtonIcon from '@/components/ButtonIcon.vue';
|
||||
import MvRow from '@/components/MvRow.vue';
|
||||
import { mapActions } from 'vuex';
|
||||
|
||||
export default {
|
||||
name: "mv",
|
||||
name: 'mv',
|
||||
components: {
|
||||
MvRow,
|
||||
ButtonIcon,
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
this.getData(to.params.id);
|
||||
next();
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
mv: {
|
||||
url: "",
|
||||
url: '',
|
||||
data: {
|
||||
name: "",
|
||||
artistName: "",
|
||||
playCount: "",
|
||||
publishTime: "",
|
||||
name: '',
|
||||
artistName: '',
|
||||
playCount: '',
|
||||
publishTime: '',
|
||||
},
|
||||
},
|
||||
player: null,
|
||||
simiMvs: [],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
...mapActions(["showToast"]),
|
||||
getData(id) {
|
||||
mvDetail(id).then((data) => {
|
||||
this.mv = data;
|
||||
let requests = data.data.brs.map((br) => {
|
||||
return mvUrl({ id, r: br.br });
|
||||
});
|
||||
Promise.all(requests).then((results) => {
|
||||
let sources = results.map((result) => {
|
||||
return {
|
||||
src: result.data.url.replace(/^http:/, "https:"),
|
||||
type: "video/mp4",
|
||||
size: result.data.r,
|
||||
};
|
||||
});
|
||||
this.player.source = {
|
||||
type: "video",
|
||||
title: this.mv.data.name,
|
||||
sources: sources,
|
||||
poster: this.mv.data.cover.replace(/^http:/, "https:"),
|
||||
};
|
||||
NProgress.done();
|
||||
});
|
||||
});
|
||||
simiMv(id).then((data) => {
|
||||
this.simiMvs = data.mvs;
|
||||
});
|
||||
},
|
||||
likeMV() {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
return;
|
||||
}
|
||||
likeAMV({
|
||||
mvid: this.mv.data.id,
|
||||
t: this.mv.subed ? 0 : 1,
|
||||
}).then((data) => {
|
||||
if (data.code === 200) this.mv.subed = !this.mv.subed;
|
||||
});
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
let videoOptions = {
|
||||
settings: ["quality"],
|
||||
settings: ['quality'],
|
||||
autoplay: false,
|
||||
quality: {
|
||||
default: 1080,
|
||||
options: [1080, 720, 480, 240],
|
||||
},
|
||||
};
|
||||
if (this.$route.query.autoplay === "true") videoOptions.autoplay = true;
|
||||
if (this.$route.query.autoplay === 'true') videoOptions.autoplay = true;
|
||||
this.player = new Plyr(this.$refs.videoPlayer, videoOptions);
|
||||
this.player.volume = this.$store.state.player.volume;
|
||||
this.player.on("playing", () => {
|
||||
this.player.on('playing', () => {
|
||||
this.$store.state.player.pause();
|
||||
});
|
||||
this.getData(this.$route.params.id);
|
||||
console.log("网易云你这mv音频码率也太糊了吧🙄");
|
||||
console.log('网易云你这mv音频码率也太糊了吧🙄');
|
||||
},
|
||||
methods: {
|
||||
...mapActions(['showToast']),
|
||||
getData(id) {
|
||||
mvDetail(id).then(data => {
|
||||
this.mv = data;
|
||||
let requests = data.data.brs.map(br => {
|
||||
return mvUrl({ id, r: br.br });
|
||||
});
|
||||
Promise.all(requests).then(results => {
|
||||
let sources = results.map(result => {
|
||||
return {
|
||||
src: result.data.url.replace(/^http:/, 'https:'),
|
||||
type: 'video/mp4',
|
||||
size: result.data.r,
|
||||
};
|
||||
});
|
||||
this.player.source = {
|
||||
type: 'video',
|
||||
title: this.mv.data.name,
|
||||
sources: sources,
|
||||
poster: this.mv.data.cover.replace(/^http:/, 'https:'),
|
||||
};
|
||||
NProgress.done();
|
||||
});
|
||||
});
|
||||
simiMv(id).then(data => {
|
||||
this.simiMvs = data.mvs;
|
||||
});
|
||||
},
|
||||
likeMV() {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
likeAMV({
|
||||
mvid: this.mv.data.id,
|
||||
t: this.mv.subed ? 0 : 1,
|
||||
}).then(data => {
|
||||
if (data.code === 200) this.mv.subed = !this.mv.subed;
|
||||
});
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
this.getData(to.params.id);
|
||||
next();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
<template>
|
||||
<div class="newAlbum">
|
||||
<h1>{{ $t("home.newAlbum") }}</h1>
|
||||
<h1>{{ $t('home.newAlbum') }}</h1>
|
||||
<div class="playlist-row">
|
||||
<div class="playlists">
|
||||
<CoverRow
|
||||
type="album"
|
||||
:items="albums"
|
||||
subText="artist"
|
||||
sub-text="artist"
|
||||
:show-play-button="true"
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -15,25 +15,25 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { newAlbums } from "@/api/album";
|
||||
import NProgress from "nprogress";
|
||||
import { newAlbums } from '@/api/album';
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
CoverRow,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
albums: [],
|
||||
};
|
||||
},
|
||||
components: {
|
||||
CoverRow,
|
||||
},
|
||||
created() {
|
||||
newAlbums({
|
||||
area: "EA",
|
||||
area: 'EA',
|
||||
limit: 100,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
this.albums = data.albums;
|
||||
NProgress.done();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,37 +1,37 @@
|
|||
<template>
|
||||
<div class="next-tracks">
|
||||
<h1>{{ $t("next.nowPlaying") }}</h1>
|
||||
<h1>{{ $t('next.nowPlaying') }}</h1>
|
||||
<TrackList
|
||||
:tracks="[currentTrack]"
|
||||
type="playlist"
|
||||
dbclickTrackFunc="none"
|
||||
dbclick-track-func="none"
|
||||
/>
|
||||
<h1 v-show="playNextList.length > 0">插队播放</h1>
|
||||
<TrackList
|
||||
v-show="playNextList.length > 0"
|
||||
:tracks="playNextTracks"
|
||||
type="playlist"
|
||||
:highlightPlayingTrack="false"
|
||||
dbclickTrackFunc="playTrackOnListByID"
|
||||
itemKey="id+index"
|
||||
v-show="playNextList.length > 0"
|
||||
:highlight-playing-track="false"
|
||||
dbclick-track-func="playTrackOnListByID"
|
||||
item-key="id+index"
|
||||
/>
|
||||
<h1>{{ $t("next.nextUp") }}</h1>
|
||||
<h1>{{ $t('next.nextUp') }}</h1>
|
||||
<TrackList
|
||||
:tracks="filteredTracks"
|
||||
type="playlist"
|
||||
:highlightPlayingTrack="false"
|
||||
dbclickTrackFunc="playTrackOnListByID"
|
||||
:highlight-playing-track="false"
|
||||
dbclick-track-func="playTrackOnListByID"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState, mapActions } from "vuex";
|
||||
import { getTrackDetail } from "@/api/track";
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import { mapState, mapActions } from 'vuex';
|
||||
import { getTrackDetail } from '@/api/track';
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
|
||||
export default {
|
||||
name: "Next",
|
||||
name: 'Next',
|
||||
components: {
|
||||
TrackList,
|
||||
},
|
||||
|
|
@ -41,7 +41,7 @@ export default {
|
|||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player"]),
|
||||
...mapState(['player']),
|
||||
currentTrack() {
|
||||
return this.player.currentTrack;
|
||||
},
|
||||
|
|
@ -53,14 +53,14 @@ export default {
|
|||
this.player.current + 1,
|
||||
this.player.current + 100
|
||||
);
|
||||
return this.tracks.filter((t) => trackIDs.includes(t.id));
|
||||
return this.tracks.filter(t => trackIDs.includes(t.id));
|
||||
},
|
||||
playNextList() {
|
||||
return this.player.playNextList;
|
||||
},
|
||||
playNextTracks() {
|
||||
return this.playNextList.map((tid) => {
|
||||
return this.tracks.find((t) => t.id === tid);
|
||||
return this.playNextList.map(tid => {
|
||||
return this.tracks.find(t => t.id === tid);
|
||||
});
|
||||
},
|
||||
},
|
||||
|
|
@ -75,8 +75,11 @@ export default {
|
|||
this.loadTracks();
|
||||
},
|
||||
},
|
||||
activated() {
|
||||
this.loadTracks();
|
||||
},
|
||||
methods: {
|
||||
...mapActions(["playTrackOnListByID"]),
|
||||
...mapActions(['playTrackOnListByID']),
|
||||
loadTracks() {
|
||||
// 获取播放列表当前歌曲后100首歌
|
||||
let trackIDs = this.player.list.slice(
|
||||
|
|
@ -88,21 +91,18 @@ export default {
|
|||
trackIDs.push(...this.playNextList);
|
||||
|
||||
// 获取已经加载了的歌曲
|
||||
let loadedTrackIDs = this.tracks.map((t) => t.id);
|
||||
let loadedTrackIDs = this.tracks.map(t => t.id);
|
||||
|
||||
if (trackIDs.length > 0) {
|
||||
getTrackDetail(trackIDs.join(",")).then((data) => {
|
||||
getTrackDetail(trackIDs.join(',')).then(data => {
|
||||
let newTracks = data.songs.filter(
|
||||
(t) => !loadedTrackIDs.includes(t.id)
|
||||
t => !loadedTrackIDs.includes(t.id)
|
||||
);
|
||||
this.tracks.push(...newTracks);
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
activated() {
|
||||
this.loadTracks();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,31 +1,30 @@
|
|||
<template>
|
||||
<div v-show="show">
|
||||
<div
|
||||
class="playlist-info"
|
||||
v-if="specialPlaylistInfo === undefined && !isLikeSongsPage"
|
||||
class="playlist-info"
|
||||
>
|
||||
<Cover
|
||||
:imageUrl="playlist.coverImgUrl | resizeImage(1024)"
|
||||
:showPlayButton="true"
|
||||
:alwaysShowShadow="true"
|
||||
:clickCoverToPlay="true"
|
||||
:fixedSize="288"
|
||||
type="playlist"
|
||||
:id="playlist.id"
|
||||
:coverHover="false"
|
||||
:playButtonSize="18"
|
||||
:image-url="playlist.coverImgUrl | resizeImage(1024)"
|
||||
:show-play-button="true"
|
||||
:always-show-shadow="true"
|
||||
:click-cover-to-play="true"
|
||||
:fixed-size="288"
|
||||
type="playlist"
|
||||
:cover-hover="false"
|
||||
:play-button-size="18"
|
||||
@click.right.native="openMenu"
|
||||
/>
|
||||
<div class="info">
|
||||
<div class="title" @click.right="openMenu"
|
||||
><span class="lock-icon" v-if="playlist.privacy === 10">
|
||||
><span v-if="playlist.privacy === 10" class="lock-icon">
|
||||
<svg-icon icon-class="lock" /></span
|
||||
>{{ playlist.name }}</div
|
||||
>
|
||||
<div class="artist">
|
||||
Playlist by
|
||||
<span
|
||||
style="font-weight: 600"
|
||||
v-if="
|
||||
[
|
||||
5277771961,
|
||||
|
|
@ -35,6 +34,7 @@
|
|||
5278068783,
|
||||
].includes(playlist.id)
|
||||
"
|
||||
style="font-weight: 600"
|
||||
>Apple Music</span
|
||||
>
|
||||
<a
|
||||
|
|
@ -45,48 +45,48 @@
|
|||
>
|
||||
</div>
|
||||
<div class="date-and-count">
|
||||
{{ $t("playlist.updatedAt") }}
|
||||
{{ $t('playlist.updatedAt') }}
|
||||
{{ playlist.updateTime | formatDate }} · {{ playlist.trackCount }}
|
||||
{{ $t("common.songs") }}
|
||||
{{ $t('common.songs') }}
|
||||
</div>
|
||||
<div class="description" @click="showFullDescription = true">
|
||||
{{ playlist.description }}
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<ButtonTwoTone @click.native="playPlaylistByID()" :iconClass="`play`">
|
||||
{{ $t("common.play") }}
|
||||
<ButtonTwoTone icon-class="play" @click.native="playPlaylistByID()">
|
||||
{{ $t('common.play') }}
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
v-if="playlist.creator.userId !== data.user.userId"
|
||||
:iconClass="playlist.subscribed ? 'heart-solid' : 'heart'"
|
||||
:iconButton="true"
|
||||
:horizontalPadding="0"
|
||||
:icon-class="playlist.subscribed ? 'heart-solid' : 'heart'"
|
||||
:icon-button="true"
|
||||
:horizontal-padding="0"
|
||||
:color="playlist.subscribed ? 'blue' : 'grey'"
|
||||
:textColor="playlist.subscribed ? '#335eea' : ''"
|
||||
:backgroundColor="
|
||||
:text-color="playlist.subscribed ? '#335eea' : ''"
|
||||
:background-color="
|
||||
playlist.subscribed ? 'var(--color-secondary-bg)' : ''
|
||||
"
|
||||
@click.native="likePlaylist"
|
||||
>
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
iconClass="more"
|
||||
:iconButton="true"
|
||||
:horizontalPadding="0"
|
||||
icon-class="more"
|
||||
:icon-button="true"
|
||||
:horizontal-padding="0"
|
||||
color="grey"
|
||||
@click.native="openMenu"
|
||||
>
|
||||
</ButtonTwoTone>
|
||||
</div>
|
||||
</div>
|
||||
<div class="search-box" v-if="displaySearchInPlaylist">
|
||||
<div v-if="displaySearchInPlaylist" class="search-box">
|
||||
<div class="container" :class="{ active: inputFocus }">
|
||||
<svg-icon icon-class="search" />
|
||||
<div class="input">
|
||||
<input
|
||||
:placeholder="inputFocus ? '' : $t('playlist.search')"
|
||||
v-model.trim="inputSearchKeyWords"
|
||||
v-focus="displaySearchInPlaylist"
|
||||
:placeholder="inputFocus ? '' : $t('playlist.search')"
|
||||
@input="inputDebounce()"
|
||||
@focus="inputFocus = true"
|
||||
@blur="inputFocus = false"
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="special-playlist" v-if="specialPlaylistInfo !== undefined">
|
||||
<div v-if="specialPlaylistInfo !== undefined" class="special-playlist">
|
||||
<div
|
||||
class="title"
|
||||
:class="specialPlaylistInfo.gradient"
|
||||
|
|
@ -111,29 +111,29 @@
|
|||
<div class="buttons">
|
||||
<ButtonTwoTone
|
||||
class="play-button"
|
||||
@click.native="playPlaylistByID()"
|
||||
iconClass="play"
|
||||
icon-class="play"
|
||||
color="grey"
|
||||
@click.native="playPlaylistByID()"
|
||||
>
|
||||
{{ $t("common.play") }}
|
||||
{{ $t('common.play') }}
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
v-if="playlist.creator.userId !== data.user.userId"
|
||||
:iconClass="playlist.subscribed ? 'heart-solid' : 'heart'"
|
||||
:iconButton="true"
|
||||
:horizontalPadding="0"
|
||||
:icon-class="playlist.subscribed ? 'heart-solid' : 'heart'"
|
||||
:icon-button="true"
|
||||
:horizontal-padding="0"
|
||||
:color="playlist.subscribed ? 'blue' : 'grey'"
|
||||
:textColor="playlist.subscribed ? '#335eea' : ''"
|
||||
:backgroundColor="
|
||||
:text-color="playlist.subscribed ? '#335eea' : ''"
|
||||
:background-color="
|
||||
playlist.subscribed ? 'var(--color-secondary-bg)' : ''
|
||||
"
|
||||
@click.native="likePlaylist"
|
||||
>
|
||||
</ButtonTwoTone>
|
||||
<ButtonTwoTone
|
||||
iconClass="more"
|
||||
:iconButton="true"
|
||||
:horizontalPadding="0"
|
||||
icon-class="more"
|
||||
:icon-button="true"
|
||||
:horizontal-padding="0"
|
||||
color="grey"
|
||||
@click.native="openMenu"
|
||||
>
|
||||
|
|
@ -141,19 +141,19 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div class="user-info" v-if="isLikeSongsPage">
|
||||
<div v-if="isLikeSongsPage" class="user-info">
|
||||
<h1>
|
||||
<img class="avatar" :src="data.user.avatarUrl | resizeImage" />{{
|
||||
data.user.nickname
|
||||
}}{{ $t("library.sLikedSongs") }}
|
||||
}}{{ $t('library.sLikedSongs') }}
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<TrackList
|
||||
:tracks="filteredTracks"
|
||||
:type="'playlist'"
|
||||
:id="playlist.id"
|
||||
:extraContextMenuItem="
|
||||
:tracks="filteredTracks"
|
||||
type="playlist"
|
||||
:extra-context-menu-item="
|
||||
isUserOwnPlaylist ? ['removeTrackFromPlaylist'] : []
|
||||
"
|
||||
/>
|
||||
|
|
@ -161,27 +161,27 @@
|
|||
<Modal
|
||||
:show="showFullDescription"
|
||||
:close="() => (showFullDescription = false)"
|
||||
:showFooter="false"
|
||||
:clickOutsideHide="true"
|
||||
:show-footer="false"
|
||||
:click-outside-hide="true"
|
||||
title="歌单介绍"
|
||||
>{{ playlist.description }}</Modal
|
||||
>
|
||||
|
||||
<ContextMenu ref="playlistMenu">
|
||||
<div class="item">{{ $t("contextMenu.playNext") }}</div>
|
||||
<div class="item">{{ $t('contextMenu.playNext') }}</div>
|
||||
<div class="item" @click="likePlaylist(true)">{{
|
||||
playlist.subscribed ? "从音乐库删除" : "保存到音乐库"
|
||||
playlist.subscribed ? '从音乐库删除' : '保存到音乐库'
|
||||
}}</div>
|
||||
<div class="item" @click="searchInPlaylist()">歌单内搜索</div>
|
||||
<div
|
||||
class="item"
|
||||
v-if="playlist.creator.userId === data.user.userId"
|
||||
class="item"
|
||||
@click="editPlaylist"
|
||||
>编辑歌单信息</div
|
||||
>
|
||||
<div
|
||||
class="item"
|
||||
v-if="playlist.creator.userId === data.user.userId"
|
||||
class="item"
|
||||
@click="deletePlaylist"
|
||||
>删除歌单</div
|
||||
>
|
||||
|
|
@ -190,112 +190,112 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapMutations, mapActions, mapState } from "vuex";
|
||||
import NProgress from "nprogress";
|
||||
import { mapMutations, mapActions, mapState } from 'vuex';
|
||||
import NProgress from 'nprogress';
|
||||
import {
|
||||
getPlaylistDetail,
|
||||
subscribePlaylist,
|
||||
deletePlaylist,
|
||||
} from "@/api/playlist";
|
||||
import { getTrackDetail } from "@/api/track";
|
||||
import { isAccountLoggedIn } from "@/utils/auth";
|
||||
import nativeAlert from "@/utils/nativeAlert";
|
||||
} from '@/api/playlist';
|
||||
import { getTrackDetail } from '@/api/track';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
import nativeAlert from '@/utils/nativeAlert';
|
||||
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import ContextMenu from "@/components/ContextMenu.vue";
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import Cover from "@/components/Cover.vue";
|
||||
import Modal from "@/components/Modal.vue";
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
import ContextMenu from '@/components/ContextMenu.vue';
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
import Cover from '@/components/Cover.vue';
|
||||
import Modal from '@/components/Modal.vue';
|
||||
|
||||
const specialPlaylist = {
|
||||
2829816518: {
|
||||
name: "欧美私人订制",
|
||||
gradient: "gradient-pink-purple-blue",
|
||||
name: '欧美私人订制',
|
||||
gradient: 'gradient-pink-purple-blue',
|
||||
},
|
||||
2890490211: {
|
||||
name: "助眠鸟鸣声",
|
||||
gradient: "gradient-green",
|
||||
name: '助眠鸟鸣声',
|
||||
gradient: 'gradient-green',
|
||||
},
|
||||
5089855855: {
|
||||
name: "夜的胡思乱想",
|
||||
gradient: "gradient-moonstone-blue",
|
||||
name: '夜的胡思乱想',
|
||||
gradient: 'gradient-moonstone-blue',
|
||||
},
|
||||
2888212971: {
|
||||
name: "全球百大DJ",
|
||||
gradient: "gradient-orange-red",
|
||||
name: '全球百大DJ',
|
||||
gradient: 'gradient-orange-red',
|
||||
},
|
||||
2829733864: {
|
||||
name: "睡眠伴侣",
|
||||
gradient: "gradient-midnight-blue",
|
||||
name: '睡眠伴侣',
|
||||
gradient: 'gradient-midnight-blue',
|
||||
},
|
||||
2829844572: {
|
||||
name: "洗澡时听的歌",
|
||||
gradient: "gradient-yellow",
|
||||
name: '洗澡时听的歌',
|
||||
gradient: 'gradient-yellow',
|
||||
},
|
||||
2920647537: {
|
||||
name: "还是会想你",
|
||||
gradient: "gradient-dark-blue-midnight-blue",
|
||||
name: '还是会想你',
|
||||
gradient: 'gradient-dark-blue-midnight-blue',
|
||||
},
|
||||
2890501416: {
|
||||
name: "助眠白噪声",
|
||||
gradient: "gradient-sky-blue",
|
||||
name: '助眠白噪声',
|
||||
gradient: 'gradient-sky-blue',
|
||||
},
|
||||
5217150082: {
|
||||
name: "摇滚唱片行",
|
||||
gradient: "gradient-yellow-red",
|
||||
name: '摇滚唱片行',
|
||||
gradient: 'gradient-yellow-red',
|
||||
},
|
||||
2829961453: {
|
||||
name: "古风音乐大赏",
|
||||
gradient: "gradient-fog",
|
||||
name: '古风音乐大赏',
|
||||
gradient: 'gradient-fog',
|
||||
},
|
||||
4923261701: {
|
||||
name: "Trance",
|
||||
gradient: "gradient-light-red-light-blue ",
|
||||
name: 'Trance',
|
||||
gradient: 'gradient-light-red-light-blue ',
|
||||
},
|
||||
5212729721: {
|
||||
name: "欧美点唱机",
|
||||
gradient: "gradient-indigo-pink-yellow",
|
||||
name: '欧美点唱机',
|
||||
gradient: 'gradient-indigo-pink-yellow',
|
||||
},
|
||||
3103434282: {
|
||||
name: "甜蜜少女心",
|
||||
gradient: "gradient-pink",
|
||||
name: '甜蜜少女心',
|
||||
gradient: 'gradient-pink',
|
||||
},
|
||||
2829896389: {
|
||||
name: "日系私人订制",
|
||||
gradient: "gradient-yellow-pink",
|
||||
name: '日系私人订制',
|
||||
gradient: 'gradient-yellow-pink',
|
||||
},
|
||||
2829779628: {
|
||||
name: "运动随身听",
|
||||
gradient: "gradient-orange-red",
|
||||
name: '运动随身听',
|
||||
gradient: 'gradient-orange-red',
|
||||
},
|
||||
2860654884: {
|
||||
name: "独立女声精选",
|
||||
gradient: "gradient-sharp-blue",
|
||||
name: '独立女声精选',
|
||||
gradient: 'gradient-sharp-blue',
|
||||
},
|
||||
898150: {
|
||||
name: "浪漫婚礼专用",
|
||||
gradient: "gradient-pink",
|
||||
name: '浪漫婚礼专用',
|
||||
gradient: 'gradient-pink',
|
||||
},
|
||||
2638104052: {
|
||||
name: "牛奶泡泡浴",
|
||||
gradient: "gradient-fog",
|
||||
name: '牛奶泡泡浴',
|
||||
gradient: 'gradient-fog',
|
||||
},
|
||||
5317236517: {
|
||||
name: "后朋克精选",
|
||||
gradient: "gradient-pink-purple-blue",
|
||||
name: '后朋克精选',
|
||||
gradient: 'gradient-pink-purple-blue',
|
||||
},
|
||||
2821115454: {
|
||||
name: "一周原创发现",
|
||||
gradient: "gradient-blue-purple",
|
||||
name: '一周原创发现',
|
||||
gradient: 'gradient-blue-purple',
|
||||
},
|
||||
3136952023: {
|
||||
name: "私人雷达",
|
||||
gradient: "gradient-radar",
|
||||
name: '私人雷达',
|
||||
gradient: 'gradient-radar',
|
||||
},
|
||||
};
|
||||
|
||||
export default {
|
||||
name: "Playlist",
|
||||
name: 'Playlist',
|
||||
components: {
|
||||
Cover,
|
||||
ButtonTwoTone,
|
||||
|
|
@ -303,14 +303,21 @@ export default {
|
|||
Modal,
|
||||
ContextMenu,
|
||||
},
|
||||
directives: {
|
||||
focus: {
|
||||
inserted: function (el) {
|
||||
el.focus();
|
||||
},
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
show: false,
|
||||
playlist: {
|
||||
id: 0,
|
||||
coverImgUrl: "",
|
||||
coverImgUrl: '',
|
||||
creator: {
|
||||
userId: "",
|
||||
userId: '',
|
||||
},
|
||||
trackIds: [],
|
||||
},
|
||||
|
|
@ -319,26 +326,16 @@ export default {
|
|||
loadingMore: false,
|
||||
lastLoadedTrackIndex: 9,
|
||||
displaySearchInPlaylist: false,
|
||||
searchKeyWords: "", // 搜索使用的关键字
|
||||
inputSearchKeyWords: "", // 搜索框中正在输入的关键字
|
||||
searchKeyWords: '', // 搜索使用的关键字
|
||||
inputSearchKeyWords: '', // 搜索框中正在输入的关键字
|
||||
inputFocus: false,
|
||||
debounceTimeout: null,
|
||||
};
|
||||
},
|
||||
created() {
|
||||
if (this.$route.name === "likedSongs") {
|
||||
this.loadData(this.data.likedSongPlaylistID);
|
||||
} else {
|
||||
this.loadData(this.$route.params.id);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener("scroll", this.handleScroll, true);
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player", "data"]),
|
||||
...mapState(['player', 'data']),
|
||||
isLikeSongsPage() {
|
||||
return this.$route.name === "likedSongs";
|
||||
return this.$route.name === 'likedSongs';
|
||||
},
|
||||
specialPlaylistInfo() {
|
||||
return specialPlaylist[this.playlist.id];
|
||||
|
|
@ -351,7 +348,7 @@ export default {
|
|||
},
|
||||
filteredTracks() {
|
||||
return this.tracks.filter(
|
||||
(track) =>
|
||||
track =>
|
||||
(track.name &&
|
||||
track.name
|
||||
.toLowerCase()
|
||||
|
|
@ -361,7 +358,7 @@ export default {
|
|||
.toLowerCase()
|
||||
.includes(this.searchKeyWords.toLowerCase())) ||
|
||||
track.ar.find(
|
||||
(artist) =>
|
||||
artist =>
|
||||
artist.name &&
|
||||
artist.name
|
||||
.toLowerCase()
|
||||
|
|
@ -370,35 +367,45 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.$route.name === 'likedSongs') {
|
||||
this.loadData(this.data.likedSongPlaylistID);
|
||||
} else {
|
||||
this.loadData(this.$route.params.id);
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
window.removeEventListener('scroll', this.handleScroll, true);
|
||||
},
|
||||
methods: {
|
||||
...mapMutations(["appendTrackToPlayerList"]),
|
||||
...mapActions(["playFirstTrackOnList", "playTrackOnListByID", "showToast"]),
|
||||
playPlaylistByID(trackID = "first") {
|
||||
let trackIDs = this.playlist.trackIds.map((t) => t.id);
|
||||
...mapMutations(['appendTrackToPlayerList']),
|
||||
...mapActions(['playFirstTrackOnList', 'playTrackOnListByID', 'showToast']),
|
||||
playPlaylistByID(trackID = 'first') {
|
||||
let trackIDs = this.playlist.trackIds.map(t => t.id);
|
||||
this.$store.state.player.replacePlaylist(
|
||||
trackIDs,
|
||||
this.playlist.id,
|
||||
"playlist",
|
||||
'playlist',
|
||||
trackID
|
||||
);
|
||||
},
|
||||
likePlaylist(toast = false) {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
subscribePlaylist({
|
||||
id: this.playlist.id,
|
||||
t: this.playlist.subscribed ? 2 : 1,
|
||||
}).then((data) => {
|
||||
}).then(data => {
|
||||
if (data.code === 200) {
|
||||
this.playlist.subscribed = !this.playlist.subscribed;
|
||||
if (toast === true)
|
||||
this.showToast(
|
||||
this.playlist.subscribed ? "已保存到音乐库" : "已从音乐库删除"
|
||||
this.playlist.subscribed ? '已保存到音乐库' : '已从音乐库删除'
|
||||
);
|
||||
}
|
||||
getPlaylistDetail(this.id, true).then((data) => {
|
||||
getPlaylistDetail(this.id, true).then(data => {
|
||||
this.playlist = data.playlist;
|
||||
});
|
||||
});
|
||||
|
|
@ -406,7 +413,7 @@ export default {
|
|||
loadData(id, next = undefined) {
|
||||
this.id = id;
|
||||
getPlaylistDetail(this.id, true)
|
||||
.then((data) => {
|
||||
.then(data => {
|
||||
this.playlist = data.playlist;
|
||||
this.tracks = data.playlist.tracks;
|
||||
NProgress.done();
|
||||
|
|
@ -414,7 +421,7 @@ export default {
|
|||
this.show = true;
|
||||
this.lastLoadedTrackIndex = data.playlist.tracks.length - 1;
|
||||
if (this.playlist.trackCount > this.tracks.length) {
|
||||
window.addEventListener("scroll", this.handleScroll, true);
|
||||
window.addEventListener('scroll', this.handleScroll, true);
|
||||
}
|
||||
return data;
|
||||
})
|
||||
|
|
@ -433,15 +440,15 @@ export default {
|
|||
)
|
||||
return t;
|
||||
});
|
||||
trackIDs = trackIDs.map((t) => t.id);
|
||||
getTrackDetail(trackIDs.join(",")).then((data) => {
|
||||
trackIDs = trackIDs.map(t => t.id);
|
||||
getTrackDetail(trackIDs.join(',')).then(data => {
|
||||
this.tracks.push(...data.songs);
|
||||
this.lastLoadedTrackIndex += trackIDs.length;
|
||||
this.loadingMore = false;
|
||||
});
|
||||
},
|
||||
handleScroll(e) {
|
||||
let dom = document.querySelector("html");
|
||||
let dom = document.querySelector('html');
|
||||
let scrollHeight = Math.max(dom.scrollHeight, dom.scrollHeight);
|
||||
let scrollTop = e.target.scrollingElement.scrollTop;
|
||||
let clientHeight =
|
||||
|
|
@ -461,39 +468,39 @@ export default {
|
|||
},
|
||||
deletePlaylist() {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
let confirmation = confirm(`确定要删除歌单 ${this.playlist.name}?`);
|
||||
if (confirmation === true) {
|
||||
deletePlaylist(this.playlist.id).then((data) => {
|
||||
deletePlaylist(this.playlist.id).then(data => {
|
||||
if (data.code === 200) {
|
||||
nativeAlert(`已删除歌单 ${this.playlist.name}`);
|
||||
this.$router.go(-1);
|
||||
} else {
|
||||
nativeAlert("发生错误");
|
||||
nativeAlert('发生错误');
|
||||
}
|
||||
});
|
||||
}
|
||||
},
|
||||
editPlaylist() {
|
||||
nativeAlert("此功能开发中");
|
||||
nativeAlert('此功能开发中');
|
||||
},
|
||||
searchInPlaylist() {
|
||||
this.displaySearchInPlaylist = !this.displaySearchInPlaylist;
|
||||
if (this.displaySearchInPlaylist == false) {
|
||||
this.searchKeyWords = "";
|
||||
this.inputSearchKeyWords = "";
|
||||
this.searchKeyWords = '';
|
||||
this.inputSearchKeyWords = '';
|
||||
} else {
|
||||
this.loadMore(500);
|
||||
}
|
||||
},
|
||||
removeTrack(trackID) {
|
||||
if (!isAccountLoggedIn()) {
|
||||
this.showToast("此操作需要登录网易云账号");
|
||||
this.showToast('此操作需要登录网易云账号');
|
||||
return;
|
||||
}
|
||||
this.tracks = this.tracks.filter((t) => t.id !== trackID);
|
||||
this.tracks = this.tracks.filter(t => t.id !== trackID);
|
||||
},
|
||||
inputDebounce() {
|
||||
if (this.debounceTimeout) clearTimeout(this.debounceTimeout);
|
||||
|
|
@ -502,13 +509,6 @@ export default {
|
|||
}, 600);
|
||||
},
|
||||
},
|
||||
directives: {
|
||||
focus: {
|
||||
inserted: function (el) {
|
||||
el.focus();
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
@ -647,7 +647,7 @@ export default {
|
|||
background-image: linear-gradient(to left, #92fe9d 0%, #00c9ff 100%);
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
.gradient-radar {
|
||||
background-image: linear-gradient(to left, #92fe9d 0%, #00c9ff 100%);
|
||||
}
|
||||
|
|
@ -824,7 +824,7 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
[data-theme="dark"] {
|
||||
[data-theme='dark'] {
|
||||
.search-box {
|
||||
.active {
|
||||
input,
|
||||
|
|
|
|||
|
|
@ -1,83 +1,83 @@
|
|||
<template>
|
||||
<div class="search" v-show="show">
|
||||
<div class="row" v-show="artists.length > 0 || albums.length > 0">
|
||||
<div class="artists" v-show="artists.length > 0">
|
||||
<div class="section-title" v-show="artists.length > 0"
|
||||
>{{ $t("search.artist")
|
||||
<div v-show="show" class="search">
|
||||
<div v-show="artists.length > 0 || albums.length > 0" class="row">
|
||||
<div v-show="artists.length > 0" class="artists">
|
||||
<div v-show="artists.length > 0" class="section-title"
|
||||
>{{ $t('search.artist')
|
||||
}}<router-link :to="`/search/${keywords}/artists`">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link></div
|
||||
>
|
||||
<CoverRow
|
||||
type="artist"
|
||||
:columnNumber="3"
|
||||
:column-number="3"
|
||||
:items="artists.slice(0, 3)"
|
||||
gap="34px 24px"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="albums">
|
||||
<div class="section-title" v-show="albums.length > 0"
|
||||
>{{ $t("search.album")
|
||||
<div v-show="albums.length > 0" class="section-title"
|
||||
>{{ $t('search.album')
|
||||
}}<router-link :to="`/search/${keywords}/albums`">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link></div
|
||||
>
|
||||
<CoverRow
|
||||
type="album"
|
||||
:items="albums.slice(0, 3)"
|
||||
subText="artist"
|
||||
:columnNumber="3"
|
||||
subTextFontSize="14px"
|
||||
sub-text="artist"
|
||||
:column-number="3"
|
||||
sub-text-font-size="14px"
|
||||
gap="34px 24px"
|
||||
:playButtonSize="26"
|
||||
:play-button-size="26"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="tracks" v-show="tracks.length > 0">
|
||||
<div v-show="tracks.length > 0" class="tracks">
|
||||
<div class="section-title"
|
||||
>{{ $t("search.song")
|
||||
>{{ $t('search.song')
|
||||
}}<router-link :to="`/search/${keywords}/tracks`">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link></div
|
||||
>
|
||||
<TrackList :tracks="tracks" type="tracklist" />
|
||||
</div>
|
||||
|
||||
<div class="music-videos" v-show="musicVideos.length > 0">
|
||||
<div v-show="musicVideos.length > 0" class="music-videos">
|
||||
<div class="section-title"
|
||||
>{{ $t("search.mv")
|
||||
>{{ $t('search.mv')
|
||||
}}<router-link :to="`/search/${keywords}/music-videos`">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link></div
|
||||
>
|
||||
<MvRow :mvs="musicVideos.slice(0, 5)" />
|
||||
</div>
|
||||
|
||||
<div class="playlists" v-show="playlists.length > 0">
|
||||
<div v-show="playlists.length > 0" class="playlists">
|
||||
<div class="section-title"
|
||||
>{{ $t("search.playlist")
|
||||
>{{ $t('search.playlist')
|
||||
}}<router-link :to="`/search/${keywords}/playlists`">{{
|
||||
$t("home.seeMore")
|
||||
$t('home.seeMore')
|
||||
}}</router-link></div
|
||||
>
|
||||
<CoverRow
|
||||
type="playlist"
|
||||
:items="playlists.slice(0, 12)"
|
||||
subText="title"
|
||||
:columnNumber="6"
|
||||
subTextFontSize="14px"
|
||||
sub-text="title"
|
||||
:column-number="6"
|
||||
sub-text-font-size="14px"
|
||||
gap="34px 24px"
|
||||
:playButtonSize="26"
|
||||
:play-button-size="26"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="no-results" v-show="!haveResult">
|
||||
<div v-show="!haveResult" class="no-results">
|
||||
<div
|
||||
><svg-icon icon-class="search" />
|
||||
{{
|
||||
keywords.length === 0 ? "输入关键字搜索" : $t("search.noResult")
|
||||
keywords.length === 0 ? '输入关键字搜索' : $t('search.noResult')
|
||||
}}</div
|
||||
>
|
||||
</div>
|
||||
|
|
@ -85,16 +85,16 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { getTrackDetail } from "@/api/track";
|
||||
import { search } from "@/api/others";
|
||||
import NProgress from "nprogress";
|
||||
import { getTrackDetail } from '@/api/track';
|
||||
import { search } from '@/api/others';
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import MvRow from "@/components/MvRow.vue";
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
import MvRow from '@/components/MvRow.vue';
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
|
||||
export default {
|
||||
name: "Search",
|
||||
name: 'Search',
|
||||
components: {
|
||||
TrackList,
|
||||
MvRow,
|
||||
|
|
@ -112,7 +112,7 @@ export default {
|
|||
},
|
||||
computed: {
|
||||
keywords() {
|
||||
return this.$route.params.keywords ?? "";
|
||||
return this.$route.params.keywords ?? '';
|
||||
},
|
||||
haveResult() {
|
||||
return (
|
||||
|
|
@ -125,12 +125,21 @@ export default {
|
|||
);
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
keywords: function (newKeywords) {
|
||||
if (newKeywords.length === 0) return;
|
||||
this.getData();
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getData();
|
||||
},
|
||||
methods: {
|
||||
playTrackInSearchResult(id) {
|
||||
let track = this.tracks.find((t) => t.id === id);
|
||||
let track = this.tracks.find(t => t.id === id);
|
||||
this.$store.state.player.appendTrackToPlayerList(track, true);
|
||||
},
|
||||
search(type = "all") {
|
||||
search(type = 'all') {
|
||||
const typeTable = {
|
||||
all: 1018,
|
||||
musicVideos: 1004,
|
||||
|
|
@ -143,7 +152,7 @@ export default {
|
|||
keywords: this.keywords,
|
||||
type: typeTable[type],
|
||||
limit: 16,
|
||||
}).then((result) => {
|
||||
}).then(result => {
|
||||
return { result: result.result, type };
|
||||
});
|
||||
},
|
||||
|
|
@ -151,32 +160,32 @@ export default {
|
|||
NProgress.start();
|
||||
this.show = false;
|
||||
|
||||
const requestAll = (requests) => {
|
||||
const requestAll = requests => {
|
||||
const keywords = this.keywords;
|
||||
Promise.all(requests).then((results) => {
|
||||
Promise.all(requests).then(results => {
|
||||
if (keywords != this.keywords) return;
|
||||
results.map((result) => {
|
||||
results.map(result => {
|
||||
const searchType = result.type;
|
||||
if (result.result === undefined) return;
|
||||
result = result.result;
|
||||
switch (searchType) {
|
||||
case "all":
|
||||
case 'all':
|
||||
this.result = result;
|
||||
break;
|
||||
case "musicVideos":
|
||||
case 'musicVideos':
|
||||
this.musicVideos = result.mvs ?? [];
|
||||
break;
|
||||
case "artists":
|
||||
case 'artists':
|
||||
this.artists = result.artists ?? [];
|
||||
break;
|
||||
case "albums":
|
||||
case 'albums':
|
||||
this.albums = result.albums ?? [];
|
||||
break;
|
||||
case "tracks":
|
||||
case 'tracks':
|
||||
this.tracks = result.songs ?? [];
|
||||
this.getTracksDetail();
|
||||
break;
|
||||
case "playlists":
|
||||
case 'playlists':
|
||||
this.playlists = result.playlists ?? [];
|
||||
break;
|
||||
}
|
||||
|
|
@ -187,32 +196,23 @@ export default {
|
|||
};
|
||||
|
||||
const requests = [
|
||||
this.search("artists"),
|
||||
this.search("albums"),
|
||||
this.search("tracks"),
|
||||
this.search('artists'),
|
||||
this.search('albums'),
|
||||
this.search('tracks'),
|
||||
];
|
||||
const requests2 = [this.search("musicVideos"), this.search("playlists")];
|
||||
const requests2 = [this.search('musicVideos'), this.search('playlists')];
|
||||
|
||||
requestAll(requests);
|
||||
requestAll(requests2);
|
||||
},
|
||||
getTracksDetail() {
|
||||
const trackIDs = this.tracks.map((t) => t.id);
|
||||
const trackIDs = this.tracks.map(t => t.id);
|
||||
if (trackIDs.length === 0) return;
|
||||
getTrackDetail(trackIDs.join(",")).then((result) => {
|
||||
getTrackDetail(trackIDs.join(',')).then(result => {
|
||||
this.tracks = result.songs;
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.getData();
|
||||
},
|
||||
watch: {
|
||||
keywords: function (newKeywords) {
|
||||
if (newKeywords.length === 0) return;
|
||||
this.getData();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -1,57 +1,57 @@
|
|||
<template>
|
||||
<div class="search" v-show="show">
|
||||
<div v-show="show" class="search">
|
||||
<h1>
|
||||
<span>{{ $t("search.searchFor") }}{{ typeNameTable[type] }}</span> "{{
|
||||
<span>{{ $t('search.searchFor') }}{{ typeNameTable[type] }}</span> "{{
|
||||
keywords
|
||||
}}"
|
||||
</h1>
|
||||
|
||||
<div v-if="type === 'artists'">
|
||||
<CoverRow type="artist" :items="result" :columnNumber="6" />
|
||||
<CoverRow type="artist" :items="result" :column-number="6" />
|
||||
</div>
|
||||
<div v-if="type === 'albums'">
|
||||
<CoverRow
|
||||
type="album"
|
||||
:items="result"
|
||||
subText="artist"
|
||||
subTextFontSize="14px"
|
||||
sub-text="artist"
|
||||
sub-text-font-size="14px"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="type === 'tracks'">
|
||||
<TrackList
|
||||
:tracks="result"
|
||||
type="playlist"
|
||||
dbclickTrackFunc="playAList"
|
||||
dbclick-track-func="playAList"
|
||||
/>
|
||||
</div>
|
||||
<div v-if="type === 'musicVideos'">
|
||||
<MvRow :mvs="result" />
|
||||
</div>
|
||||
<div v-if="type === 'playlists'">
|
||||
<CoverRow type="playlist" :items="result" subText="title" />
|
||||
<CoverRow type="playlist" :items="result" sub-text="title" />
|
||||
</div>
|
||||
|
||||
<div class="load-more">
|
||||
<ButtonTwoTone v-show="hasMore" @click.native="fetchData" color="grey">{{
|
||||
$t("explore.loadMore")
|
||||
<ButtonTwoTone v-show="hasMore" color="grey" @click.native="fetchData">{{
|
||||
$t('explore.loadMore')
|
||||
}}</ButtonTwoTone>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getTrackDetail } from "@/api/track";
|
||||
import { search } from "@/api/others";
|
||||
import { camelCase } from "change-case";
|
||||
import NProgress from "nprogress";
|
||||
import { getTrackDetail } from '@/api/track';
|
||||
import { search } from '@/api/others';
|
||||
import { camelCase } from 'change-case';
|
||||
import NProgress from 'nprogress';
|
||||
|
||||
import TrackList from "@/components/TrackList.vue";
|
||||
import MvRow from "@/components/MvRow.vue";
|
||||
import CoverRow from "@/components/CoverRow.vue";
|
||||
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
|
||||
import TrackList from '@/components/TrackList.vue';
|
||||
import MvRow from '@/components/MvRow.vue';
|
||||
import CoverRow from '@/components/CoverRow.vue';
|
||||
import ButtonTwoTone from '@/components/ButtonTwoTone.vue';
|
||||
|
||||
export default {
|
||||
name: "Search",
|
||||
name: 'Search',
|
||||
components: {
|
||||
TrackList,
|
||||
MvRow,
|
||||
|
|
@ -70,14 +70,17 @@ export default {
|
|||
},
|
||||
typeNameTable() {
|
||||
return {
|
||||
musicVideos: "MV",
|
||||
tracks: "歌曲",
|
||||
albums: "专辑",
|
||||
artists: "艺人",
|
||||
playlists: "歌单",
|
||||
musicVideos: 'MV',
|
||||
tracks: '歌曲',
|
||||
albums: '专辑',
|
||||
artists: '艺人',
|
||||
playlists: '歌单',
|
||||
};
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchData();
|
||||
},
|
||||
methods: {
|
||||
fetchData() {
|
||||
const typeTable = {
|
||||
|
|
@ -91,30 +94,30 @@ export default {
|
|||
keywords: this.keywords,
|
||||
type: typeTable[this.type],
|
||||
offset: this.result.length,
|
||||
}).then((result) => {
|
||||
}).then(result => {
|
||||
result = result.result;
|
||||
this.hasMore = result.hasMore ?? true;
|
||||
switch (this.type) {
|
||||
case "musicVideos":
|
||||
case 'musicVideos':
|
||||
this.result.push(...result.mvs);
|
||||
if (result.mvCount <= this.result.length) {
|
||||
this.hasMore = false;
|
||||
}
|
||||
break;
|
||||
case "artists":
|
||||
case 'artists':
|
||||
this.result.push(...result.artists);
|
||||
break;
|
||||
case "albums":
|
||||
case 'albums':
|
||||
this.result.push(...result.albums);
|
||||
if (result.albumCount <= this.result.length) {
|
||||
this.hasMore = false;
|
||||
}
|
||||
break;
|
||||
case "tracks":
|
||||
case 'tracks':
|
||||
this.result.push(...result.songs);
|
||||
this.getTracksDetail();
|
||||
break;
|
||||
case "playlists":
|
||||
case 'playlists':
|
||||
this.result.push(...result.playlists);
|
||||
break;
|
||||
}
|
||||
|
|
@ -123,16 +126,13 @@ export default {
|
|||
});
|
||||
},
|
||||
getTracksDetail() {
|
||||
const trackIDs = this.result.map((t) => t.id);
|
||||
const trackIDs = this.result.map(t => t.id);
|
||||
if (trackIDs.length === 0) return;
|
||||
getTrackDetail(trackIDs.join(",")).then((result) => {
|
||||
getTrackDetail(trackIDs.join(',')).then(result => {
|
||||
this.result = result.songs;
|
||||
});
|
||||
},
|
||||
},
|
||||
created() {
|
||||
this.fetchData();
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
|
|
|
|||
|
|
@ -21,14 +21,14 @@
|
|||
<div class="right">
|
||||
<button @click="logout">
|
||||
<svg-icon icon-class="logout" />
|
||||
{{ $t("settings.logout") }}
|
||||
{{ $t('settings.logout') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<h2>{{ $t("settings.settings") }}</h2>
|
||||
<h2>{{ $t('settings.settings') }}</h2>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.language") }} </div>
|
||||
<div class="title"> {{ $t('settings.language') }} </div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<select v-model="lang">
|
||||
|
|
@ -40,44 +40,44 @@
|
|||
</div>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.appearance.text") }} </div>
|
||||
<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="auto">{{ $t('settings.appearance.auto') }}</option>
|
||||
<option value="light"
|
||||
>🌞 {{ $t("settings.appearance.light") }}</option
|
||||
>🌞 {{ $t('settings.appearance.light') }}</option
|
||||
>
|
||||
<option value="dark"
|
||||
>🌚 {{ $t("settings.appearance.dark") }}</option
|
||||
>🌚 {{ $t('settings.appearance.dark') }}</option
|
||||
>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.musicQuality.text") }} </div>
|
||||
<div class="title"> {{ $t('settings.musicQuality.text') }} </div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<select v-model="musicQuality">
|
||||
<option value="128000">
|
||||
{{ $t("settings.musicQuality.low") }} - 128Kbps
|
||||
{{ $t('settings.musicQuality.low') }} - 128Kbps
|
||||
</option>
|
||||
<option value="192000">
|
||||
{{ $t("settings.musicQuality.medium") }} - 192Kbps
|
||||
{{ $t('settings.musicQuality.medium') }} - 192Kbps
|
||||
</option>
|
||||
<option value="320000">
|
||||
{{ $t("settings.musicQuality.high") }} - 320Kbps
|
||||
{{ $t('settings.musicQuality.high') }} - 320Kbps
|
||||
</option>
|
||||
<option value="999000">
|
||||
{{ $t("settings.musicQuality.lossless") }} - FLAC
|
||||
{{ $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 class="title"> {{ $t('settings.deviceSelector') }} </div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<select v-model="outputDevice" :disabled="withoutAudioPrivilege">
|
||||
|
|
@ -95,7 +95,7 @@
|
|||
<div v-if="isElectron" class="item">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{ $t("settings.automaticallyCacheSongs") }}
|
||||
{{ $t('settings.automaticallyCacheSongs') }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
|
|
@ -112,12 +112,12 @@
|
|||
</div>
|
||||
<div v-if="isElectron" class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.cacheLimit.text") }} </div>
|
||||
<div class="title"> {{ $t('settings.cacheLimit.text') }} </div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<select v-model="cacheLimit">
|
||||
<option :value="false">
|
||||
{{ $t("settings.cacheLimit.none") }}
|
||||
{{ $t('settings.cacheLimit.none') }}
|
||||
</option>
|
||||
<option :value="512"> 500MB </option>
|
||||
<option :value="1024"> 1GB </option>
|
||||
|
|
@ -130,7 +130,7 @@
|
|||
<div class="left">
|
||||
<div class="title">
|
||||
{{
|
||||
$t("settings.cacheCount", {
|
||||
$t('settings.cacheCount', {
|
||||
song: tracksCache.length,
|
||||
size: tracksCache.size,
|
||||
})
|
||||
|
|
@ -139,13 +139,13 @@
|
|||
</div>
|
||||
<div class="right">
|
||||
<button @click="clearCache()">
|
||||
{{ $t("settings.clearSongsCache") }}
|
||||
{{ $t('settings.clearSongsCache') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title">{{ $t("settings.showLyricsTranslation") }}</div>
|
||||
<div class="title">{{ $t('settings.showLyricsTranslation') }}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="toggle">
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title">{{
|
||||
$t("settings.showLyricsDynamicBackground")
|
||||
$t('settings.showLyricsDynamicBackground')
|
||||
}}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
|
|
@ -179,28 +179,28 @@
|
|||
</div>
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.lyricFontSize.text") }} </div>
|
||||
<div class="title"> {{ $t('settings.lyricFontSize.text') }} </div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<select v-model="lyricFontSize">
|
||||
<option value="16">
|
||||
{{ $t("settings.lyricFontSize.small") }} - 16px
|
||||
{{ $t('settings.lyricFontSize.small') }} - 16px
|
||||
</option>
|
||||
<option value="22">
|
||||
{{ $t("settings.lyricFontSize.medium") }} - 22px
|
||||
{{ $t('settings.lyricFontSize.medium') }} - 22px
|
||||
</option>
|
||||
<option value="28">
|
||||
{{ $t("settings.lyricFontSize.large") }} - 28px
|
||||
{{ $t('settings.lyricFontSize.large') }} - 28px
|
||||
</option>
|
||||
<option value="36">
|
||||
{{ $t("settings.lyricFontSize.xlarge") }} - 36px
|
||||
{{ $t('settings.lyricFontSize.xlarge') }} - 36px
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="isElectron && !isMac" class="item">
|
||||
<div class="left">
|
||||
<div class="title">{{ $t("settings.minimizeToTray") }}</div>
|
||||
<div class="title">{{ $t('settings.minimizeToTray') }}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="toggle">
|
||||
|
|
@ -221,7 +221,7 @@
|
|||
{{
|
||||
isLastfmConnected
|
||||
? `已连接到 Last.fm (${lastfm.name})`
|
||||
: "连接 Last.fm "
|
||||
: '连接 Last.fm '
|
||||
}}</div
|
||||
>
|
||||
</div>
|
||||
|
|
@ -235,7 +235,7 @@
|
|||
|
||||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.showLibraryDefault") }}</div>
|
||||
<div class="title"> {{ $t('settings.showLibraryDefault') }}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="toggle">
|
||||
|
|
@ -277,7 +277,7 @@
|
|||
<div class="item">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{ $t("settings.showPlaylistsByAppleMusic") }}</div
|
||||
{{ $t('settings.showPlaylistsByAppleMusic') }}</div
|
||||
>
|
||||
</div>
|
||||
<div class="right">
|
||||
|
|
@ -295,7 +295,7 @@
|
|||
<div v-if="isElectron" class="item">
|
||||
<div class="left">
|
||||
<div class="title">
|
||||
{{ $t("settings.enableDiscordRichPresence") }}</div
|
||||
{{ $t('settings.enableDiscordRichPresence') }}</div
|
||||
>
|
||||
</div>
|
||||
<div class="right">
|
||||
|
|
@ -312,7 +312,7 @@
|
|||
</div>
|
||||
<div v-if="isElectron" class="item">
|
||||
<div class="left">
|
||||
<div class="title"> {{ $t("settings.enableGlobalShortcut") }}</div>
|
||||
<div class="title"> {{ $t('settings.enableGlobalShortcut') }}</div>
|
||||
</div>
|
||||
<div class="right">
|
||||
<div class="toggle">
|
||||
|
|
@ -355,32 +355,32 @@
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import { mapState } 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";
|
||||
import { mapState } 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';
|
||||
|
||||
export default {
|
||||
name: "Settings",
|
||||
name: 'Settings',
|
||||
data() {
|
||||
return {
|
||||
tracksCache: {
|
||||
size: "0KB",
|
||||
size: '0KB',
|
||||
length: 0,
|
||||
},
|
||||
allOutputDevices: [
|
||||
{
|
||||
deviceId: "default",
|
||||
label: "settings.permissionRequired",
|
||||
deviceId: 'default',
|
||||
label: 'settings.permissionRequired',
|
||||
},
|
||||
],
|
||||
withoutAudioPrivilege: true,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
...mapState(["player", "settings", "data", "lastfm"]),
|
||||
...mapState(['player', 'settings', 'data', 'lastfm']),
|
||||
isElectron() {
|
||||
return process.env.IS_ELECTRON;
|
||||
},
|
||||
|
|
@ -400,17 +400,17 @@ export default {
|
|||
},
|
||||
set(lang) {
|
||||
this.$i18n.locale = lang;
|
||||
this.$store.commit("changeLang", lang);
|
||||
this.$store.commit('changeLang', lang);
|
||||
},
|
||||
},
|
||||
appearance: {
|
||||
get() {
|
||||
if (this.settings.appearance === undefined) return "auto";
|
||||
if (this.settings.appearance === undefined) return 'auto';
|
||||
return this.settings.appearance;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "appearance",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'appearance',
|
||||
value,
|
||||
});
|
||||
changeAppearance(value);
|
||||
|
|
@ -423,7 +423,7 @@ export default {
|
|||
},
|
||||
set(value) {
|
||||
if (value === this.settings.musicQuality) return;
|
||||
this.$store.commit("changeMusicQuality", value);
|
||||
this.$store.commit('changeMusicQuality', value);
|
||||
this.clearCache();
|
||||
},
|
||||
},
|
||||
|
|
@ -433,26 +433,26 @@ export default {
|
|||
return this.settings.lyricFontSize;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("changeLyricFontSize", value);
|
||||
this.$store.commit('changeLyricFontSize', value);
|
||||
},
|
||||
},
|
||||
outputDevice: {
|
||||
get() {
|
||||
if (this.withoutAudioPrivilege === true) this.getAllOutputDevices();
|
||||
const isValidDevice = this.allOutputDevices.find(
|
||||
(device) => device.deviceId === this.settings.outputDevice
|
||||
device => device.deviceId === this.settings.outputDevice
|
||||
);
|
||||
if (
|
||||
this.settings.outputDevice === undefined ||
|
||||
isValidDevice === undefined
|
||||
)
|
||||
return "default"; // Default deviceId
|
||||
return 'default'; // Default deviceId
|
||||
return this.settings.outputDevice;
|
||||
},
|
||||
set(deviceId) {
|
||||
if (deviceId === this.settings.outputDevice || deviceId === undefined)
|
||||
return;
|
||||
this.$store.commit("changeOutputDevice", deviceId);
|
||||
this.$store.commit('changeOutputDevice', deviceId);
|
||||
this.player.setOutputDevice();
|
||||
},
|
||||
},
|
||||
|
|
@ -461,8 +461,8 @@ export default {
|
|||
return this.settings.enableUnblockNeteaseMusic || true;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "enableUnblockNeteaseMusic",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'enableUnblockNeteaseMusic',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -473,8 +473,8 @@ export default {
|
|||
return this.settings.showPlaylistsByAppleMusic;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "showPlaylistsByAppleMusic",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'showPlaylistsByAppleMusic',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -485,8 +485,8 @@ export default {
|
|||
return this.settings.nyancatStyle;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "nyancatStyle",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'nyancatStyle',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -497,8 +497,8 @@ export default {
|
|||
return this.settings.automaticallyCacheSongs;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "automaticallyCacheSongs",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'automaticallyCacheSongs',
|
||||
value,
|
||||
});
|
||||
if (value === false) {
|
||||
|
|
@ -511,8 +511,8 @@ export default {
|
|||
return this.settings.showLyricsTranslation;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "showLyricsTranslation",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'showLyricsTranslation',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -522,8 +522,8 @@ export default {
|
|||
return this.settings.showLyricsDynamicBackground;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "showLyricsDynamicBackground",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'showLyricsDynamicBackground',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -533,8 +533,8 @@ export default {
|
|||
return this.settings.minimizeToTray;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "minimizeToTray",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'minimizeToTray',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -544,8 +544,8 @@ export default {
|
|||
return this.settings.enableDiscordRichPresence;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "enableDiscordRichPresence",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'enableDiscordRichPresence',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -555,8 +555,8 @@ export default {
|
|||
return this.settings.enableGlobalShortcut;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "enableGlobalShortcut",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'enableGlobalShortcut',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -566,8 +566,8 @@ export default {
|
|||
return this.settings.showLibraryDefault || false;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "showLibraryDefault",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'showLibraryDefault',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -577,8 +577,8 @@ export default {
|
|||
return this.settings.cacheLimit || false;
|
||||
},
|
||||
set(value) {
|
||||
this.$store.commit("updateSettings", {
|
||||
key: "cacheLimit",
|
||||
this.$store.commit('updateSettings', {
|
||||
key: 'cacheLimit',
|
||||
value,
|
||||
});
|
||||
},
|
||||
|
|
@ -588,27 +588,27 @@ export default {
|
|||
},
|
||||
},
|
||||
created() {
|
||||
this.countDBSize("tracks");
|
||||
this.countDBSize('tracks');
|
||||
},
|
||||
activated() {
|
||||
this.countDBSize("tracks");
|
||||
this.countDBSize('tracks');
|
||||
},
|
||||
methods: {
|
||||
getAllOutputDevices() {
|
||||
navigator.mediaDevices.enumerateDevices().then((devices) => {
|
||||
this.allOutputDevices = devices.filter((device) => {
|
||||
return device.kind == "audiooutput";
|
||||
navigator.mediaDevices.enumerateDevices().then(devices => {
|
||||
this.allOutputDevices = devices.filter(device => {
|
||||
return device.kind == 'audiooutput';
|
||||
});
|
||||
if (
|
||||
this.allOutputDevices.length > 0 &&
|
||||
this.allOutputDevices[0].label !== ""
|
||||
this.allOutputDevices[0].label !== ''
|
||||
) {
|
||||
this.withoutAudioPriviledge = false;
|
||||
} else {
|
||||
this.allOutputDevices = [
|
||||
{
|
||||
deviceId: "default",
|
||||
label: "settings.permissionRequired",
|
||||
deviceId: 'default',
|
||||
label: 'settings.permissionRequired',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
@ -616,13 +616,13 @@ export default {
|
|||
},
|
||||
logout() {
|
||||
doLogout();
|
||||
this.$router.push({ name: "home" });
|
||||
this.$router.push({ name: 'home' });
|
||||
},
|
||||
countDBSize() {
|
||||
countDBSize().then((data) => {
|
||||
countDBSize().then(data => {
|
||||
if (data === undefined) {
|
||||
this.tracksCache = {
|
||||
size: "0KB",
|
||||
size: '0KB',
|
||||
length: 0,
|
||||
};
|
||||
return;
|
||||
|
|
@ -639,16 +639,16 @@ export default {
|
|||
lastfmConnect() {
|
||||
lastfmAuth();
|
||||
let lastfmChecker = setInterval(() => {
|
||||
const session = localStorage.getItem("lastfm");
|
||||
const session = localStorage.getItem('lastfm');
|
||||
if (session) {
|
||||
this.$store.commit("updateLastfm", JSON.parse(session));
|
||||
this.$store.commit('updateLastfm', JSON.parse(session));
|
||||
clearInterval(lastfmChecker);
|
||||
}
|
||||
}, 1000);
|
||||
},
|
||||
lastfmDisconnect() {
|
||||
localStorage.removeItem("lastfm");
|
||||
this.$store.commit("updateLastfm", {});
|
||||
localStorage.removeItem('lastfm');
|
||||
this.$store.commit('updateLastfm', {});
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
@ -835,7 +835,7 @@ h2 {
|
|||
border-radius: 8px;
|
||||
}
|
||||
.toggle input + label:before {
|
||||
content: "";
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
-webkit-transition: 0.2s cubic-bezier(0.24, 0, 0.5, 1);
|
||||
|
|
@ -847,7 +847,7 @@ h2 {
|
|||
border-radius: 8px;
|
||||
}
|
||||
.toggle input + label:after {
|
||||
content: "";
|
||||
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),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue