2020-06-24 20:54:36 +00:00
|
|
|
<template>
|
2020-10-14 20:18:13 +00:00
|
|
|
<div>
|
|
|
|
<h1 class="mb-8 text-5xl">
|
2020-07-18 16:06:07 +00:00
|
|
|
{{ $t('favorites.title') }}
|
2020-06-24 20:54:36 +00:00
|
|
|
<div
|
|
|
|
@click="reloadTabs"
|
2020-10-14 20:18:13 +00:00
|
|
|
class="inline-block clickable reload-button"
|
2020-06-24 20:54:36 +00:00
|
|
|
ref="reloadButton"
|
|
|
|
role="button"
|
|
|
|
aria-label="reload"
|
|
|
|
>
|
|
|
|
<i class="material-icons">sync</i>
|
|
|
|
</div>
|
2020-10-14 20:18:13 +00:00
|
|
|
</h1>
|
2020-10-07 18:29:20 +00:00
|
|
|
|
2020-10-14 20:18:13 +00:00
|
|
|
<ul class="section-tabs">
|
|
|
|
<li
|
2020-08-31 20:14:14 +00:00
|
|
|
class="section-tabs__tab favorites_tablinks"
|
|
|
|
:class="{ active: activeTab === tab }"
|
|
|
|
@click="activeTab = tab"
|
|
|
|
v-for="tab in tabs"
|
|
|
|
:key="tab"
|
|
|
|
>
|
|
|
|
{{ $tc(`globals.listTabs.${tab}`, 2) }}
|
2020-10-14 20:18:13 +00:00
|
|
|
</li>
|
|
|
|
</ul>
|
2020-06-24 20:54:36 +00:00
|
|
|
|
2020-10-10 18:03:19 +00:00
|
|
|
<button class="btn btn-primary" v-if="!activeTabEmpty" style="margin-bottom: 2rem" @click="downloadAllOfType">
|
2020-11-02 21:50:19 +00:00
|
|
|
{{ $t('globals.download', { thing: $tc(`globals.listTabs.${activeTab}N`, getTabLenght()) }) }}
|
2020-10-07 18:29:20 +00:00
|
|
|
</button>
|
|
|
|
|
2020-08-31 20:14:14 +00:00
|
|
|
<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'playlist' }">
|
2020-06-24 20:54:36 +00:00
|
|
|
<div v-if="playlists.length == 0">
|
2020-07-18 16:06:07 +00:00
|
|
|
<h1>{{ $t('favorites.noPlaylists') }}</h1>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
<div class="release_grid" v-if="playlists.length > 0 || spotifyPlaylists > 0">
|
2020-11-02 22:24:10 +00:00
|
|
|
<div class="release" v-for="release in playlists" :key="release.id">
|
|
|
|
<router-link tag="div" class="cursor-pointer" :to="{ name: 'Playlist', params: { id: release.id } }">
|
|
|
|
<CoverContainer is-rounded :cover="release.picture_medium" :link="release.link" @click.stop="addToQueue" />
|
|
|
|
<p class="primary-text">{{ release.title }}</p>
|
|
|
|
</router-link>
|
2020-11-02 21:33:00 +00:00
|
|
|
|
2020-07-18 16:06:07 +00:00
|
|
|
<p class="secondary-text">
|
2020-09-19 15:07:28 +00:00
|
|
|
{{
|
|
|
|
`${$t('globals.by', { artist: release.creator.name })} - ${$tc(
|
|
|
|
'globals.listTabs.trackN',
|
|
|
|
release.nb_tracks
|
|
|
|
)}`
|
|
|
|
}}
|
2020-07-18 16:06:07 +00:00
|
|
|
</p>
|
2020-11-02 22:24:10 +00:00
|
|
|
</div>
|
2020-11-02 21:33:00 +00:00
|
|
|
|
2020-11-02 22:24:10 +00:00
|
|
|
<div class="release" v-for="release in spotifyPlaylists" :key="release.id">
|
|
|
|
<router-link tag="div" class="cursor-pointer" :to="{ name: 'Spotify Playlist', params: { id: release.id } }">
|
|
|
|
<CoverContainer is-rounded :cover="release.picture_medium" :link="release.link" @click.stop="addToQueue" />
|
|
|
|
<p class="primary-text">{{ release.title }}</p>
|
|
|
|
</router-link>
|
2020-11-02 21:33:00 +00:00
|
|
|
|
2020-07-18 16:06:07 +00:00
|
|
|
<p class="secondary-text">
|
2020-09-19 15:07:28 +00:00
|
|
|
{{
|
|
|
|
`${$t('globals.by', { artist: release.creator.name })} - ${$tc(
|
|
|
|
'globals.listTabs.trackN',
|
|
|
|
release.nb_tracks
|
|
|
|
)}`
|
|
|
|
}}
|
2020-07-18 16:06:07 +00:00
|
|
|
</p>
|
2020-11-02 22:24:10 +00:00
|
|
|
</div>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-08-31 20:14:14 +00:00
|
|
|
|
|
|
|
<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'album' }">
|
2020-06-24 20:54:36 +00:00
|
|
|
<div v-if="albums.length == 0">
|
2020-07-18 16:06:07 +00:00
|
|
|
<h1>{{ $t('favorites.noAlbums') }}</h1>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
<div class="release_grid" v-if="albums.length > 0">
|
2020-09-26 17:48:30 +00:00
|
|
|
<router-link
|
|
|
|
tag="div"
|
|
|
|
class="release clickable"
|
|
|
|
v-for="release in albums"
|
|
|
|
:key="release.id"
|
2020-09-26 19:10:40 +00:00
|
|
|
:to="{ name: 'Album', params: { id: release.id } }"
|
2020-09-26 17:48:30 +00:00
|
|
|
>
|
2020-11-02 21:33:00 +00:00
|
|
|
<CoverContainer is-rounded :cover="release.cover_medium" :link="release.link" @click.stop="addToQueue" />
|
2020-06-24 20:54:36 +00:00
|
|
|
<p class="primary-text">{{ release.title }}</p>
|
2020-09-26 17:48:30 +00:00
|
|
|
</router-link>
|
2020-11-02 21:33:00 +00:00
|
|
|
|
|
|
|
<p class="secondary-text">{{ `${$t('globals.by', { artist: release.artist.name })}` }}</p>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-08-31 20:14:14 +00:00
|
|
|
|
|
|
|
<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'artist' }">
|
2020-06-24 20:54:36 +00:00
|
|
|
<div v-if="artists.length == 0">
|
2020-07-18 16:06:07 +00:00
|
|
|
<h1>{{ $t('favorites.noArtists') }}</h1>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
<div class="release_grid" v-if="artists.length > 0">
|
2020-09-26 17:48:30 +00:00
|
|
|
<router-link
|
|
|
|
tag="div"
|
|
|
|
class="release clickable"
|
|
|
|
v-for="release in artists"
|
|
|
|
:key="release.id"
|
|
|
|
:to="{ name: 'Artist', params: { id: release.id } }"
|
|
|
|
>
|
2020-11-02 21:33:00 +00:00
|
|
|
<CoverContainer is-circle :cover="release.picture_medium" :link="release.link" @click.stop="addToQueue" />
|
2020-06-24 20:54:36 +00:00
|
|
|
<p class="primary-text">{{ release.name }}</p>
|
2020-09-26 17:48:30 +00:00
|
|
|
</router-link>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
2020-08-31 20:14:14 +00:00
|
|
|
|
|
|
|
<div class="favorites_tabcontent" :class="{ 'favorites_tabcontent--active': activeTab === 'track' }">
|
2020-06-24 20:54:36 +00:00
|
|
|
<div v-if="tracks.length == 0">
|
2020-07-18 16:06:07 +00:00
|
|
|
<h1>{{ $t('favorites.noTracks') }}</h1>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
<table v-if="tracks.length > 0" class="table">
|
|
|
|
<tr v-for="track in tracks" class="track_row">
|
2020-11-02 11:25:08 +00:00
|
|
|
<td class="p-3 text-center cursor-default" :class="{ first: track.position === 1 }">
|
2020-06-24 20:54:36 +00:00
|
|
|
{{ track.position }}
|
|
|
|
</td>
|
|
|
|
<td>
|
|
|
|
<a
|
|
|
|
href="#"
|
|
|
|
class="rounded"
|
|
|
|
:class="{ 'single-cover': !!track.preview }"
|
|
|
|
@click="playPausePreview"
|
|
|
|
:data-preview="track.preview"
|
|
|
|
>
|
2020-10-13 21:48:00 +00:00
|
|
|
<PreviewControls v-if="track.preview" />
|
|
|
|
|
2020-06-24 20:54:36 +00:00
|
|
|
<img class="rounded coverart" :src="track.album.cover_small" />
|
|
|
|
</a>
|
|
|
|
</td>
|
2020-11-02 21:33:00 +00:00
|
|
|
<td class="table__cell--large">
|
2020-06-24 20:54:36 +00:00
|
|
|
{{
|
|
|
|
track.title +
|
2020-07-28 20:09:13 +00:00
|
|
|
(track.title_version && track.title.indexOf(track.title_version) == -1 ? ' ' + track.title_version : '')
|
2020-06-24 20:54:36 +00:00
|
|
|
}}
|
|
|
|
</td>
|
2020-09-26 17:48:30 +00:00
|
|
|
<router-link
|
|
|
|
tag="td"
|
2020-11-02 21:33:00 +00:00
|
|
|
class="table__cell table__cell--medium table__cell--center clickable"
|
2020-09-26 17:48:30 +00:00
|
|
|
:to="{ name: 'Artist', params: { id: track.artist.id } }"
|
2020-06-24 20:54:36 +00:00
|
|
|
>
|
|
|
|
{{ track.artist.name }}
|
2020-09-26 17:48:30 +00:00
|
|
|
</router-link>
|
|
|
|
<router-link
|
|
|
|
tag="td"
|
2020-11-02 21:33:00 +00:00
|
|
|
class="table__cell--medium table__cell--center clickable"
|
2020-09-26 19:10:40 +00:00
|
|
|
:to="{ name: 'Album', params: { id: track.album.id } }"
|
2020-06-24 20:54:36 +00:00
|
|
|
>
|
|
|
|
{{ track.album.title }}
|
2020-09-26 17:48:30 +00:00
|
|
|
</router-link>
|
2020-06-24 20:54:36 +00:00
|
|
|
<td class="table__cell--small">
|
|
|
|
{{ convertDuration(track.duration) }}
|
|
|
|
</td>
|
|
|
|
<td
|
2020-11-02 21:33:00 +00:00
|
|
|
class="cursor-pointer group"
|
2020-06-24 20:54:36 +00:00
|
|
|
@click.stop="addToQueue"
|
|
|
|
:data-link="track.link"
|
|
|
|
role="button"
|
|
|
|
aria-label="download"
|
|
|
|
>
|
|
|
|
<div class="table__cell-content table__cell-content--vertical-center">
|
2020-11-02 21:33:00 +00:00
|
|
|
<i
|
|
|
|
class="transition-colors duration-150 ease-in-out material-icons group-hover:text-primary"
|
|
|
|
:title="$t('globals.download_hint')"
|
|
|
|
>
|
|
|
|
get_app
|
|
|
|
</i>
|
2020-06-24 20:54:36 +00:00
|
|
|
</div>
|
|
|
|
</td>
|
|
|
|
</tr>
|
|
|
|
</table>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
2020-10-07 18:29:20 +00:00
|
|
|
<style lang="scss" scoped>
|
2020-08-31 20:14:14 +00:00
|
|
|
.favorites_tabcontent {
|
|
|
|
display: none;
|
|
|
|
|
|
|
|
&--active {
|
|
|
|
display: block;
|
|
|
|
}
|
|
|
|
}
|
2020-10-14 20:18:13 +00:00
|
|
|
|
|
|
|
.reload-button {
|
|
|
|
&.spin {
|
|
|
|
i {
|
|
|
|
animation: spin 500ms infinite ease-out reverse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-08-31 20:14:14 +00:00
|
|
|
</style>
|
|
|
|
|
2020-06-24 20:54:36 +00:00
|
|
|
<script>
|
2020-09-21 19:54:00 +00:00
|
|
|
import { socket } from '@/utils/socket'
|
2020-10-07 18:29:20 +00:00
|
|
|
import { sendAddToQueue, aggregateDownloadLinks } from '@/utils/downloads'
|
2020-08-31 20:14:14 +00:00
|
|
|
import { convertDuration } from '@/utils/utils'
|
2020-07-16 22:11:28 +00:00
|
|
|
import { toast } from '@/utils/toasts'
|
2020-09-21 19:54:00 +00:00
|
|
|
import { getFavoritesData } from '@/data/favorites'
|
|
|
|
|
2020-10-13 21:48:00 +00:00
|
|
|
import EventBus from '@/utils/EventBus'
|
|
|
|
import PreviewControls from '@components/globals/PreviewControls.vue'
|
2020-11-02 21:33:00 +00:00
|
|
|
import CoverContainer from '@components/globals/CoverContainer.vue'
|
2020-10-13 21:48:00 +00:00
|
|
|
|
2020-06-24 20:54:36 +00:00
|
|
|
export default {
|
2020-10-13 21:48:00 +00:00
|
|
|
components: {
|
2020-11-02 21:33:00 +00:00
|
|
|
PreviewControls,
|
|
|
|
CoverContainer
|
2020-10-13 21:48:00 +00:00
|
|
|
},
|
2020-06-24 20:54:36 +00:00
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
tracks: [],
|
|
|
|
albums: [],
|
|
|
|
artists: [],
|
|
|
|
playlists: [],
|
2020-08-31 20:14:14 +00:00
|
|
|
spotifyPlaylists: [],
|
|
|
|
activeTab: 'playlist',
|
|
|
|
tabs: ['playlist', 'album', 'artist', 'track']
|
|
|
|
}
|
|
|
|
},
|
2020-10-07 18:29:20 +00:00
|
|
|
computed: {
|
|
|
|
activeTabEmpty() {
|
|
|
|
let toCheck = this.getActiveRelease()
|
|
|
|
|
|
|
|
return toCheck.length === 0
|
|
|
|
}
|
|
|
|
},
|
2020-09-21 19:54:00 +00:00
|
|
|
async created() {
|
|
|
|
const favoritesData = await getFavoritesData()
|
|
|
|
|
2020-09-22 20:40:41 +00:00
|
|
|
// TODO Change with isLoggedIn vuex getter
|
|
|
|
if (Object.entries(favoritesData).length === 0) return
|
|
|
|
|
2020-09-21 19:54:00 +00:00
|
|
|
this.setFavorites(favoritesData)
|
2020-06-24 20:54:36 +00:00
|
|
|
},
|
2020-08-31 20:14:14 +00:00
|
|
|
mounted() {
|
|
|
|
socket.on('updated_userFavorites', this.updated_userFavorites)
|
|
|
|
socket.on('updated_userSpotifyPlaylists', this.updated_userSpotifyPlaylists)
|
|
|
|
socket.on('updated_userPlaylists', this.updated_userPlaylists)
|
|
|
|
socket.on('updated_userAlbums', this.updated_userAlbums)
|
|
|
|
socket.on('updated_userArtist', this.updated_userArtist)
|
|
|
|
socket.on('updated_userTracks', this.updated_userTracks)
|
2020-09-21 19:54:00 +00:00
|
|
|
|
|
|
|
this.$on('hook:destroyed', () => {
|
|
|
|
socket.off('updated_userFavorites')
|
|
|
|
socket.off('updated_userSpotifyPlaylists')
|
|
|
|
socket.off('updated_userPlaylists')
|
|
|
|
socket.off('updated_userAlbums')
|
|
|
|
socket.off('updated_userArtist')
|
|
|
|
socket.off('updated_userTracks')
|
|
|
|
})
|
2020-08-31 20:14:14 +00:00
|
|
|
},
|
2020-06-24 20:54:36 +00:00
|
|
|
methods: {
|
2020-07-16 20:49:08 +00:00
|
|
|
playPausePreview(e) {
|
|
|
|
EventBus.$emit('trackPreview:playPausePreview', e)
|
|
|
|
},
|
2020-08-31 20:14:14 +00:00
|
|
|
convertDuration,
|
2020-10-07 18:29:20 +00:00
|
|
|
downloadAllOfType() {
|
|
|
|
try {
|
|
|
|
let toDownload = this.getActiveRelease()
|
|
|
|
|
|
|
|
if (this.activeTab === 'track') {
|
|
|
|
let lovedTracks = this.getLovedTracksPlaylist()
|
|
|
|
|
|
|
|
sendAddToQueue(lovedTracks.link)
|
|
|
|
} else {
|
|
|
|
sendAddToQueue(aggregateDownloadLinks(toDownload))
|
|
|
|
}
|
|
|
|
} catch (error) {
|
|
|
|
console.error(error.message)
|
|
|
|
}
|
|
|
|
},
|
2020-06-24 20:54:36 +00:00
|
|
|
addToQueue(e) {
|
2020-09-21 19:54:00 +00:00
|
|
|
sendAddToQueue(e.currentTarget.dataset.link)
|
2020-06-24 20:54:36 +00:00
|
|
|
},
|
|
|
|
updated_userSpotifyPlaylists(data) {
|
|
|
|
this.spotifyPlaylists = data
|
|
|
|
},
|
|
|
|
updated_userPlaylists(data) {
|
|
|
|
this.playlists = data
|
|
|
|
},
|
|
|
|
updated_userAlbums(data) {
|
|
|
|
this.albums = data
|
|
|
|
},
|
|
|
|
updated_userArtist(data) {
|
|
|
|
this.artists = data
|
|
|
|
},
|
|
|
|
updated_userTracks(data) {
|
|
|
|
this.tracks = data
|
|
|
|
},
|
|
|
|
reloadTabs() {
|
|
|
|
this.$refs.reloadButton.classList.add('spin')
|
2020-09-21 17:12:14 +00:00
|
|
|
|
2020-06-24 20:54:36 +00:00
|
|
|
socket.emit('update_userFavorites')
|
2020-09-21 17:12:14 +00:00
|
|
|
|
|
|
|
if (localStorage.getItem('spotifyUser')) {
|
2020-06-24 20:54:36 +00:00
|
|
|
socket.emit('update_userSpotifyPlaylists', localStorage.getItem('spotifyUser'))
|
2020-09-21 17:12:14 +00:00
|
|
|
}
|
2020-06-24 20:54:36 +00:00
|
|
|
},
|
|
|
|
updated_userFavorites(data) {
|
2020-09-21 19:54:00 +00:00
|
|
|
this.setFavorites(data)
|
2020-06-24 20:54:36 +00:00
|
|
|
|
|
|
|
// Removing animation class only when the animation has completed an iteration
|
|
|
|
// Prevents animation ugly stutter
|
|
|
|
this.$refs.reloadButton.addEventListener(
|
|
|
|
'animationiteration',
|
|
|
|
() => {
|
|
|
|
this.$refs.reloadButton.classList.remove('spin')
|
2020-07-21 09:09:47 +00:00
|
|
|
toast(this.$t('toasts.refreshFavs'), 'done', true)
|
2020-06-24 20:54:36 +00:00
|
|
|
},
|
|
|
|
{ once: true }
|
|
|
|
)
|
|
|
|
},
|
2020-09-21 19:54:00 +00:00
|
|
|
setFavorites(data) {
|
|
|
|
const { tracks, albums, artists, playlists } = data
|
|
|
|
|
|
|
|
this.tracks = tracks
|
|
|
|
this.albums = albums
|
|
|
|
this.artists = artists
|
|
|
|
this.playlists = playlists
|
2020-10-07 18:29:20 +00:00
|
|
|
},
|
|
|
|
getActiveRelease(tab = this.activeTab) {
|
|
|
|
let toDownload
|
|
|
|
|
|
|
|
switch (tab) {
|
|
|
|
case 'playlist':
|
|
|
|
toDownload = this.playlists
|
|
|
|
break
|
|
|
|
case 'album':
|
|
|
|
toDownload = this.albums
|
|
|
|
break
|
|
|
|
case 'artist':
|
|
|
|
toDownload = this.artists
|
|
|
|
break
|
|
|
|
case 'track':
|
|
|
|
toDownload = this.tracks
|
|
|
|
break
|
|
|
|
|
|
|
|
default:
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
return toDownload
|
|
|
|
},
|
2020-11-02 21:50:19 +00:00
|
|
|
getTabLenght(tab = this.activeTab) {
|
|
|
|
let total = this[`${tab}s`].length
|
|
|
|
// TODO: Add Spotify playlists to downlaod queue as well
|
|
|
|
//if (tab === "playlist") total += this.spotifyPlaylists.length
|
|
|
|
return total
|
|
|
|
},
|
2020-10-07 18:29:20 +00:00
|
|
|
getLovedTracksPlaylist() {
|
|
|
|
let lovedTracks = this.playlists.filter(playlist => {
|
|
|
|
return playlist.is_loved_track
|
|
|
|
})
|
|
|
|
|
|
|
|
if (lovedTracks.length !== 0) {
|
|
|
|
return lovedTracks[0]
|
|
|
|
} else {
|
|
|
|
throw new Error('No loved tracks playlist!')
|
|
|
|
}
|
2020-06-24 20:54:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
</script>
|