mirror of
https://github.com/qier222/YesPlayMusic.git
synced 2024-11-28 19:23:51 +08:00
feat: support cloud disk
This commit is contained in:
parent
996904f056
commit
571d0d71f8
|
@ -10,6 +10,7 @@ const table = {
|
|||
'/album/detail/dynamic': require('../module/album_detail_dynamic'),
|
||||
'/recommend/resource': require('../module/recommend_resource'),
|
||||
'/playlist/subscribe': require('../module/playlist_subscribe'),
|
||||
'/user/cloud/detail': require('../module/user_cloud_detail'),
|
||||
'/playlist/catlist': require('../module/playlist_catlist'),
|
||||
'/playlist/detail': require('../module/playlist_detail'),
|
||||
'/login/cellphone': require('../module/login_cellphone'),
|
||||
|
@ -17,6 +18,7 @@ const table = {
|
|||
'/playlist/create': require('../module/playlist_create'),
|
||||
'/playlist/tracks': require('../module/playlist_tracks'),
|
||||
'/recommend/songs': require('../module/recommend_songs'),
|
||||
'/user/cloud/del': require('../module/user_cloud_del'),
|
||||
'/toplist/artist': require('../module/toplist_artist'),
|
||||
'/artist/sublist': require('../module/artist_sublist'),
|
||||
'/login/refresh': require('../module/login_refresh'),
|
||||
|
|
|
@ -95,6 +95,7 @@ export default {
|
|||
this.$store.dispatch('fetchLikedAlbums');
|
||||
this.$store.dispatch('fetchLikedArtists');
|
||||
this.$store.dispatch('fetchLikedMVs');
|
||||
this.$store.dispatch('fetchCloudDisk');
|
||||
}
|
||||
},
|
||||
handleScroll() {
|
||||
|
|
|
@ -130,3 +130,69 @@ export function likedMVs() {
|
|||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传歌曲到云盘(需要登录)
|
||||
*/
|
||||
export function uploadSong(file) {
|
||||
let formData = new FormData();
|
||||
formData.append('songFile', file);
|
||||
return request({
|
||||
url: '/cloud',
|
||||
method: 'post',
|
||||
params: {
|
||||
timestamp: new Date().getTime(),
|
||||
},
|
||||
data: formData,
|
||||
headers: {
|
||||
'Content-Type': 'multipart/form-data',
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取云盘歌曲(需要登录)
|
||||
* 说明 : 登录后调用此接口 , 可获取云盘数据 , 获取的数据没有对应 url, 需要再调用一 次 /song/url 获取 url
|
||||
* - limit : 返回数量 , 默认为 200
|
||||
* - offset : 偏移数量,用于分页 , 如 :( 页数 -1)*200, 其中 200 为 limit 的值 , 默认为 0
|
||||
* @param {Object} params
|
||||
* @param {number} params.limit
|
||||
* @param {number=} params.offset
|
||||
*/
|
||||
export function cloudDisk(params = {}) {
|
||||
params.timestamp = new Date().getTime();
|
||||
return request({
|
||||
url: '/user/cloud',
|
||||
method: 'get',
|
||||
params,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取云盘歌曲详情(需要登录)
|
||||
*/
|
||||
export function cloudDiskTrackDetail(id) {
|
||||
return request({
|
||||
url: '/user/cloud/detail',
|
||||
method: 'get',
|
||||
params: {
|
||||
timestamp: new Date().getTime(),
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除云盘歌曲(需要登录)
|
||||
* @param {Array} id
|
||||
*/
|
||||
export function cloudDiskTrackDelete(id) {
|
||||
return request({
|
||||
url: '/user/cloud/del',
|
||||
method: 'get',
|
||||
params: {
|
||||
timestamp: new Date().getTime(),
|
||||
id,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
1
src/assets/icons/arrow-up-alt.svg
Normal file
1
src/assets/icons/arrow-up-alt.svg
Normal file
|
@ -0,0 +1 @@
|
|||
<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="arrow-up" class="svg-inline--fa fa-arrow-up fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M34.9 289.5l-22.2-22.2c-9.4-9.4-9.4-24.6 0-33.9L207 39c9.4-9.4 24.6-9.4 33.9 0l194.3 194.3c9.4 9.4 9.4 24.6 0 33.9L413 289.4c-9.5 9.5-25 9.3-34.3-.4L264 168.6V456c0 13.3-10.7 24-24 24h-32c-13.3 0-24-10.7-24-24V168.6L69.2 289.1c-9.3 9.8-24.8 10-34.3.4z"></path></svg>
|
After Width: | Height: | Size: 487 B |
|
@ -240,6 +240,8 @@ export default {
|
|||
this.$router.push({ path: '/library/liked-songs' });
|
||||
} else if (this.player.playlistSource.type === 'url') {
|
||||
this.$router.push({ path: this.player.playlistSource.id });
|
||||
} else if (this.player.playlistSource.type === 'cloudDisk') {
|
||||
this.$router.push({ path: '/library' });
|
||||
} else {
|
||||
this.$router.push({
|
||||
path:
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
<template>
|
||||
<div class="track-list">
|
||||
<ContextMenu ref="menu">
|
||||
<div class="item-info">
|
||||
<img :src="rightClickedTrack.al.picUrl | resizeImage(224)" />
|
||||
<div v-show="type !== 'cloudDisk'" class="item-info">
|
||||
<img :src="rightClickedTrackComputed.al.picUrl | resizeImage(224)" />
|
||||
<div class="info">
|
||||
<div class="title">{{ rightClickedTrack.name }}</div>
|
||||
<div class="subtitle">{{ rightClickedTrack.ar[0].name }}</div>
|
||||
<div class="title">{{ rightClickedTrackComputed.name }}</div>
|
||||
<div class="subtitle">{{ rightClickedTrackComputed.ar[0].name }}</div>
|
||||
</div>
|
||||
</div>
|
||||
<hr />
|
||||
<hr v-show="type !== 'cloudDisk'" />
|
||||
<div class="item" @click="play">{{ $t('contextMenu.play') }}</div>
|
||||
<div class="item" @click="addToQueue">{{
|
||||
$t('contextMenu.addToQueue')
|
||||
|
@ -19,11 +19,19 @@
|
|||
@click="removeTrackFromQueue"
|
||||
>从队列删除</div
|
||||
>
|
||||
<hr />
|
||||
<div v-show="!isRightClickedTrackLiked" class="item" @click="like">
|
||||
<hr v-show="type !== 'cloudDisk'" />
|
||||
<div
|
||||
v-show="!isRightClickedTrackLiked && type !== 'cloudDisk'"
|
||||
class="item"
|
||||
@click="like"
|
||||
>
|
||||
{{ $t('contextMenu.saveToMyLikedSongs') }}
|
||||
</div>
|
||||
<div v-show="isRightClickedTrackLiked" class="item" @click="like">
|
||||
<div
|
||||
v-show="isRightClickedTrackLiked && type !== 'cloudDisk'"
|
||||
class="item"
|
||||
@click="like"
|
||||
>
|
||||
{{ $t('contextMenu.removeFromMyLikedSongs') }}
|
||||
</div>
|
||||
<div
|
||||
|
@ -32,17 +40,27 @@
|
|||
@click="removeTrackFromPlaylist"
|
||||
>从歌单中删除</div
|
||||
>
|
||||
<div class="item" @click="addTrackToPlaylist">{{
|
||||
$t('contextMenu.addToPlaylist')
|
||||
}}</div>
|
||||
<div
|
||||
v-show="type !== 'cloudDisk'"
|
||||
class="item"
|
||||
@click="addTrackToPlaylist"
|
||||
>{{ $t('contextMenu.addToPlaylist') }}</div
|
||||
>
|
||||
<div
|
||||
v-if="extraContextMenuItem.includes('removeTrackFromCloudDisk')"
|
||||
class="item"
|
||||
@click="removeTrackFromCloudDisk"
|
||||
>从云盘中删除</div
|
||||
>
|
||||
</ContextMenu>
|
||||
|
||||
<div :style="listStyles">
|
||||
<TrackListItem
|
||||
v-for="(track, index) in tracks"
|
||||
:key="itemKey === 'id' ? track.id : `${track.id}${index}`"
|
||||
:track="track"
|
||||
:track-prop="track"
|
||||
:highlight-playing-track="highlightPlayingTrack"
|
||||
@dblclick.native="playThisList(track.id)"
|
||||
@dblclick.native="playThisList(track.id || track.songId)"
|
||||
@click.right.native="openMenu($event, track, index)"
|
||||
/>
|
||||
</div>
|
||||
|
@ -52,6 +70,7 @@
|
|||
<script>
|
||||
import { mapActions, mapMutations, mapState } from 'vuex';
|
||||
import { addOrRemoveTrackFromPlaylist } from '@/api/playlist';
|
||||
import { cloudDiskTrackDelete } from '@/api/user';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
|
||||
import TrackListItem from '@/components/TrackListItem.vue';
|
||||
|
@ -65,9 +84,20 @@ export default {
|
|||
ContextMenu,
|
||||
},
|
||||
props: {
|
||||
tracks: Array,
|
||||
type: String,
|
||||
id: Number,
|
||||
tracks: {
|
||||
type: Array,
|
||||
default: () => {
|
||||
return [];
|
||||
},
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: 'tracklist',
|
||||
}, // tracklist | album | playlist | cloudDisk
|
||||
id: {
|
||||
type: Number,
|
||||
default: 0,
|
||||
},
|
||||
dbclickTrackFunc: {
|
||||
type: String,
|
||||
default: 'default',
|
||||
|
@ -88,6 +118,7 @@ export default {
|
|||
return [
|
||||
// 'removeTrackFromPlaylist'
|
||||
// 'removeTrackFromQueue'
|
||||
// 'removeTrackFromCloudDisk'
|
||||
];
|
||||
},
|
||||
},
|
||||
|
@ -121,6 +152,16 @@ export default {
|
|||
isRightClickedTrackLiked() {
|
||||
return this.liked.songs.includes(this.rightClickedTrack?.id);
|
||||
},
|
||||
rightClickedTrackComputed() {
|
||||
return this.type === 'cloudDisk'
|
||||
? {
|
||||
id: 0,
|
||||
name: '',
|
||||
ar: [{ name: '' }],
|
||||
al: { picUrl: '' },
|
||||
}
|
||||
: this.rightClickedTrack;
|
||||
},
|
||||
},
|
||||
created() {
|
||||
if (this.type === 'tracklist') {
|
||||
|
@ -158,11 +199,14 @@ export default {
|
|||
} else if (this.dbclickTrackFunc === 'playPlaylistByID') {
|
||||
this.player.playPlaylistByID(this.id, trackID);
|
||||
} else if (this.dbclickTrackFunc === 'playAList') {
|
||||
let trackIDs = this.tracks.map(t => t.id);
|
||||
let trackIDs = this.tracks.map(t => t.id || t.songId);
|
||||
this.player.replacePlaylist(trackIDs, this.id, 'artist', trackID);
|
||||
} else if (this.dbclickTrackFunc === 'dailyTracks') {
|
||||
let trackIDs = this.tracks.map(t => t.id);
|
||||
this.player.replacePlaylist(trackIDs, '/daily/songs', 'url', trackID);
|
||||
} else if (this.dbclickTrackFunc === 'playCloudDisk') {
|
||||
let trackIDs = this.tracks.map(t => t.id || t.songId);
|
||||
this.player.replacePlaylist(trackIDs, this.id, 'cloudDisk', trackID);
|
||||
}
|
||||
},
|
||||
playThisListDefault(trackID) {
|
||||
|
@ -226,6 +270,23 @@ export default {
|
|||
this.rightClickedTrackIndex
|
||||
);
|
||||
},
|
||||
removeTrackFromCloudDisk() {
|
||||
if (confirm(`确定要从云盘删除 ${this.rightClickedTrack.songName}?`)) {
|
||||
let trackID = this.rightClickedTrack.songId;
|
||||
cloudDiskTrackDelete(trackID).then(data => {
|
||||
this.showToast(
|
||||
data.code === 200 ? '已将此歌曲从云盘删除' : data.message
|
||||
);
|
||||
let newCloudDisk = this.liked.cloudDisk.filter(
|
||||
t => t.songId !== trackID
|
||||
);
|
||||
this.$store.commit('updateLikedXXX', {
|
||||
name: 'cloudDisk',
|
||||
data: newCloudDisk,
|
||||
});
|
||||
});
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
:class="{ hover: focus }"
|
||||
@click="goToAlbum"
|
||||
/>
|
||||
<div v-if="isAlbum" class="no">
|
||||
<div v-if="showOrderNumber" class="no">
|
||||
<button v-show="focus && track.playable && !isPlaying" @click="playTrack">
|
||||
<svg-icon
|
||||
icon-class="play"
|
||||
|
@ -37,7 +37,7 @@
|
|||
<span v-if="isAlbum" class="featured">
|
||||
<ArtistsInLine
|
||||
:artists="track.ar"
|
||||
:exclude="this.$parent.albumObject.artist.name"
|
||||
:exclude="$parent.albumObject.artist.name"
|
||||
prefix="-"
|
||||
/></span>
|
||||
<span v-if="isAlbum && track.mark === 1318912" class="explicit-symbol"
|
||||
|
@ -58,11 +58,13 @@
|
|||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<div v-if="!isTracklist && !isAlbum" class="album">
|
||||
|
||||
<div v-if="showAlbumName" class="album">
|
||||
<router-link :to="`/album/${album.id}`">{{ album.name }}</router-link>
|
||||
<div></div>
|
||||
</div>
|
||||
<div v-if="!isTracklist" class="actions">
|
||||
|
||||
<div v-if="showLikeButton" class="actions">
|
||||
<button @click="likeThisSong">
|
||||
<svg-icon
|
||||
icon-class="heart"
|
||||
|
@ -73,7 +75,7 @@
|
|||
<svg-icon v-show="isLiked" icon-class="heart-solid"></svg-icon>
|
||||
</button>
|
||||
</div>
|
||||
<div v-if="!isTracklist" class="time">
|
||||
<div v-if="showTrackTime" class="time">
|
||||
{{ track.dt | formatTime }}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -87,18 +89,26 @@ import { mapState } from 'vuex';
|
|||
export default {
|
||||
name: 'TrackListItem',
|
||||
components: { ArtistsInLine, ExplicitSymbol },
|
||||
|
||||
props: {
|
||||
track: Object,
|
||||
trackProp: Object,
|
||||
highlightPlayingTrack: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
|
||||
data() {
|
||||
return { hover: false, trackStyle: {} };
|
||||
},
|
||||
|
||||
computed: {
|
||||
...mapState(['settings']),
|
||||
track() {
|
||||
return this.type === 'cloudDisk'
|
||||
? this.trackProp.simpleSong
|
||||
: this.trackProp;
|
||||
},
|
||||
imgUrl() {
|
||||
let image =
|
||||
this.track?.al?.picUrl ??
|
||||
|
@ -112,7 +122,7 @@ export default {
|
|||
return [];
|
||||
},
|
||||
album() {
|
||||
return this.track.album || this.track.al;
|
||||
return this.track.album || this.track.al || this.track?.simpleSong?.al;
|
||||
},
|
||||
translate() {
|
||||
let t;
|
||||
|
@ -134,17 +144,14 @@ export default {
|
|||
this.track.alia?.length > 0
|
||||
);
|
||||
},
|
||||
isTracklist() {
|
||||
return this.type === 'tracklist';
|
||||
},
|
||||
isPlaylist() {
|
||||
return this.type === 'playlist';
|
||||
},
|
||||
isLiked() {
|
||||
return this.$parent.liked.songs.includes(this.track.id);
|
||||
return this.$parent.liked.songs.includes(this.track?.id);
|
||||
},
|
||||
isPlaying() {
|
||||
return this.$store.state.player.currentTrack.id === this.track.id;
|
||||
return this.$store.state.player.currentTrack.id === this.track?.id;
|
||||
},
|
||||
trackClass() {
|
||||
let trackClass = [this.type];
|
||||
|
@ -169,7 +176,20 @@ export default {
|
|||
? !this.$store.state.settings.enableUnblockNeteaseMusic
|
||||
: true;
|
||||
},
|
||||
showLikeButton() {
|
||||
return this.type !== 'tracklist' && this.type !== 'cloudDisk';
|
||||
},
|
||||
showOrderNumber() {
|
||||
return this.type === 'album';
|
||||
},
|
||||
showAlbumName() {
|
||||
return this.type !== 'album' && this.type !== 'tracklist';
|
||||
},
|
||||
showTrackTime() {
|
||||
return this.type !== 'tracklist';
|
||||
},
|
||||
},
|
||||
|
||||
methods: {
|
||||
goToAlbum() {
|
||||
this.$router.push({ path: '/album/' + this.track.al.id });
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
likedAlbums,
|
||||
likedArtists,
|
||||
likedMVs,
|
||||
cloudDisk,
|
||||
} from '@/api/user';
|
||||
|
||||
export default {
|
||||
|
@ -147,4 +148,16 @@ export default {
|
|||
}
|
||||
});
|
||||
},
|
||||
fetchCloudDisk: ({ commit }) => {
|
||||
if (!isAccountLoggedIn()) return;
|
||||
return cloudDisk().then(result => {
|
||||
console.log(result);
|
||||
if (result.data) {
|
||||
commit('updateLikedXXX', {
|
||||
name: 'cloudDisk',
|
||||
data: result.data,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
|
|
@ -19,6 +19,7 @@ export default {
|
|||
albums: [],
|
||||
artists: [],
|
||||
mvs: [],
|
||||
cloudDisk: [],
|
||||
},
|
||||
contextMenu: {
|
||||
clickObjectID: 0,
|
||||
|
|
|
@ -80,14 +80,26 @@
|
|||
>
|
||||
{{ $t('library.mvs') }}
|
||||
</div>
|
||||
<div
|
||||
class="tab"
|
||||
:class="{ active: currentTab === 'cloudDisk' }"
|
||||
@click="updateCurrentTab('cloudDisk')"
|
||||
>
|
||||
云盘
|
||||
</div>
|
||||
</div>
|
||||
<button
|
||||
v-show="currentTab === 'playlists'"
|
||||
class="add-playlist"
|
||||
icon="plus"
|
||||
class="tab-button"
|
||||
@click="openAddPlaylistModal"
|
||||
><svg-icon icon-class="plus" />{{ $t('library.newPlayList') }}</button
|
||||
>
|
||||
><svg-icon icon-class="plus" />{{ $t('library.newPlayList') }}
|
||||
</button>
|
||||
<button
|
||||
v-show="currentTab === 'cloudDisk'"
|
||||
class="tab-button"
|
||||
@click="selectUploadFiles"
|
||||
><svg-icon icon-class="arrow-up-alt" /> 上传歌曲
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div v-show="currentTab === 'playlists'">
|
||||
|
@ -121,8 +133,26 @@
|
|||
<div v-show="currentTab === 'mvs'">
|
||||
<MvRow :mvs="liked.mvs" />
|
||||
</div>
|
||||
|
||||
<div v-show="currentTab === 'cloudDisk'">
|
||||
<TrackList
|
||||
:id="-8"
|
||||
:tracks="liked.cloudDisk"
|
||||
:column-number="3"
|
||||
type="cloudDisk"
|
||||
dbclick-track-func="playCloudDisk"
|
||||
:extra-context-menu-item="['removeTrackFromCloudDisk']"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<input
|
||||
ref="cloudDiskUploadInput"
|
||||
type="file"
|
||||
style="display: none"
|
||||
@change="uploadSongToCloudDisk"
|
||||
/>
|
||||
|
||||
<ContextMenu>
|
||||
<div class="item" @click="changePlaylistFilter('all')">{{
|
||||
$t('contextMenu.allPlaylists')
|
||||
|
@ -140,9 +170,10 @@
|
|||
|
||||
<script>
|
||||
import { mapActions, mapMutations, mapState } from 'vuex';
|
||||
import { getLyric } from '@/api/track';
|
||||
import { randomNum, dailyTask } from '@/utils/common';
|
||||
import { isAccountLoggedIn } from '@/utils/auth';
|
||||
import { uploadSong } from '@/api/user';
|
||||
import { getLyric } from '@/api/track';
|
||||
import NProgress from 'nprogress';
|
||||
import locale from '@/locale';
|
||||
|
||||
|
@ -227,6 +258,7 @@ export default {
|
|||
this.$store.dispatch('fetchLikedAlbums');
|
||||
this.$store.dispatch('fetchLikedArtists');
|
||||
this.$store.dispatch('fetchLikedMVs');
|
||||
this.$store.dispatch('fetchCloudDisk');
|
||||
},
|
||||
playLikedSongs() {
|
||||
this.$store.state.player.playPlaylistByID(
|
||||
|
@ -272,6 +304,22 @@ export default {
|
|||
this.updateData({ key: 'libraryPlaylistFilter', value: type });
|
||||
window.scrollTo({ top: 375, behavior: 'smooth' });
|
||||
},
|
||||
selectUploadFiles() {
|
||||
this.$refs.cloudDiskUploadInput.click();
|
||||
},
|
||||
uploadSongToCloudDisk(e) {
|
||||
const files = e.target.files;
|
||||
uploadSong(files[0]).then(result => {
|
||||
if (result.code === 200) {
|
||||
let newCloudDisk = this.liked.cloudDisk;
|
||||
newCloudDisk.unshift(result.privateCloud);
|
||||
this.$store.commit('updateLikedXXX', {
|
||||
name: 'cloudDisk',
|
||||
data: newCloudDisk,
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -427,7 +475,7 @@ h1 {
|
|||
}
|
||||
}
|
||||
|
||||
button.add-playlist {
|
||||
button.tab-button {
|
||||
color: var(--color-text);
|
||||
border-radius: 8px;
|
||||
padding: 0 14px;
|
||||
|
|
Loading…
Reference in New Issue
Block a user