koel/resources/assets/js/stores/artist.js
2016-06-05 19:06:24 +08:00

282 lines
6.5 KiB
JavaScript

import Vue from 'vue';
import {
reduce,
each,
find,
union,
difference,
take,
filter,
orderBy,
} from 'lodash';
import http from '../services/http';
import config from '../config';
import stub from '../stubs/artist';
import albumStore from './album';
const UNKNOWN_ARTIST_ID = 1;
const VARIOUS_ARTISTS_ID = 2;
export default {
stub,
state: {
artists: [],
},
/**
* Init the store.
*
* @param {Array.<Object>} artists The array of artists we got from the server.
*/
init(artists) {
this.all = artists;
albumStore.init(this.all);
// Traverse through artists array to get the cover and number of songs for each.
each(this.all, artist => {
this.setupArtist(artist);
});
},
/**
* Set up the (reactive) properties of an artist.
*
* @param {Object} artist
*/
setupArtist(artist) {
this.getImage(artist);
Vue.set(artist, 'playCount', 0);
// Here we build a list of songs performed by the artist, so that we don't need to traverse
// down the "artist > albums > items" route later.
// This also makes sure songs in compilation albums are counted as well.
Vue.set(artist, 'songs', reduce(artist.albums, (songs, album) => {
// If the album is compilation, we cater for the songs contributed by this artist only.
if (album.is_compilation) {
return songs.concat(filter(album.songs, { contributing_artist_id: artist.id }));
}
// Otherwise, just use all songs in the album.
return songs.concat(album.songs);
}, []));
Vue.set(artist, 'songCount', artist.songs.length);
Vue.set(artist, 'info', null);
return artist;
},
/**
* Get all artists.
*
* @return {Array.<Object>}
*/
get all() {
return this.state.artists;
},
/**
* Set all artists.
*
* @param {Array.<Object>} value
*/
set all(value) {
this.state.artists = value;
},
/**
* Get an artist object by its ID.
*
* @param {Number} id
*/
byId(id) {
return find(this.all, { id });
},
/**
* Adds an artist/artists into the current collection.
*
* @param {Array.<Object>|Object} artists
*/
add(artists) {
artists = [].concat(artists);
each(artists, a => this.setupArtist(a));
this.all = union(this.all, artists);
},
/**
* Remove artist(s) from the store.
*
* @param {Array.<Object>|Object} artists
*/
remove(artists) {
this.all = difference(this.all, [].concat(artists));
},
/**
* Get extra artist info (from Last.fm).
*
* @param {Object} artist
* @param {?Function} cb
*/
fetchInfo(artist, cb = null) {
if (artist.info) {
cb && cb();
return;
}
http.get(`artist/${artist.id}/info`, response => {
if (response.data) {
this.mergeArtistInfo(artist, response.data);
}
cb && cb();
});
},
/**
* Merge the (fetched) info into an artist.
*
* @param {Object} artist
* @param {Object} info
*/
mergeArtistInfo(artist, info) {
// If the artist image is not in a nice form, discard.
if (typeof info.image !== 'string') {
info.image = null;
}
// Set the artist image on the client side to the retrieved image from server.
if (info.image) {
artist.image = info.image;
}
artist.info = info;
},
/**
* Add album(s) into an artist.
*
* @param {Object} artist
* @param {Array.<Object>|Object} albums
*
*/
addAlbumsIntoArtist(artist, albums) {
albums = [].concat(albums);
artist.albums = union(artist.albums ? artist.albums : [], albums);
each(albums, album => {
album.artist_id = artist.id;
album.artist = artist;
artist.playCount += album.playCount;
});
},
/**
* Remove album(s) from an artist.
*
* @param {Object} artist
* @param {Array.<Object>|Object} albums
*/
removeAlbumsFromArtist(artist, albums) {
albums = [].concat(albums);
artist.albums = difference(artist.albums, albums);
each(albums, album => artist.playCount -= album.playCount);
},
/**
* Checks if an artist is empty.
*
* @param {Object} artist
*
* @return {boolean}
*/
isArtistEmpty(artist) {
return !artist.albums.length;
},
/**
* Determine if the artist is the special "Various Artists".
*
* @param {Object} artist
*
* @return {Boolean}
*/
isVariousArtists(artist) {
return artist.id === VARIOUS_ARTISTS_ID;
},
/**
* Determine if the artist is the special "Unknown Artist".
*
* @param {Object} artist [description]
*
* @return {Boolean}
*/
isUnknownArtist(artist) {
return artist.id === UNKNOWN_ARTIST_ID;
},
/**
* Get all songs performed by an artist.
*
* @param {Object} artist
*
* @return {Array.<Object>}
*/
getSongsByArtist(artist) {
return artist.songs;
},
/**
* Get the artist's image.
*
* @param {Object} artist
*
* @return {String}
*/
getImage(artist) {
if (!artist.image) {
// Try to get an image from one of the albums.
artist.image = config.unknownCover;
artist.albums.every(album => {
// If there's a "real" cover, use it.
if (album.image !== config.unknownCover) {
artist.image = album.cover;
// I want to break free.
return false;
}
});
}
return artist.image;
},
/**
* Get top n most-played artists.
*
* @param {Number} n
*
* @return {Array.<Object>}
*/
getMostPlayed(n = 6) {
// Only non-unknown artists with actually play count are applicable.
// Also, "Various Artists" doesn't count.
const applicable = filter(this.all, artist => {
return artist.playCount
&& !this.isUnknownArtist(artist)
&& !this.isVariousArtists(artist);
});
return take(orderBy(applicable, 'playCount', 'desc'), n);
},
};