mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-18 06:07:48 +00:00
chore: format codes
This commit is contained in:
parent
6922c716e2
commit
9351f6bc89
73 changed files with 2321 additions and 2321 deletions
|
|
@ -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) => {
|
||||
this.moreAlbums = data.hotAlbums;
|
||||
}
|
||||
);
|
||||
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音频码率也太糊了吧🙄');
|
||||
},
|
||||
beforeRouteUpdate(to, from, next) {
|
||||
this.getData(to.params.id);
|
||||
next();
|
||||
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;
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</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