fix: conflict

master
kunkka 4 years ago
commit 309ca88c34

@ -41,6 +41,7 @@
"extract-zip": "^2.0.1",
"howler": "^2.2.0",
"js-cookie": "^2.2.1",
"localforage": "^1.9.0",
"nprogress": "^0.2.0",
"pac-proxy-agent": "^4.1.0",
"plyr": "^3.6.2",

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

@ -166,6 +166,7 @@ button {
a {
color: inherit;
text-decoration: none;
cursor: pointer;
&:hover {
text-decoration: underline;
}

@ -61,15 +61,15 @@ export function toplistOfArtists(type = null) {
/**
* 获取歌手 mv
* 说明 : 调用此接口 , 传入歌手 id, 可获得歌手 mv 信息 , 具体 mv 播放地址可调 /mv传入此接口获得的 mvid 来拿到 , : /artist/mv?id=6452,/mv?mvid=5461064
* @param {number} id 歌手 id, 可由搜索接口获得
* @param {number} params.id 歌手 id, 可由搜索接口获得
* @param {number} params.offset
* @param {number} params.limit
*/
export function artistMv(id) {
export function artistMv(params) {
return request({
url: "/artist/mv",
method: "get",
params: {
id,
},
params,
});
}

@ -64,6 +64,7 @@ export function dailySignin(type = 0) {
method: "post",
params: {
type,
timestamp: new Date().getTime(),
},
});
}

@ -62,3 +62,40 @@
.volume-control:hover .vue-slider-process {
background-color: #335eea;
}
/* nyancat */
.nyancat .vue-slider-rail {
background-color: rgba(128, 128, 128, 0.18);
padding: 2.5px 0px;
border-radius: 0;
}
.nyancat .vue-slider-process {
padding: 0px 1px;
top: -2px;
border-radius: 0;
background: -webkit-gradient(
linear,
left top,
left bottom,
color-stop(0, #f00),
color-stop(17%, #f90),
color-stop(33%, #ff0),
color-stop(50%, #3f0),
color-stop(67%, #09f),
color-stop(83%, #63f)
);
}
.nyancat .vue-slider-dot-handle {
background: url("/img/logos/nyancat.gif");
background-size: 36px;
width: 36px;
height: 24px;
margin-top: -6px;
box-shadow: none;
border-radius: 0;
box-sizing: border-box;
visibility: visible;
}

@ -1,8 +1,9 @@
<template>
<span class="artist-in-line">
<span v-for="(ar, index) in slicedArtists" :key="ar.id">
{{ computedPrefix }}
<span v-for="(ar, index) in filteredArtists" :key="ar.id">
<router-link :to="`/artist/${ar.id}`">{{ ar.name }}</router-link>
<span v-if="index !== slicedArtists.length - 1">, </span>
<span v-if="index !== filteredArtists.length - 1">, </span>
</span>
</span>
</template>
@ -15,16 +16,22 @@ export default {
type: Array,
required: true,
},
showFirstArtist: {
type: Boolean,
default: true,
exclude: {
type: String,
default: "",
},
prefix: {
type: String,
default: "",
},
},
computed: {
slicedArtists() {
return this.showFirstArtist
? this.artists
: this.artists.slice(1, this.artists.length);
filteredArtists() {
return this.artists.filter((a) => a.name !== this.exclude);
},
computedPrefix() {
if (this.filteredArtists.length !== 0) return this.prefix;
else return "";
},
},
};

@ -1,5 +1,5 @@
<template>
<div class="context-menu">
<div class="context-menu" ref="contextMenu">
<div
class="menu"
tabindex="-1"
@ -37,6 +37,7 @@ export default {
closeMenu() {
this.showMenu = false;
this.$parent.closeMenu();
},
openMenu(e) {
@ -62,10 +63,11 @@ export default {
.menu {
position: fixed;
min-width: 136px;
max-width: 240px;
list-style: none;
background: rgba(255, 255, 255, 0.88);
box-shadow: 0 6px 12px -4px rgba(0, 0, 0, 0.08);
border: 1px solid rgba(0, 0, 0, 0.04);
border: 1px solid rgba(0, 0, 0, 0.06);
backdrop-filter: blur(12px);
border-radius: 8px;
box-sizing: border-box;
@ -77,15 +79,65 @@ export default {
}
}
[data-theme="dark"] {
.menu {
background: rgba(46, 46, 46, 0.68);
backdrop-filter: blur(16px) contrast(120%);
border: 1px solid rgba(255, 255, 255, 0.08);
}
}
.menu .item {
font-weight: 600;
font-size: 14px;
padding: 10px 14px;
border-radius: 7px;
cursor: default;
color: var(--color-text);
&:hover {
background: #eaeffd;
color: #335eea;
background: var(--color-primary-bg);
color: var(--color-primary);
}
}
hr {
margin: 4px 10px;
background: rgba(128, 128, 128, 0.18);
height: 1px;
box-shadow: none;
border: none;
}
.item-info {
padding: 10px 10px;
display: flex;
align-items: center;
color: var(--color-text);
cursor: default;
img {
height: 38px;
border-radius: 4px;
}
.info {
margin-left: 8px;
}
.title {
font-size: 16px;
font-weight: 600;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
word-break: break-all;
}
.subtitle {
font-size: 12px;
opacity: 0.68;
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
overflow: hidden;
word-break: break-all;
}
}
</style>

@ -51,9 +51,11 @@ export default {
this.$router.push({ path: "/mv/" + id, query });
},
getUrl(mv) {
if (mv.cover !== undefined) return mv.cover;
if (mv.imgurl16v9 !== undefined) return mv.imgurl16v9;
if (mv.coverUrl !== undefined) return mv.coverUrl;
if (mv.cover !== undefined) return mv.cover.replace(/^http:/, "https:");
if (mv.imgurl16v9 !== undefined)
return mv.imgurl16v9.replace(/^http:/, "https:");
if (mv.coverUrl !== undefined)
return mv.coverUrl.replace(/^http:/, "https:");
},
getID(mv) {
if (mv.id !== undefined) return mv.id;

@ -1,6 +1,6 @@
<template>
<div class="player">
<div class="progress-bar">
<div class="progress-bar" :class="{ nyancat: settings.nyancatStyle }">
<vue-slider
v-model="progress"
:min="0"

@ -1,6 +1,14 @@
<template>
<div class="track-list" :style="listStyles">
<ContextMenu ref="menu">
<div class="item-info">
<img :src="rightClickedTrack.al.picUrl | resizeImage(128)" />
<div class="info">
<div class="title">{{ rightClickedTrack.name }}</div>
<div class="subtitle">{{ rightClickedTrack.ar[0].name }}</div>
</div>
</div>
<hr />
<div class="item" @click="play">Play</div>
<div class="item" @click="playNext">Play Next</div>
<div
@ -60,10 +68,25 @@ export default {
type: String,
default: "default",
},
albumObject: {
type: Object,
default: () => {
return {
artist: {
name: "",
},
};
},
},
},
data() {
return {
rightClickedTrack: null,
rightClickedTrack: {
id: 0,
name: "",
ar: [{ name: "" }],
al: { picUrl: "" },
},
listStyles: {},
};
},
@ -90,6 +113,14 @@ export default {
this.rightClickedTrack = track;
this.$refs.menu.openMenu(e);
},
closeMenu() {
this.rightClickedTrack = {
id: 0,
name: "",
ar: [{ name: "" }],
al: { picUrl: "" },
};
},
playThisList(trackID) {
if (this.dbclickTrackFunc === "default") {
this.playThisListDefault(trackID);

@ -4,8 +4,8 @@
:class="trackClass"
:style="trackStyle"
:title="track.reason"
@mouseover="focus = true"
@mouseleave="focus = false"
@mouseover="hover = true"
@mouseleave="hover = false"
>
<img
:src="imgUrl | resizeImage(224)"
@ -34,9 +34,11 @@
<div class="container">
<div class="title">
{{ track.name }}
<span class="featured" v-if="isAlbum && track.ar.length > 1">
-
<ArtistsInLine :artists="track.ar" :showFirstArtist="false"
<span class="featured" v-if="isAlbum">
<ArtistsInLine
:artists="track.ar"
:exclude="this.$parent.albumObject.artist.name"
prefix="-"
/></span>
<span v-if="isAlbum && track.mark === 1318912" class="explicit-symbol"
><ExplicitSymbol
@ -90,7 +92,7 @@ export default {
track: Object,
},
data() {
return { focus: false, trackStyle: {} };
return { hover: false, trackStyle: {} };
},
computed: {
imgUrl() {
@ -125,11 +127,21 @@ export default {
let trackClass = [this.type];
if (!this.track.playable) trackClass.push("disable");
if (this.isPlaying) trackClass.push("playing");
if (this.focus) trackClass.push("focus");
return trackClass;
},
accountLogin() {
return isAccountLoggedIn();
},
isMenuOpened() {
return this.$parent.rightClickedTrack.id === this.track.id ? true : false;
},
focus() {
return (
(this.hover && this.$parent.rightClickedTrack.id === 0) ||
this.isMenuOpened
);
},
},
methods: {
goToAlbum() {
@ -285,11 +297,13 @@ button {
opacity: 0.88;
color: var(--color-text);
}
&:hover {
}
.track.focus {
transition: all 0.3s;
background: var(--color-secondary-bg);
}
}
.track.disable {
img {
filter: grayscale(1) opacity(0.6);

@ -91,7 +91,7 @@ export default {
artist: "Artists",
album: "Albums",
song: "Songs",
mv: "MVs",
mv: "Music Videos",
playlist: "Playlists",
noResult: "No Results",
searchFor: "Search for",

@ -3,7 +3,7 @@ export default {
nav: {
home: "首页",
explore: "发现",
library: "资料库",
library: "音乐库",
search: "搜索",
},
home: {
@ -14,7 +14,7 @@ export default {
charts: "排行榜",
},
library: {
sLibrary: "的资料库",
sLibrary: "的音乐库",
likedSongs: "我喜欢的歌",
sLikedSongs: "喜欢的歌",
},

@ -49,6 +49,14 @@ const routes = [
keepAlive: true,
},
},
{
path: "/artist/:id/mv",
name: "artistMV",
component: () => import("@/views/artistMV.vue"),
meta: {
keepAlive: true,
},
},
{
path: "/mv/:id",
name: "mv",

@ -1,13 +1,16 @@
import { updateMediaSessionMetaData } from "@/utils/mediaSession";
import { getTrackDetail, scrobble, getMP3 } from "@/api/track";
import { getTrackDetail, scrobble } from "@/api/track";
import { isAccountLoggedIn } from "@/utils/auth";
import { updateHttps } from "@/utils/common";
// import { updateHttps } from "@/utils/common";
import localforage from "localforage";
import { cacheTrack } from "@/utils/db";
export default {
switchTrack({ state, dispatch, commit }, basicTrack) {
getTrackDetail(basicTrack.id).then((data) => {
let track = data.songs[0];
track.sort = basicTrack.sort;
// 获取当前的播放时间。初始化为 loading 状态时返回 howler 的实例而不是浮点数时间,比如 1.332
let time = state.howler.seek();
let currentTime = 0;
@ -26,6 +29,7 @@ export default {
sourceid: state.player.listInfo.id,
time: currentTime,
});
commit("updateCurrentTrack", track);
updateMediaSessionMetaData(track);
document.title = `${track.name} · ${track.ar[0].name} - YesPlayMusic`;
@ -42,11 +46,16 @@ export default {
});
}
if (isAccountLoggedIn()) {
getMP3(track.id).then((data) => {
// 未知情况下会没有返回数据导致报错,增加防范逻辑
if (data.data[0]) {
const url = updateHttps(data.data[0].url);
commitMP3(url);
let tracks = localforage.createInstance({
name: "tracks",
});
tracks.getItem(`${track.id}`).then((t) => {
if (t !== null) {
commitMP3(URL.createObjectURL(t.mp3));
} else {
cacheTrack(`${track.id}`).then((t) => {
commitMP3(URL.createObjectURL(t.mp3));
});
}
});
} else {

@ -107,3 +107,89 @@ export function changeAppearance(appearance) {
.querySelector('meta[name="theme-color"]')
.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",
];
for (let keyword of keywords) {
if (title.includes(keyword) === false) continue;
return {
title: title
.replace(`(${keyword})`, "")
.replace(`: ${keyword}`, "")
.replace(`[${keyword}]`, "")
.replace(`- ${keyword}`, "")
.replace(`${keyword}`, ""),
subtitle: keyword,
};
}
return {
title: title,
subtitle: "",
};
}
export function splitAlbumTitle(title) {
let keywords = [
"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}`, ""),
subtitle: keyword,
};
}
return {
title: title,
subtitle: "",
};
}
export function bytesToSize(bytes) {
var marker = 1024; // Change to 1000 if required
var decimal = 2; // Change as required
var kiloBytes = marker;
var megaBytes = marker * marker;
var gigaBytes = marker * marker * marker;
if (bytes < kiloBytes) return bytes + " Bytes";
else if (bytes < megaBytes)
return (bytes / kiloBytes).toFixed(decimal) + " KB";
else if (bytes < gigaBytes)
return (bytes / megaBytes).toFixed(decimal) + " MB";
else return (bytes / gigaBytes).toFixed(decimal) + " GB";
}

@ -0,0 +1,57 @@
import axios from "axios";
import localforage from "localforage";
import { getMP3 } from "@/api/track";
export function cacheTrack(id) {
let tracks = localforage.createInstance({
name: "tracks",
});
// TODO: limit cache songs number
// tracks.length().then(function (length) {
// if (length > 2) {
// tracks.keys().then(function (keys) {
// tracks.removeItem(keys[keys.length - 2]);
// });
// }
// });
// TODO: cache track details
return getMP3(id).then((data) => {
return axios
.get(data.data[0].url.replace(/^http:/, "https:"), {
responseType: "blob",
})
.then((data) => {
tracks.setItem(`${id}`, { mp3: data.data });
return { mp3: data.data };
});
});
}
export function countDBSize(dbName) {
let db = localforage.createInstance({
name: dbName,
});
let trackSizes = [];
return db
.iterate((value) => {
trackSizes.push(value.mp3.size);
})
.then(() => {
return {
bytes: trackSizes.reduce((s1, s2) => s1 + s2),
length: trackSizes.length,
};
})
.catch((err) => {
console.log(err);
});
}
export function clearDB(dbName) {
let db = localforage.createInstance({
name: dbName,
});
return db.clear();
}

@ -11,9 +11,8 @@
:id="album.id"
/>
<div class="info">
<div class="title">
{{ album.name }}
</div>
<div class="title"> {{ title }}</div>
<div class="subtitle" v-if="subtitle !== ''">{{ subtitle }}</div>
<div class="artist">
<span>{{ album.type | formatAlbumType(album) }} by </span
><router-link :to="`/artist/${album.artist.id}`">{{
@ -53,7 +52,12 @@
</div>
</div>
</div>
<TrackList :tracks="tracks" :type="'album'" :id="album.id" />
<TrackList
:tracks="tracks"
:type="'album'"
:id="album.id"
:albumObject="album"
/>
<div class="extra-info">
<div class="album-time"></div>
<div class="release-date">
@ -103,6 +107,7 @@ import { getArtistAlbum } from "@/api/artist";
import { getTrackDetail } from "@/api/track";
import { playAlbumByID } from "@/utils/play";
import { getAlbum, albumDynamicDetail, likeAAlbum } from "@/api/album";
import { splitSoundtrackAlbumTitle, splitAlbumTitle } from "@/utils/common";
import NProgress from "nprogress";
import { isAccountLoggedIn } from "@/utils/auth";
@ -135,6 +140,8 @@ export default {
show: false,
moreAlbums: [],
dynamicDetail: {},
subtitle: "",
title: "",
};
},
created() {
@ -161,7 +168,11 @@ export default {
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);
} else {
return [...realAlbums, ...restItems].slice(0, 5);
}
},
},
methods: {
@ -182,10 +193,24 @@ export default {
this.dynamicDetail.isSub = !this.dynamicDetail.isSub;
});
},
formatTitle() {
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;
} else {
this.subtitle =
splitTitle.subtitle === ""
? splitTitle2.subtitle
: splitTitle.subtitle;
}
},
loadData(id) {
getAlbum(id).then((data) => {
this.album = data.album;
this.tracks = data.songs;
this.formatTitle();
NProgress.done();
this.show = true;
@ -230,8 +255,10 @@ export default {
.title {
font-size: 56px;
font-weight: 700;
display: inline-flex;
align-items: center;
}
.subtitle {
font-size: 22px;
font-weight: 600;
}
.artist {
font-size: 18px;

@ -8,9 +8,17 @@
<div class="name">{{ artist.name }}</div>
<div class="artist">{{ $t("artist.artist") }}</div>
<div class="statistics">
{{ artist.musicSize }} {{ $t("common.songs") }} ·
{{ artist.albumSize }} {{ $t("artist.withAlbums") }} ·
{{ artist.mvSize }} {{ $t("artist.videos") }}
<a @click="scrollTo('popularTracks')"
>{{ artist.musicSize }} {{ $t("common.songs") }}</a
>
·
<a @click="scrollTo('seeMore', 'start')"
>{{ artist.albumSize }} {{ $t("artist.withAlbums") }}</a
>
·
<a @click="scrollTo('mvs')"
>{{ artist.mvSize }} {{ $t("artist.videos") }}</a
>
</div>
<div class="buttons">
<ButtonTwoTone @click.native="playPopularSongs()" :iconClass="`play`">
@ -57,21 +65,21 @@
<div></div>
</div>
</div>
<div class="popular-tracks">
<div class="popular-tracks" id="popularTracks">
<div class="section-title">{{ $t("artist.popularSongs") }}</div>
<TrackList
:tracks="popularTracks.slice(0, showMorePopTracks ? 24 : 12)"
:type="'tracklist'"
/>
<div class="show-more">
<div class="show-more" id="seeMore">
<button @click="showMorePopTracks = !showMorePopTracks">
<span v-show="!showMorePopTracks">{{ $t("artist.showMore") }}</span>
<span v-show="showMorePopTracks">{{ $t("artist.showLess") }}</span>
</button>
</div>
</div>
<div class="albums" v-if="albums.length !== 0">
<div class="albums" id="albums" v-if="albums.length !== 0">
<div class="section-title">{{ $t("artist.albums") }}</div>
<CoverRow
:type="'album'"
@ -80,8 +88,13 @@
:showPlayButton="true"
/>
</div>
<div class="mvs" v-if="mvs.length !== 0">
<div class="section-title">MVs</div>
<div class="mvs" id="mvs" v-if="mvs.length !== 0">
<div class="section-title"
>MVs
<router-link v-show="hasMoreMV" :to="`/artist/${this.artist.id}/mv`">{{
$t("home.seeMore")
}}</router-link>
</div>
<MvRow :mvs="mvs" subtitle="publishTime" />
</div>
<div class="eps" v-if="eps.length !== 0">
@ -135,6 +148,7 @@ export default {
},
showMorePopTracks: false,
mvs: [],
hasMoreMV: false,
};
},
computed: {
@ -163,8 +177,9 @@ export default {
this.albumsData = data.hotAlbums;
this.latestRelease = data.hotAlbums[0];
});
artistMv(id).then((data) => {
artistMv({ id }).then((data) => {
this.mvs = data.mvs;
this.hasMoreMV = data.hasMore;
});
},
goToAlbum(id) {
@ -185,6 +200,12 @@ export default {
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);
@ -211,7 +232,7 @@ export default {
.artist-info {
display: flex;
align-items: center;
margin-bottom: 72px;
margin-bottom: 26px;
color: var(--color-text);
img {
height: 192px;
@ -255,7 +276,16 @@ export default {
opacity: 0.88;
color: var(--color-text);
margin-bottom: 16px;
margin-top: 46px;
padding-top: 46px;
display: flex;
justify-content: space-between;
align-items: flex-end;
a {
font-size: 13px;
font-weight: 600;
opacity: 0.68;
}
}
.latest-release {

@ -0,0 +1,96 @@
<template>
<div v-show="show">
<h1>
<img class="avatar" :src="artist.img1v1Url | resizeImage(1024)" />{{
artist.name
}}'s Music Videos
</h1>
<MvRow :mvs="mvs" subtitle="publishTime" />
<div class="load-more">
<ButtonTwoTone v-show="hasMore" @click.native="loadMVs" color="grey">{{
$t("explore.loadMore")
}}</ButtonTwoTone>
</div>
</div>
</template>
<script>
import { artistMv, getArtist } from "@/api/artist";
import NProgress from "nprogress";
import ButtonTwoTone from "@/components/ButtonTwoTone.vue";
import MvRow from "@/components/MvRow.vue";
export default {
name: "artistMV",
components: {
MvRow,
ButtonTwoTone,
},
data() {
return {
id: 0,
show: false,
hasMore: true,
artist: {},
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 + 1 }).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();
},
activated() {
if (this.$route.params.id !== this.id) {
this.id = this.$route.params.id;
this.mvs = [];
this.artist = {};
this.show = false;
this.hasMore = true;
this.loadData();
}
},
beforeRouteUpdate(to, from, next) {
NProgress.start();
this.id = to.params.id;
this.loadData();
next();
},
};
</script>
<style lang="scss" scoped>
h1 {
font-size: 42px;
color: var(--color-text);
.avatar {
height: 44px;
margin-right: 12px;
vertical-align: -7px;
border-radius: 50%;
border: rgba(0, 0, 0, 0.2);
}
}
.load-more {
display: flex;
justify-content: center;
}
</style>

@ -1,8 +1,8 @@
<template>
<div v-show="show">
<h1>
<img class="head" :src="user.profile.avatarUrl | resizeImage" />{{
user.profile.nickname
<img class="head" :src="data.user.avatarUrl | resizeImage" />{{
data.user.nickname
}}{{ $t("library.sLibrary") }}
</h1>
<div class="section-one">
@ -129,12 +129,6 @@ export default {
data() {
return {
show: false,
user: {
profile: {
avatarUrl: "",
nickname: "",
},
},
playlists: [],
hasMorePlaylists: true,
likedSongsPlaylist: {
@ -153,7 +147,7 @@ export default {
created() {
NProgress.start();
userDetail(this.data.user.userId).then((data) => {
this.user = data;
this.$store.commit("updateData", { key: "user", value: data.profile });
});
},
activated() {
@ -253,18 +247,24 @@ export default {
});
},
loadLikedAlbums() {
NProgress.start();
likedAlbums().then((data) => {
this.albums = data.data;
NProgress.done();
});
},
loadLikedArtists() {
NProgress.start();
likedArtists().then((data) => {
this.artists = data.data;
NProgress.done();
});
},
loadLikedMVs() {
NProgress.start();
likedMVs().then((data) => {
this.mvs = data.data;
NProgress.done();
});
},
},

@ -121,7 +121,7 @@ export default {
},
created() {
if (this.$route.name === "likedSongs") {
this.loadData(this.data.user.likedSongPlaylistID);
this.loadData(this.data.likedSongPlaylistID);
} else {
this.loadData(this.$route.params.id);
}

@ -74,6 +74,16 @@
</select>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"
>Cached {{ tracksCache.length }} songs ({{ tracksCache.size }})</div
>
</div>
<div class="right">
<button @click="clearCache('tracks')"> Clear Songs Cache </button>
</div>
</div>
<div class="item">
<div class="left">
<div class="title"> Show Github Icon </div>
@ -106,6 +116,22 @@
</div>
</div>
</div>
<div class="item">
<div class="left">
<div class="title" style="transform: scaleX(-1)">🐈 🏳🌈</div>
</div>
<div class="right">
<div class="toggle">
<input
type="checkbox"
name="nyancat-style"
id="nyancat-style"
v-model="nyancatStyle"
/>
<label for="nyancat-style"></label>
</div>
</div>
</div>
</div>
</div>
</template>
@ -113,10 +139,19 @@
<script>
import { mapState } from "vuex";
import { doLogout } from "@/utils/auth";
import { changeAppearance } from "@/utils/common";
import { changeAppearance, bytesToSize } from "@/utils/common";
import { countDBSize, clearDB } from "@/utils/db";
export default {
name: "settings",
data() {
return {
tracksCache: {
size: "0KB",
length: 0,
},
};
},
computed: {
...mapState(["settings", "data"]),
lang: {
@ -143,11 +178,13 @@ export default {
},
musicQuality: {
get() {
if (this.settings.appearance === undefined) return 320000;
if (this.settings.musicQuality === undefined) return 320000;
return this.settings.musicQuality;
},
set(value) {
if (value === this.settings.musicQuality) return;
this.$store.commit("changeMusicQuality", value);
this.clearCache("tracks");
},
},
showGithubIcon: {
@ -174,12 +211,49 @@ export default {
});
},
},
nyancatStyle: {
get() {
if (this.settings.nyancatStyle === undefined) return false;
return this.settings.nyancatStyle;
},
set(value) {
this.$store.commit("updateSettings", {
key: "nyancatStyle",
value,
});
},
},
},
methods: {
logout() {
doLogout();
this.$router.push({ name: "home" });
},
countDBSize(dbName) {
countDBSize(dbName).then((data) => {
if (data === undefined) {
this.tracksCache = {
size: "0KB",
length: 0,
};
return;
}
this.tracksCache.size = bytesToSize(data.bytes);
this.tracksCache.length = data.length;
});
},
clearCache(dbName) {
// TODO: toast
clearDB(dbName).then(() => {
this.countDBSize("tracks");
});
},
},
created() {
this.countDBSize("tracks");
},
activated() {
this.countDBSize("tracks");
},
};
</script>
@ -301,6 +375,21 @@ h2 {
background: var(--color-primary-bg);
}
}
button {
color: var(--color-text);
background: var(--color-secondary-bg);
padding: 8px 12px 8px 12px;
font-weight: 600;
border-radius: 8px;
transition: 0.2s;
&:hover {
transform: scale(1.06);
}
&:active {
transform: scale(0.94);
}
}
}
.beforeAnimation {

@ -7017,6 +7017,13 @@ localforage@1.8.1:
dependencies:
lie "3.1.1"
localforage@^1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.9.0.tgz#f3e4d32a8300b362b4634cc4e066d9d00d2f09d1"
integrity sha512-rR1oyNrKulpe+VM9cYmcFn6tsHuokyVHFaCM3+osEmxaHTbEk8oQu6eGDfS6DQLWi/N67XRmB8ECG37OES368g==
dependencies:
lie "3.1.1"
locate-path@^2.0.0:
version "2.0.0"
resolved "https://registry.npm.taobao.org/locate-path/download/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
@ -11046,7 +11053,7 @@ vue-class-component@^7.1.0:
resolved "https://registry.yarnpkg.com/vue-class-component/-/vue-class-component-7.2.6.tgz#8471e037b8e4762f5a464686e19e5afc708502e4"
integrity sha512-+eaQXVrAm/LldalI272PpDe3+i4mPis0ORiMYxF6Ae4hyuCh15W8Idet7wPUEs4N4YptgFHGys4UrgNQOMyO6w==
vue-cli-plugin-electron-builder@^2.0.0-rc.5:
vue-cli-plugin-electron-builder@~2.0.0-rc.4:
version "2.0.0-rc.5"
resolved "https://registry.npm.taobao.org/vue-cli-plugin-electron-builder/download/vue-cli-plugin-electron-builder-2.0.0-rc.5.tgz#87cd8d09877f5f3ae339abc0bedc47d7d2b733ac"
integrity sha1-h82NCYd/XzrjOavAvtxH19K3M6w=

Loading…
Cancel
Save