Playlist and Users data storage overhaul
This commit is contained in:
@ -6046,9 +6046,11 @@ main header {
|
|||||||
height: 0.5em;
|
height: 0.5em;
|
||||||
margin: 0.25em 1px;
|
margin: 0.25em 1px;
|
||||||
background: #cecac4;
|
background: #cecac4;
|
||||||
opacity: 0.25; }
|
opacity: 0.2; }
|
||||||
.popularity-bars .bar.filled {
|
.popularity-bars .bar.filled {
|
||||||
opacity: 1; }
|
opacity: 1; }
|
||||||
|
.light-theme .popularity-bars .bar {
|
||||||
|
background: #121212; }
|
||||||
|
|
||||||
.popularity-value {
|
.popularity-value {
|
||||||
display: none; }
|
display: none; }
|
||||||
@ -6422,7 +6424,8 @@ main .track-view {
|
|||||||
height: 4rem;
|
height: 4rem;
|
||||||
margin-top: -1rem; }
|
margin-top: -1rem; }
|
||||||
.search-view .search-form input:focus, .search-view .search-form input:active {
|
.search-view .search-form input:focus, .search-view .search-form input:active {
|
||||||
border-color: #08d58f; }
|
border-color: #08d58f;
|
||||||
|
background: transparent; }
|
||||||
|
|
||||||
.search-view .search-result-sections {
|
.search-view .search-result-sections {
|
||||||
padding-bottom: 30px; }
|
padding-bottom: 30px; }
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -98,7 +98,7 @@
|
|||||||
|
|
||||||
// Release details
|
// Release details
|
||||||
// These are automatically injected to built HTML
|
// These are automatically injected to built HTML
|
||||||
var build = "1535617670";
|
var build = "1535658713";
|
||||||
var version = "3.25.1";
|
var version = "3.25.1";
|
||||||
|
|
||||||
// Construct the script tag
|
// Construct the script tag
|
||||||
|
|||||||
@ -35,7 +35,7 @@ class AlbumGrid extends React.Component{
|
|||||||
<div className={className}>
|
<div className={className}>
|
||||||
{
|
{
|
||||||
this.props.albums.map(item => {
|
this.props.albums.map(item => {
|
||||||
var album = helpers.collateObject(item, {artists: this.props.artists});
|
var album = helpers.collate(item, {artists: this.props.artists});
|
||||||
return (
|
return (
|
||||||
<GridItem
|
<GridItem
|
||||||
key={album.uri}
|
key={album.uri}
|
||||||
|
|||||||
@ -50,7 +50,7 @@ class ArtistGrid extends React.Component{
|
|||||||
<GridItem
|
<GridItem
|
||||||
key={artist.uri}
|
key={artist.uri}
|
||||||
type="artist"
|
type="artist"
|
||||||
item={artist}
|
item={helpers.collate(artist, {albums: this.props.albums})}
|
||||||
show_source_icon={this.props.show_source_icon}
|
show_source_icon={this.props.show_source_icon}
|
||||||
onClick={e => {hashHistory.push(global.baseURL+'artist/'+encodeURIComponent(artist.uri))}}
|
onClick={e => {hashHistory.push(global.baseURL+'artist/'+encodeURIComponent(artist.uri))}}
|
||||||
lastfmActions={this.props.lastfmActions}
|
lastfmActions={this.props.lastfmActions}
|
||||||
@ -69,7 +69,9 @@ class ArtistGrid extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
return {}
|
return {
|
||||||
|
albums: state.core.albums
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps = (dispatch) => {
|
||||||
|
|||||||
@ -55,7 +55,7 @@ export default class GridItem extends React.Component{
|
|||||||
case 'artist':
|
case 'artist':
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{item.followers ? item.followers.total.toLocaleString()+' followers' : null}
|
{item.followers ? item.followers.toLocaleString()+' followers' : null}
|
||||||
{item.albums_uris ? item.albums_uris.length+' albums' : null}
|
{item.albums_uris ? item.albums_uris.length+' albums' : null}
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
@ -73,7 +73,7 @@ export default class GridItem extends React.Component{
|
|||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
{ item.artists ? <ArtistSentence artists={ item.artists } /> : null }
|
{ item.artists ? <ArtistSentence artists={ item.artists } /> : null }
|
||||||
{ item.followers ? item.followers.total.toLocaleString()+' followers' : null }
|
{ item.followers ? item.followers.toLocaleString()+' followers' : null }
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -132,6 +132,10 @@ export let sizedImages = function(images){
|
|||||||
huge: false
|
huge: false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!images){
|
||||||
|
return sizes;
|
||||||
|
}
|
||||||
|
|
||||||
// An array of images has been provided
|
// An array of images has been provided
|
||||||
if (Array.isArray(images)){
|
if (Array.isArray(images)){
|
||||||
|
|
||||||
@ -314,9 +318,9 @@ export let formatAlbum = function(data){
|
|||||||
var album = {};
|
var album = {};
|
||||||
var fields = [
|
var fields = [
|
||||||
'uri',
|
'uri',
|
||||||
|
'provider',
|
||||||
'name',
|
'name',
|
||||||
'type',
|
'type',
|
||||||
'provider',
|
|
||||||
'artists_uris',
|
'artists_uris',
|
||||||
'tracks_uris',
|
'tracks_uris',
|
||||||
'release_date',
|
'release_date',
|
||||||
@ -347,15 +351,17 @@ export let formatArtist = function(data){
|
|||||||
var artist = {}
|
var artist = {}
|
||||||
var fields = [
|
var fields = [
|
||||||
'uri',
|
'uri',
|
||||||
|
'provider',
|
||||||
|
'mbid',
|
||||||
'name',
|
'name',
|
||||||
'type',
|
'type',
|
||||||
'provider',
|
|
||||||
'popularity',
|
|
||||||
'images',
|
'images',
|
||||||
|
'popularity',
|
||||||
|
'followers',
|
||||||
|
'listeners',
|
||||||
'biography',
|
'biography',
|
||||||
'biography_link',
|
'biography_link',
|
||||||
'biography_publish_date',
|
'biography_publish_date',
|
||||||
'followers',
|
|
||||||
'related_artists_uris',
|
'related_artists_uris',
|
||||||
'albums_uris',
|
'albums_uris',
|
||||||
'tracks_uris'
|
'tracks_uris'
|
||||||
@ -388,6 +394,78 @@ export let formatArtist = function(data){
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format our playlist objects into a universal format
|
||||||
|
*
|
||||||
|
* @param data obj
|
||||||
|
* @return playlist obj
|
||||||
|
**/
|
||||||
|
export let formatPlaylist = function(data){
|
||||||
|
var playlist = {}
|
||||||
|
var fields = [
|
||||||
|
'uri',
|
||||||
|
'provider',
|
||||||
|
'type',
|
||||||
|
'name',
|
||||||
|
'description',
|
||||||
|
'images',
|
||||||
|
'popularity',
|
||||||
|
'followers',
|
||||||
|
'last_modified_date',
|
||||||
|
'can_edit',
|
||||||
|
'user_uri',
|
||||||
|
'tracks_uris'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Loop fields and import from data
|
||||||
|
for (var field of fields){
|
||||||
|
if (data.hasOwnProperty(field)){
|
||||||
|
playlist[field] = data[field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.followers && data.followers.total){
|
||||||
|
playlist.followers = data.followers.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
return playlist;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format a user objects into a universal format
|
||||||
|
*
|
||||||
|
* @param data obj
|
||||||
|
* @return playlist obj
|
||||||
|
**/
|
||||||
|
export let formatUser = function(data){
|
||||||
|
var user = {}
|
||||||
|
var fields = [
|
||||||
|
'uri',
|
||||||
|
'provider',
|
||||||
|
'name',
|
||||||
|
'images',
|
||||||
|
'followers'
|
||||||
|
];
|
||||||
|
|
||||||
|
// Loop fields and import from data
|
||||||
|
for (var field of fields){
|
||||||
|
if (data.hasOwnProperty(field)){
|
||||||
|
user[field] = data[field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.followers && data.followers.total){
|
||||||
|
user.followers = data.followers.total;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.display_name && !user.name) user.name = data.display_name;
|
||||||
|
if (data.id && !user.name) user.name = data.id;
|
||||||
|
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format tracks into our universal format
|
* Format tracks into our universal format
|
||||||
*
|
*
|
||||||
@ -475,7 +553,7 @@ export let formatTracks = function(tracks){
|
|||||||
* @param indexes Obj (the relevant core indexes)
|
* @param indexes Obj (the relevant core indexes)
|
||||||
* @return object Obj
|
* @return object Obj
|
||||||
**/
|
**/
|
||||||
export let collateObject = function(obj, indexes = {}){
|
export let collate = function(obj, indexes = {}){
|
||||||
|
|
||||||
// First, let's reset this object
|
// First, let's reset this object
|
||||||
// This is important because by changing this object, we inadvertently
|
// This is important because by changing this object, we inadvertently
|
||||||
@ -486,12 +564,12 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
// Setup empty arrays for the appropriate reference objects
|
// Setup empty arrays for the appropriate reference objects
|
||||||
// This helps create a consistent object structure
|
// This helps create a consistent object structure
|
||||||
if (obj.artists_uris !== undefined) obj.artists = [];
|
if (obj.artists_uris !== undefined) obj.artists = [];
|
||||||
if (obj.albums_uris !== undefined) obj.albums = [];
|
if (obj.albums_uris !== undefined) obj.albums = [];
|
||||||
if (obj.tracks_uris !== undefined) obj.tracks = [];
|
if (obj.tracks_uris !== undefined) obj.tracks = [];
|
||||||
if (obj.users_uris !== undefined) obj.users = [];
|
if (obj.users_uris !== undefined) obj.users = [];
|
||||||
|
if (obj.playlists_uris !== undefined) obj.playlists = [];
|
||||||
|
|
||||||
if (indexes.artists){
|
if (indexes.artists){
|
||||||
|
|
||||||
if (obj.artists_uris){
|
if (obj.artists_uris){
|
||||||
for (var uri of obj.artists_uris){
|
for (var uri of obj.artists_uris){
|
||||||
if (indexes.artists[uri]){
|
if (indexes.artists[uri]){
|
||||||
@ -499,7 +577,6 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.artist_uri){
|
if (obj.artist_uri){
|
||||||
if (indexes.artists[obj.artist_uri]){
|
if (indexes.artists[obj.artist_uri]){
|
||||||
obj.artist = indexes.artists[obj.artist_uri];
|
obj.artist = indexes.artists[obj.artist_uri];
|
||||||
@ -515,7 +592,6 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.album_uri){
|
if (obj.album_uri){
|
||||||
if (indexes.albums[obj.album_uri]){
|
if (indexes.albums[obj.album_uri]){
|
||||||
obj.album = indexes.albums[obj.album_uri];
|
obj.album = indexes.albums[obj.album_uri];
|
||||||
@ -524,7 +600,6 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (indexes.tracks){
|
if (indexes.tracks){
|
||||||
|
|
||||||
if (obj.tracks_uris){
|
if (obj.tracks_uris){
|
||||||
for (var uri of obj.tracks_uris){
|
for (var uri of obj.tracks_uris){
|
||||||
if (indexes.tracks[uri]){
|
if (indexes.tracks[uri]){
|
||||||
@ -532,7 +607,6 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.track_uri){
|
if (obj.track_uri){
|
||||||
if (indexes.tracks[obj.track_uri]){
|
if (indexes.tracks[obj.track_uri]){
|
||||||
obj.track = indexes.tracks[obj.track_uri];
|
obj.track = indexes.tracks[obj.track_uri];
|
||||||
@ -548,7 +622,6 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (obj.user_uri){
|
if (obj.user_uri){
|
||||||
if (indexes.users[obj.user_uri]){
|
if (indexes.users[obj.user_uri]){
|
||||||
obj.user = indexes.users[obj.user_uri];
|
obj.user = indexes.users[obj.user_uri];
|
||||||
@ -556,6 +629,21 @@ export let collateObject = function(obj, indexes = {}){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (indexes.playlists){
|
||||||
|
if (obj.playlists_uris){
|
||||||
|
for (var uri of obj.playlists_uris){
|
||||||
|
if (indexes.playlists[uri]){
|
||||||
|
obj.playlists.push(indexes.playlists[uri]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (obj.playlist_uri){
|
||||||
|
if (indexes.playlists[obj.playlist_uri]){
|
||||||
|
obj.playlist = indexes.playlists[obj.playlist_uri];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -86,38 +86,51 @@ export function cachebustHttpStream(){
|
|||||||
* relevant service to load the record - all from one neat package.
|
* relevant service to load the record - all from one neat package.
|
||||||
**/
|
**/
|
||||||
|
|
||||||
export function loadTrack(uri){
|
export function loadTrack(uri, force_reload = false){
|
||||||
return {
|
return {
|
||||||
type: 'LOAD_TRACK',
|
type: 'LOAD_TRACK',
|
||||||
uri: uri
|
uri: uri,
|
||||||
|
force_reload: force_reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadAlbum(uri){
|
export function loadAlbum(uri, force_reload = false){
|
||||||
return {
|
return {
|
||||||
type: 'LOAD_ALBUM',
|
type: 'LOAD_ALBUM',
|
||||||
uri: uri
|
uri: uri,
|
||||||
|
force_reload: force_reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadArtist(uri){
|
export function loadArtist(uri, force_reload = false){
|
||||||
return {
|
return {
|
||||||
type: 'LOAD_ARTIST',
|
type: 'LOAD_ARTIST',
|
||||||
uri: uri
|
uri: uri,
|
||||||
|
force_reload: force_reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadPlaylist(uri){
|
export function loadPlaylist(uri, force_reload = false){
|
||||||
return {
|
return {
|
||||||
type: 'LOAD_PLAYLIST',
|
type: 'LOAD_PLAYLIST',
|
||||||
uri: uri
|
uri: uri,
|
||||||
|
force_reload: force_reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadUser(uri){
|
export function loadUser(uri, force_reload = false){
|
||||||
return {
|
return {
|
||||||
type: 'LOAD_USER',
|
type: 'LOAD_USER',
|
||||||
uri: uri
|
uri: uri,
|
||||||
|
force_reload: force_reload
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function loadUserPlaylists(uri, force_reload = false){
|
||||||
|
return {
|
||||||
|
type: 'LOAD_USER_PLAYLISTS',
|
||||||
|
uri: uri,
|
||||||
|
force_reload: force_reload
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -177,6 +190,15 @@ export function usersLoaded(users){
|
|||||||
users: users
|
users: users
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
export function userPlaylistsLoaded(uri, playlists, more = null, total = null){
|
||||||
|
return {
|
||||||
|
type: 'USER_PLAYLISTS_LOADED',
|
||||||
|
uri: uri,
|
||||||
|
playlists: playlists,
|
||||||
|
more: more,
|
||||||
|
total: total
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function loadedMore(parent_type, parent_key, records_type, records_data){
|
export function loadedMore(parent_type, parent_key, records_type, records_data){
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -357,6 +357,14 @@ const CoreMiddleware = (function(){
|
|||||||
|
|
||||||
|
|
||||||
case 'LOAD_TRACK':
|
case 'LOAD_TRACK':
|
||||||
|
|
||||||
|
if (
|
||||||
|
!action.force_reload &&
|
||||||
|
store.getState().core.tracks[action.uri]){
|
||||||
|
console.info('Loading "'+action.uri+'" from index');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (helpers.uriSource(action.uri)){
|
switch (helpers.uriSource(action.uri)){
|
||||||
case 'spotify':
|
case 'spotify':
|
||||||
store.dispatch(spotifyActions.getTrack(action.uri));
|
store.dispatch(spotifyActions.getTrack(action.uri));
|
||||||
@ -374,6 +382,15 @@ const CoreMiddleware = (function(){
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'LOAD_ALBUM':
|
case 'LOAD_ALBUM':
|
||||||
|
|
||||||
|
if (
|
||||||
|
!action.force_reload &&
|
||||||
|
store.getState().core.albums[action.uri] &&
|
||||||
|
store.getState().core.albums[action.uri].tracks_uris){
|
||||||
|
console.info('Loading "'+action.uri+'" from index');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (helpers.uriSource(action.uri)){
|
switch (helpers.uriSource(action.uri)){
|
||||||
case 'spotify':
|
case 'spotify':
|
||||||
store.dispatch(spotifyActions.getAlbum(action.uri));
|
store.dispatch(spotifyActions.getAlbum(action.uri));
|
||||||
@ -391,6 +408,16 @@ const CoreMiddleware = (function(){
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'LOAD_ARTIST':
|
case 'LOAD_ARTIST':
|
||||||
|
|
||||||
|
if (
|
||||||
|
!action.force_reload &&
|
||||||
|
store.getState().core.artists[action.uri] &&
|
||||||
|
store.getState().core.artists[action.uri].albums_uris &&
|
||||||
|
store.getState().core.artists[action.uri].tracks_uris){
|
||||||
|
console.info('Loading "'+action.uri+'" from index');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (helpers.uriSource(action.uri)){
|
switch (helpers.uriSource(action.uri)){
|
||||||
case 'spotify':
|
case 'spotify':
|
||||||
store.dispatch(spotifyActions.getArtist(action.uri, true));
|
store.dispatch(spotifyActions.getArtist(action.uri, true));
|
||||||
@ -408,6 +435,15 @@ const CoreMiddleware = (function(){
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'LOAD_PLAYLIST':
|
case 'LOAD_PLAYLIST':
|
||||||
|
|
||||||
|
if (
|
||||||
|
!action.force_reload &&
|
||||||
|
store.getState().core.playlists[action.uri] &&
|
||||||
|
store.getState().core.playlists[action.uri].tracks_uris){
|
||||||
|
console.info('Loading "'+action.uri+'" from index');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (helpers.uriSource(action.uri)){
|
switch (helpers.uriSource(action.uri)){
|
||||||
case 'spotify':
|
case 'spotify':
|
||||||
store.dispatch(spotifyActions.getPlaylist(action.uri));
|
store.dispatch(spotifyActions.getPlaylist(action.uri));
|
||||||
@ -424,6 +460,46 @@ const CoreMiddleware = (function(){
|
|||||||
next(action);
|
next(action);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'LOAD_USER':
|
||||||
|
|
||||||
|
console.log(action);
|
||||||
|
|
||||||
|
if (
|
||||||
|
!action.force_reload &&
|
||||||
|
store.getState().core.playlists[action.uri] &&
|
||||||
|
store.getState().core.playlists[action.uri].albums_uris ){
|
||||||
|
console.info('Loading "'+action.uri+'" from index');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (helpers.uriSource(action.uri)){
|
||||||
|
case 'spotify':
|
||||||
|
store.dispatch(spotifyActions.getUser(action.uri));
|
||||||
|
store.dispatch(spotifyActions.following(action.uri));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// No Mopidy mechanism for users
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next(action);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'LOAD_USER_PLAYLISTS':
|
||||||
|
switch (helpers.uriSource(action.uri)){
|
||||||
|
case 'spotify':
|
||||||
|
store.dispatch(spotifyActions.getUserPlaylists(action.uri));
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// No Mopidy mechanism for users
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
next(action);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Index actions
|
* Index actions
|
||||||
@ -537,7 +613,9 @@ const CoreMiddleware = (function(){
|
|||||||
var playlists_loaded = [];
|
var playlists_loaded = [];
|
||||||
var tracks_loaded = [];
|
var tracks_loaded = [];
|
||||||
|
|
||||||
action.playlists.forEach(playlist => {
|
for (var playlist of action.playlists){
|
||||||
|
|
||||||
|
playlist = helpers.formatPlaylist(playlist);
|
||||||
|
|
||||||
// Detect editability
|
// Detect editability
|
||||||
switch (helpers.uriSource(playlist.uri)){
|
switch (helpers.uriSource(playlist.uri)){
|
||||||
@ -567,7 +645,7 @@ const CoreMiddleware = (function(){
|
|||||||
|
|
||||||
// Update index
|
// Update index
|
||||||
playlists_loaded.push(playlist);
|
playlists_loaded.push(playlist);
|
||||||
});
|
}
|
||||||
|
|
||||||
action.playlists = playlists_loaded;
|
action.playlists = playlists_loaded;
|
||||||
|
|
||||||
@ -581,20 +659,25 @@ const CoreMiddleware = (function(){
|
|||||||
var users_index = Object.assign({}, core.users);
|
var users_index = Object.assign({}, core.users);
|
||||||
var users_loaded = [];
|
var users_loaded = [];
|
||||||
|
|
||||||
action.users.forEach(user => {
|
for (var user of action.users){
|
||||||
|
|
||||||
if (users_index[user.uri]){
|
if (users_index[user.uri]){
|
||||||
user = Object.assign({}, users_index[user.uri], user);
|
user = Object.assign({}, users_index[user.uri], user);
|
||||||
}
|
}
|
||||||
|
|
||||||
users_loaded.push(user);
|
users_loaded.push(user);
|
||||||
});
|
}
|
||||||
|
|
||||||
action.users = users_loaded;
|
action.users = users_loaded;
|
||||||
|
|
||||||
next(action);
|
next(action);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'USER_PLAYLISTS_LOADED':
|
||||||
|
store.dispatch(coreActions.playlistsLoaded(action.playlists));
|
||||||
|
next(action);
|
||||||
|
break;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loaded more linked assets
|
* Loaded more linked assets
|
||||||
* Often fired during lazy-loading or async asset grabbing.
|
* Often fired during lazy-loading or async asset grabbing.
|
||||||
|
|||||||
@ -124,37 +124,37 @@ export default function reducer(core = {}, action){
|
|||||||
|
|
||||||
case 'TRACKS_LOADED':
|
case 'TRACKS_LOADED':
|
||||||
var tracks = Object.assign({}, core.tracks);
|
var tracks = Object.assign({}, core.tracks);
|
||||||
action.tracks.forEach(track => {
|
for (var track of action.tracks){
|
||||||
tracks[track.uri] = track;
|
tracks[track.uri] = track;
|
||||||
});
|
}
|
||||||
return Object.assign({}, core, { tracks: tracks });
|
return Object.assign({}, core, { tracks: tracks });
|
||||||
|
|
||||||
case 'ALBUMS_LOADED':
|
case 'ALBUMS_LOADED':
|
||||||
var albums = Object.assign({}, core.albums);
|
var albums = Object.assign({}, core.albums);
|
||||||
action.albums.forEach(album => {
|
for (var album of action.albums){
|
||||||
albums[album.uri] = album;
|
albums[album.uri] = album;
|
||||||
});
|
}
|
||||||
return Object.assign({}, core, { albums: albums });
|
return Object.assign({}, core, { albums: albums });
|
||||||
|
|
||||||
case 'ARTISTS_LOADED':
|
case 'ARTISTS_LOADED':
|
||||||
var artists = Object.assign({}, core.artists);
|
var artists = Object.assign({}, core.artists);
|
||||||
action.artists.forEach(artist => {
|
for (var artist of action.artists){
|
||||||
artists[artist.uri] = artist;
|
artists[artist.uri] = artist;
|
||||||
});
|
}
|
||||||
return Object.assign({}, core, { artists: artists });
|
return Object.assign({}, core, { artists: artists });
|
||||||
|
|
||||||
case 'PLAYLISTS_LOADED':
|
case 'PLAYLISTS_LOADED':
|
||||||
var playlists = Object.assign({}, core.playlists);
|
var playlists = Object.assign({}, core.playlists);
|
||||||
action.playlists.forEach(playlist => {
|
for (var playlist of action.playlists){
|
||||||
playlists[playlist.uri] = playlist;
|
playlists[playlist.uri] = playlist;
|
||||||
});
|
}
|
||||||
return Object.assign({}, core, { playlists: playlists });
|
return Object.assign({}, core, { playlists: playlists });
|
||||||
|
|
||||||
case 'USERS_LOADED':
|
case 'USERS_LOADED':
|
||||||
var users = Object.assign({}, core.users);
|
var users = Object.assign({}, core.users);
|
||||||
action.users.forEach(user => {
|
for (var user of action.users){
|
||||||
users[user.uri] = user;
|
users[user.uri] = user;
|
||||||
});
|
}
|
||||||
return Object.assign({}, core, { users: users });
|
return Object.assign({}, core, { users: users });
|
||||||
|
|
||||||
|
|
||||||
@ -167,8 +167,10 @@ export default function reducer(core = {}, action){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
var new_releases = []
|
var new_releases = [];
|
||||||
if (core.new_releases) new_releases = Object.assign([], core.new_releases)
|
if (core.new_releases){
|
||||||
|
new_releases = Object.assign([], core.new_releases);
|
||||||
|
}
|
||||||
|
|
||||||
return Object.assign({}, core, {
|
return Object.assign({}, core, {
|
||||||
new_releases: [...new_releases, ...action.uris],
|
new_releases: [...new_releases, ...action.uris],
|
||||||
@ -199,19 +201,23 @@ export default function reducer(core = {}, action){
|
|||||||
|
|
||||||
case 'USER_PLAYLISTS_LOADED':
|
case 'USER_PLAYLISTS_LOADED':
|
||||||
var users = Object.assign({}, core.users)
|
var users = Object.assign({}, core.users)
|
||||||
var playlists_uris = []
|
var existing_playlists_uris = [];
|
||||||
if (users[action.key] && users[action.key].playlists_uris) playlists_uris = users[action.key].playlists_uris
|
if (users[action.uri] && users[action.uri].playlists_uris){
|
||||||
|
existing_playlists_uris = users[action.uri].playlists_uris;
|
||||||
|
}
|
||||||
|
|
||||||
var artist = Object.assign(
|
var playlists_uris = [...existing_playlists_uris, ...helpers.arrayOf('uri',action.playlists)]
|
||||||
|
|
||||||
|
var user = Object.assign(
|
||||||
{},
|
{},
|
||||||
users[action.key],
|
users[action.uri],
|
||||||
{
|
{
|
||||||
playlists_uris: [...playlists_uris, ...action.uris],
|
playlists_uris: playlists_uris,
|
||||||
playlists_more: action.more,
|
playlists_more: action.more,
|
||||||
playlists_total: action.total
|
playlists_total: action.total
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
users[action.key] = artist
|
users[action.uri] = user;
|
||||||
return Object.assign({}, core, { users: users });
|
return Object.assign({}, core, { users: users });
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -239,10 +239,10 @@ export function getArtist(uri, artist, mbid = false){
|
|||||||
uri: uri,
|
uri: uri,
|
||||||
images: response.artist.image,
|
images: response.artist.image,
|
||||||
mbid: response.artist.mbid,
|
mbid: response.artist.mbid,
|
||||||
bio: response.artist.bio,
|
biography: response.artist.bio.content,
|
||||||
listeners: parseInt(response.artist.stats.listeners),
|
biography_publish_date: response.artist.bio.published,
|
||||||
play_count: parseInt(response.artist.stats.playcount),
|
biography_link: response.artist.bio.links.link.href,
|
||||||
on_tour: response.artist.stats.ontour
|
listeners: parseInt(response.artist.stats.listeners)
|
||||||
};
|
};
|
||||||
|
|
||||||
dispatch(coreActions.artistLoaded(artist));
|
dispatch(coreActions.artistLoaded(artist));
|
||||||
|
|||||||
@ -1750,26 +1750,43 @@ const MopidyMiddleware = (function(){
|
|||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.length <= 0) return
|
if (response.length <= 0) return
|
||||||
|
|
||||||
var albums = []
|
var albums_loaded = [];
|
||||||
|
var artists_loaded = [];
|
||||||
|
var tracks_loaded = [];
|
||||||
|
|
||||||
for (var uri in response){
|
for (var uri in response){
|
||||||
if (response.hasOwnProperty(uri) && response[uri].length > 0 && response[uri][0] && response[uri][0].album){
|
if (response.hasOwnProperty(uri) && response[uri].length > 0 && response[uri][0] && response[uri][0].album){
|
||||||
|
|
||||||
|
var artists_uris = [];
|
||||||
|
for (var artist in response[uri][0].artists){
|
||||||
|
artists_loaded.push(helpers.formatArtist(artist));
|
||||||
|
artists_uris.push(artist.uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
var tracks_uris = [];
|
||||||
|
for (var track in response[uri]){
|
||||||
|
tracks_loaded.push(helpers.formatTrack(track));
|
||||||
|
tracks_uris.push(track.uri);
|
||||||
|
}
|
||||||
|
|
||||||
var album = Object.assign(
|
var album = Object.assign(
|
||||||
{},
|
{},
|
||||||
{
|
{
|
||||||
source: 'local',
|
source: 'local',
|
||||||
artists: response[uri][0].artists,
|
artists_uris: artists_uris,
|
||||||
tracks: response[uri],
|
tracks_uris: tracks_uris,
|
||||||
tracks_total: response[uri].length
|
tracks_total: tracks_uris.length
|
||||||
},
|
},
|
||||||
response[uri][0].album
|
response[uri][0].album
|
||||||
)
|
)
|
||||||
|
|
||||||
albums.push(album)
|
albums_loaded.push(album);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(coreActions.albumsLoaded(albums));
|
store.dispatch(coreActions.albumsLoaded(albums_loaded));
|
||||||
|
store.dispatch(coreActions.artistsLoaded(artists_loaded));
|
||||||
|
store.dispatch(coreActions.tracksLoaded(tracks_loaded));
|
||||||
|
|
||||||
// Re-run any consequential processes in 100ms. This allows a small window for other
|
// Re-run any consequential processes in 100ms. This allows a small window for other
|
||||||
// server requests before our next batch. It's a little crude but it means the server isn't
|
// server requests before our next batch. It's a little crude but it means the server isn't
|
||||||
@ -1788,26 +1805,31 @@ const MopidyMiddleware = (function(){
|
|||||||
case 'MOPIDY_GET_ALBUM':
|
case 'MOPIDY_GET_ALBUM':
|
||||||
request(socket, store, 'library.lookup', action.data)
|
request(socket, store, 'library.lookup', action.data)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
if (response.length <= 0){
|
if (!response || response.length <= 0){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var artists = [];
|
||||||
|
for (var artist of response[0].artists){
|
||||||
|
artists.push(helpers.formatArtist(artist));
|
||||||
|
}
|
||||||
|
|
||||||
var album = Object.assign(
|
var album = Object.assign(
|
||||||
{},
|
{},
|
||||||
{ images: [] },
|
{
|
||||||
response[0].album,
|
images: []
|
||||||
|
},
|
||||||
|
helpers.formatAlbum(response[0].album),
|
||||||
{
|
{
|
||||||
source: 'local',
|
source: 'local',
|
||||||
artists: response[0].artists,
|
artists_uris: helpers.arrayOf('uri', artists),
|
||||||
tracks: response,
|
tracks_uris: helpers.arrayOf('uri', response),
|
||||||
tracks_total: response.length
|
tracks_total: response.length
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
var uris = [];
|
store.dispatch(coreActions.albumLoaded(album));
|
||||||
for(var i = 0; i < album.tracks.length; i++){
|
store.dispatch(coreActions.artistsLoaded(artists));
|
||||||
uris.push(album.tracks[i].uri );
|
|
||||||
}
|
|
||||||
|
|
||||||
// load artwork from LastFM
|
// load artwork from LastFM
|
||||||
if (album.images.length <= 0){
|
if (album.images.length <= 0){
|
||||||
@ -1819,29 +1841,17 @@ const MopidyMiddleware = (function(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
request(socket, store, 'library.lookup', { uris: uris } )
|
request(socket, store, 'library.lookup', { uris: album.tracks_uris } )
|
||||||
.then(response => {
|
.then(response => {
|
||||||
|
var tracks_loaded = [];
|
||||||
|
|
||||||
for(var uri in response){
|
for (var uri in response){
|
||||||
if (response.hasOwnProperty(uri)){
|
if (response.hasOwnProperty(uri)){
|
||||||
|
tracks_loaded.push(response[uri][0]);
|
||||||
var track = response[uri][0];
|
|
||||||
|
|
||||||
// find the track reference, and drop in the full track data
|
|
||||||
function getByURI(trackReference){
|
|
||||||
return track.uri == trackReference.uri
|
|
||||||
}
|
|
||||||
var trackReferences = album.tracks.filter(getByURI);
|
|
||||||
|
|
||||||
// there could be multiple instances of this track, so accommodate this
|
|
||||||
for(var j = 0; j < trackReferences.length; j++){
|
|
||||||
var key = album.tracks.indexOf(trackReferences[j] );
|
|
||||||
album.tracks[ key ] = track;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
store.dispatch(coreActions.albumLoaded(album));
|
store.dispatch(coreActions.tracksLoaded(tracks_loaded));
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
break;
|
break;
|
||||||
|
|||||||
@ -1229,17 +1229,12 @@ export function playArtistTopTracks(uri){
|
|||||||
* ======================================================================================
|
* ======================================================================================
|
||||||
**/
|
**/
|
||||||
|
|
||||||
export function getUser(uri, and_playlists = false){
|
export function getUser(uri){
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
|
sendRequest(dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri))
|
||||||
// get the user
|
|
||||||
sendRequest(dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri) )
|
|
||||||
.then(
|
.then(
|
||||||
response => {
|
response => {
|
||||||
dispatch({
|
dispatch(coreActions.userLoaded(helpers.formatUser(response)));
|
||||||
type: 'USERS_LOADED',
|
|
||||||
users: [response]
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
dispatch(coreActions.handleException(
|
dispatch(coreActions.handleException(
|
||||||
@ -1247,46 +1242,38 @@ export function getUser(uri, and_playlists = false){
|
|||||||
error
|
error
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
if (and_playlists){
|
|
||||||
dispatch(getUserPlaylists(uri));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getUserPlaylists(user_uri){
|
export function getUserPlaylists(uri){
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
|
|
||||||
// get the first page of playlists
|
// get the first page of playlists
|
||||||
sendRequest(dispatch, getState, 'users/'+ helpers.getFromUri('userid', user_uri) +'/playlists?limit=40' )
|
sendRequest(dispatch, getState, 'users/'+ helpers.getFromUri('userid', uri) +'/playlists?limit=40' )
|
||||||
.then(
|
.then(
|
||||||
response => {
|
response => {
|
||||||
var playlists = []
|
var playlists = [];
|
||||||
for (var i = 0; i < response.items.length; i++){
|
for (var raw_playlist of response.items){
|
||||||
|
|
||||||
var can_edit = false
|
var can_edit = false;
|
||||||
if (getState().spotify.me && response.items[i].owner.id == getState().spotify.me.id){
|
if (getState().spotify.me && raw_playlist.owner.id == getState().spotify.me.id){
|
||||||
can_edit = true
|
can_edit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
playlists.push(Object.assign(
|
var playlist = Object.assign(
|
||||||
{},
|
{},
|
||||||
response.items[i],
|
helpers.formatPlaylist(raw_playlist),
|
||||||
{
|
{
|
||||||
can_edit: can_edit,
|
can_edit: can_edit,
|
||||||
tracks_total: response.items[i].tracks.total
|
tracks_total: raw_playlist.tracks.total
|
||||||
}
|
}
|
||||||
))
|
);
|
||||||
|
|
||||||
|
playlists.push(playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch({
|
dispatch(coreActions.userPlaylistsLoaded(uri, playlists, response.more, response.total));
|
||||||
type: 'LOADED_MORE',
|
|
||||||
parent_type: 'user',
|
|
||||||
parent_key: user_uri,
|
|
||||||
records_type: 'playlist',
|
|
||||||
records_data: response
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
dispatch(coreActions.handleException(
|
dispatch(coreActions.handleException(
|
||||||
@ -1322,26 +1309,29 @@ export function getAlbum(uri){
|
|||||||
// dispatch our loaded artists (simple objects)
|
// dispatch our loaded artists (simple objects)
|
||||||
dispatch(coreActions.artistsLoaded(response.artists));
|
dispatch(coreActions.artistsLoaded(response.artists));
|
||||||
|
|
||||||
|
var tracks = Object.assign([], response.tracks.items);
|
||||||
|
|
||||||
var album = Object.assign(
|
var album = Object.assign(
|
||||||
{},
|
{},
|
||||||
response,
|
helpers.formatAlbum(response),
|
||||||
{
|
{
|
||||||
artists_uris: helpers.arrayOf('uri',response.artists),
|
artists_uris: helpers.arrayOf('uri',response.artists),
|
||||||
tracks: response.tracks.items,
|
tracks_uris: helpers.arrayOf('uri', tracks),
|
||||||
tracks_more: response.tracks.next,
|
tracks_more: response.tracks.next,
|
||||||
tracks_total: response.tracks.total
|
tracks_total: response.tracks.total
|
||||||
}
|
}
|
||||||
)
|
);
|
||||||
|
|
||||||
// add our album to all the tracks
|
// add our album to all the tracks
|
||||||
for (var i = 0; i < album.tracks.length; i++){
|
for (var i = 0; i < tracks.length; i++){
|
||||||
album.tracks[i].album = {
|
tracks[i].album = {
|
||||||
name: album.name,
|
name: album.name,
|
||||||
uri: album.uri
|
uri: album.uri
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dispatch(coreActions.albumLoaded(album));
|
dispatch(coreActions.albumLoaded(album));
|
||||||
|
dispatch(coreActions.tracksLoaded(tracks));
|
||||||
|
|
||||||
// now get all the artists for this album (full objects)
|
// now get all the artists for this album (full objects)
|
||||||
// we do this to get the artist artwork
|
// we do this to get the artist artwork
|
||||||
@ -1535,19 +1525,24 @@ export function getPlaylist(uri){
|
|||||||
description = description.split('<a href="spotify:user:').join('<a href="#'+global.baseURL+'user/spotify:user:')
|
description = description.split('<a href="spotify:user:').join('<a href="#'+global.baseURL+'user/spotify:user:')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var tracks = helpers.formatTracks(response.tracks.items);
|
||||||
|
|
||||||
var playlist = Object.assign(
|
var playlist = Object.assign(
|
||||||
{},
|
{},
|
||||||
response,
|
helpers.formatPlaylist(response),
|
||||||
{
|
{
|
||||||
is_completely_loaded: true,
|
is_completely_loaded: true,
|
||||||
can_edit: (getState().spotify.me && response.owner.id == getState().spotify.me.id),
|
can_edit: (getState().spotify.me && response.owner.id == getState().spotify.me.id),
|
||||||
tracks: helpers.formatTracks(response.tracks.items),
|
user_uri: response.owner.uri,
|
||||||
|
tracks_uris: helpers.arrayOf('uri', tracks),
|
||||||
tracks_more: response.tracks.next,
|
tracks_more: response.tracks.next,
|
||||||
tracks_total: response.tracks.total,
|
tracks_total: response.tracks.total,
|
||||||
description: description
|
description: description
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//dispatch(coreActions.userLoaded(helpers.formatUser(response.owner)));
|
||||||
|
dispatch(coreActions.tracksLoaded(tracks));
|
||||||
dispatch(coreActions.playlistLoaded(playlist));
|
dispatch(coreActions.playlistLoaded(playlist));
|
||||||
},
|
},
|
||||||
error => {
|
error => {
|
||||||
|
|||||||
@ -119,7 +119,7 @@ class Album extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var album = helpers.collateObject(this.props.album, {tracks: this.props.tracks, artists: this.props.artists});
|
var album = helpers.collate(this.props.album, {tracks: this.props.tracks, artists: this.props.artists});
|
||||||
|
|
||||||
if (album.tracks && album.tracks.length <= 0 && helpers.isLoading(this.props.load_queue,['spotify_albums/'+helpers.getFromUri('albumid',this.props.params.uri)])){
|
if (album.tracks && album.tracks.length <= 0 && helpers.isLoading(this.props.load_queue,['spotify_albums/'+helpers.getFromUri('albumid',this.props.params.uri)])){
|
||||||
var is_loading_tracks = true;
|
var is_loading_tracks = true;
|
||||||
@ -138,8 +138,8 @@ class Album extends React.Component{
|
|||||||
<h1>{album.name}</h1>
|
<h1>{album.name}</h1>
|
||||||
|
|
||||||
<ul className="details">
|
<ul className="details">
|
||||||
{!this.props.slim_mode ? <li className="has-tooltip"><Icon type="fontawesome" name={helpers.sourceIcon(this.props.params.uri )} /><span className="tooltip">{helpers.uriSource(this.props.params.uri )} {album.type ? album.type : 'album'}</span></li> : null}
|
{!this.props.slim_mode ? <li className="has-tooltip"><Icon type="fontawesome" name={helpers.sourceIcon(album.uri )} /><span className="tooltip">{helpers.uriSource(this.props.params.uri )} {album.type ? album.type : 'album'}</span></li> : null}
|
||||||
{!this.props.slim_mode && album.artists.length > 0 ? <li><ArtistSentence artists={album.artists} /></li> : null}
|
{!this.props.slim_mode && album.artists && album.artists.length > 0 ? <li><ArtistSentence artists={album.artists} /></li> : null}
|
||||||
{album.release_date ? <li><Dater type="date" data={album.release_date} /></li> : null}
|
{album.release_date ? <li><Dater type="date" data={album.release_date} /></li> : null}
|
||||||
<li>
|
<li>
|
||||||
{album.tracks ? <span>{album.tracks.length} tracks, <Dater type="total-time" data={album.tracks} /></span> : '0 tracks, 0 mins' }
|
{album.tracks ? <span>{album.tracks.length} tracks, <Dater type="total-time" data={album.tracks} /></span> : '0 tracks, 0 mins' }
|
||||||
|
|||||||
@ -33,15 +33,15 @@ class Artist extends React.Component{
|
|||||||
|
|
||||||
componentDidMount(){
|
componentDidMount(){
|
||||||
this.setWindowTitle();
|
this.setWindowTitle();
|
||||||
this.loadArtist();
|
this.props.coreActions.loadArtist(this.props.params.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps){
|
componentWillReceiveProps(nextProps){
|
||||||
if (nextProps.params.uri != this.props.params.uri){
|
if (nextProps.params.uri != this.props.params.uri){
|
||||||
this.loadArtist(nextProps);
|
this.props.coreActions.loadArtist(nextProps.params.uri);
|
||||||
}else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
|
}else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
|
||||||
if (helpers.uriSource(this.props.params.uri ) != 'spotify'){
|
if (helpers.uriSource(this.props.params.uri ) != 'spotify'){
|
||||||
this.loadArtist(nextProps);
|
this.props.coreActions.loadArtist(nextProps.params.uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,30 +72,6 @@ class Artist extends React.Component{
|
|||||||
this.props.uiActions.showContextMenu(data);
|
this.props.uiActions.showContextMenu(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
loadArtist(props = this.props){
|
|
||||||
switch(helpers.uriSource(props.params.uri )){
|
|
||||||
|
|
||||||
case 'spotify':
|
|
||||||
if (props.artist && props.artist.albums_uris && props.artist.related_artists_uris){
|
|
||||||
console.info('Loading spotify artist from index');
|
|
||||||
} else {
|
|
||||||
this.props.spotifyActions.getArtist(props.params.uri, true);
|
|
||||||
}
|
|
||||||
this.props.spotifyActions.following(props.params.uri);
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (props.mopidy_connected){
|
|
||||||
if (props.artist && props.artist.images && props.artist.albums_uris){
|
|
||||||
console.info('Loading local artist from index');
|
|
||||||
} else {
|
|
||||||
this.props.mopidyActions.getArtist(props.params.uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMore(){
|
loadMore(){
|
||||||
this.props.spotifyActions.getMore(
|
this.props.spotifyActions.getMore(
|
||||||
this.props.artist.albums_more,
|
this.props.artist.albums_more,
|
||||||
|
|||||||
@ -29,16 +29,16 @@ class Playlist extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount(){
|
componentDidMount(){
|
||||||
this.loadPlaylist();
|
|
||||||
this.setWindowTitle();
|
this.setWindowTitle();
|
||||||
|
this.props.coreActions.loadPlaylist(this.props.params.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps){
|
componentWillReceiveProps(nextProps){
|
||||||
if (nextProps.params.uri != this.props.params.uri){
|
if (nextProps.params.uri != this.props.params.uri){
|
||||||
this.loadPlaylist(nextProps);
|
this.props.coreActions.loadPlaylist(nextProps.params.uri);
|
||||||
} else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
|
} else if (!this.props.mopidy_connected && nextProps.mopidy_connected){
|
||||||
if (helpers.uriSource(this.props.params.uri) != 'spotify'){
|
if (helpers.uriSource(this.props.params.uri) != 'spotify'){
|
||||||
this.loadPlaylist(nextProps);
|
this.props.coreActions.loadPlaylist(nextProps.params.uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -59,28 +59,6 @@ class Playlist extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadPlaylist(props = this.props){
|
|
||||||
|
|
||||||
if (props.playlist && props.playlist.is_completely_loaded){
|
|
||||||
console.info('Loading playlist from index')
|
|
||||||
|
|
||||||
} else {
|
|
||||||
switch (helpers.uriSource(props.params.uri)){
|
|
||||||
|
|
||||||
case 'spotify':
|
|
||||||
this.props.spotifyActions.getPlaylist(props.params.uri);
|
|
||||||
this.props.spotifyActions.following(props.params.uri);
|
|
||||||
break
|
|
||||||
|
|
||||||
default:
|
|
||||||
if (props.mopidy_connected){
|
|
||||||
this.props.mopidyActions.getPlaylist(props.params.uri);
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMore(){
|
loadMore(){
|
||||||
this.props.spotifyActions.getMore(
|
this.props.spotifyActions.getMore(
|
||||||
this.props.playlist.tracks_more,
|
this.props.playlist.tracks_more,
|
||||||
@ -140,7 +118,7 @@ class Playlist extends React.Component{
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderActions(){
|
renderActions(){
|
||||||
switch(helpers.uriSource(this.props.playlist.uri )){
|
switch(helpers.uriSource(this.props.playlist.uri)){
|
||||||
|
|
||||||
case 'm3u':
|
case 'm3u':
|
||||||
return (
|
return (
|
||||||
@ -196,22 +174,14 @@ class Playlist extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var playlist = helpers.collate(this.props.playlist, {tracks: this.props.tracks, users: this.props.users});
|
||||||
|
|
||||||
var context = 'playlist';
|
var context = 'playlist';
|
||||||
if (this.props.playlist.can_edit){
|
if (playlist.can_edit){
|
||||||
context = 'editable-playlist';
|
context = 'editable-playlist';
|
||||||
}
|
}
|
||||||
|
|
||||||
var tracks = [];
|
if (playlist.tracks && playlist.tracks.length <= 0 && helpers.isLoading(this.props.load_queue,['spotify_users/'+user_id+'/playlists/'+playlist_id, 'spotify_users/'+user_id+'/playlists/'+playlist_id+'/tracks'])){
|
||||||
if (this.props.playlist.tracks_uris && this.props.tracks){
|
|
||||||
for (var i = 0; i < this.props.playlist.tracks_uris.length; i++){
|
|
||||||
var uri = this.props.playlist.tracks_uris[i]
|
|
||||||
if (this.props.tracks.hasOwnProperty(uri)){
|
|
||||||
tracks.push(this.props.tracks[uri])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tracks.length <= 0 && helpers.isLoading(this.props.load_queue,['spotify_users/'+user_id+'/playlists/'+playlist_id, 'spotify_users/'+user_id+'/playlists/'+playlist_id+'/tracks'])){
|
|
||||||
var is_loading_tracks = true;
|
var is_loading_tracks = true;
|
||||||
} else {
|
} else {
|
||||||
var is_loading_tracks = false;
|
var is_loading_tracks = false;
|
||||||
@ -220,21 +190,21 @@ class Playlist extends React.Component{
|
|||||||
return (
|
return (
|
||||||
<div className="view playlist-view content-wrapper">
|
<div className="view playlist-view content-wrapper">
|
||||||
<div className="thumbnail-wrapper">
|
<div className="thumbnail-wrapper">
|
||||||
<Thumbnail size="large" canZoom images={ this.props.playlist.images } />
|
<Thumbnail size="large" canZoom images={playlist.images} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="title">
|
<div className="title">
|
||||||
<h1>{ this.props.playlist.name }</h1>
|
<h1>{playlist.name}</h1>
|
||||||
{ this.props.playlist.description ? <h2 className="description grey-text" dangerouslySetInnerHTML={{__html: this.props.playlist.description}}></h2> : null }
|
{playlist.description ? <h2 className="description grey-text" dangerouslySetInnerHTML={{__html: playlist.description}}></h2> : null }
|
||||||
|
|
||||||
<ul className="details">
|
<ul className="details">
|
||||||
{ !this.props.slim_mode ? <li className="has-tooltip"><Icon type="fontawesome" name={helpers.sourceIcon(this.props.params.uri )} /><span className="tooltip">{helpers.uriSource(this.props.params.uri)} playlist</span></li> : null }
|
{!this.props.slim_mode ? <li className="has-tooltip"><Icon type="fontawesome" name={helpers.sourceIcon(playlist.uri)} /><span className="tooltip">{helpers.uriSource(playlist.uri)} playlist</span></li> : null }
|
||||||
{ this.props.playlist.owner && !this.props.slim_mode ? <li><URILink type="user" uri={this.props.playlist.owner.uri}>{this.props.playlist.owner.id}</URILink></li> : null }
|
{playlist.user_uri && !this.props.slim_mode ? <li><URILink type="user" uri={playlist.user_uri}>{playlist.user ? playlist.user.name : helpers.getFromUri('userid',playlist.user_uri)}</URILink></li> : null }
|
||||||
{ this.props.playlist.followers ? <li>{this.props.playlist.followers.total.toLocaleString()} followers</li> : null }
|
{playlist.followers ? <li>{playlist.followers.toLocaleString()} followers</li> : null }
|
||||||
{ this.props.playlist.last_modified ? <li>Edited <Dater type="ago" data={this.props.playlist.last_modified} /></li> : null }
|
{playlist.last_modified_date ? <li>Edited <Dater type="ago" data={playlist.last_modified_date} /></li> : null }
|
||||||
<li>
|
<li>
|
||||||
{ this.props.playlist.tracks_total ? this.props.playlist.tracks_total : tracks.length} tracks,
|
{playlist.tracks_total ? playlist.tracks_total : (playlist.tracks ? playlist.tracks.length : '0')} tracks,
|
||||||
<Dater type="total-time" data={tracks} />
|
<Dater type="total-time" data={playlist.tracks} />
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
@ -242,8 +212,8 @@ class Playlist extends React.Component{
|
|||||||
{ this.renderActions() }
|
{ this.renderActions() }
|
||||||
|
|
||||||
<section className="list-wrapper">
|
<section className="list-wrapper">
|
||||||
<TrackList uri={this.props.params.uri} className="playlist-track-list" context={context} tracks={tracks} removeTracks={ tracks_indexes => this.removeTracks(tracks_indexes) } reorderTracks={ (indexes, index) => this.reorderTracks(indexes, index) } />
|
<TrackList uri={playlist.uri} className="playlist-track-list" context={context} tracks={playlist.tracks} removeTracks={ tracks_indexes => this.removeTracks(tracks_indexes) } reorderTracks={ (indexes, index) => this.reorderTracks(indexes, index) } />
|
||||||
<LazyLoadListener loading={this.props.playlist.tracks_more} forceLoader={is_loading_tracks} loadMore={() => this.loadMore()}/>
|
<LazyLoadListener loading={playlist.tracks_more} forceLoader={is_loading_tracks} loadMore={() => this.loadMore()}/>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -263,6 +233,7 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
allow_reporting: state.ui.allow_reporting,
|
allow_reporting: state.ui.allow_reporting,
|
||||||
slim_mode: state.ui.slim_mode,
|
slim_mode: state.ui.slim_mode,
|
||||||
load_queue: state.ui.load_queue,
|
load_queue: state.ui.load_queue,
|
||||||
|
users: state.core.users,
|
||||||
tracks: state.core.tracks,
|
tracks: state.core.tracks,
|
||||||
playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : false ),
|
playlist: (state.core.playlists[uri] !== undefined ? state.core.playlists[uri] : false ),
|
||||||
spotify_library_playlists: state.spotify.library_playlists,
|
spotify_library_playlists: state.spotify.library_playlists,
|
||||||
|
|||||||
@ -25,12 +25,14 @@ class User extends React.Component{
|
|||||||
|
|
||||||
componentDidMount(){
|
componentDidMount(){
|
||||||
this.setWindowTitle();
|
this.setWindowTitle();
|
||||||
this.loadUser();
|
this.props.coreActions.loadUser(this.props.params.uri);
|
||||||
|
this.props.coreActions.loadUserPlaylists(this.props.params.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillReceiveProps(nextProps){
|
componentWillReceiveProps(nextProps){
|
||||||
if (nextProps.params.uri != this.props.params.uri){
|
if (nextProps.params.uri != this.props.params.uri){
|
||||||
this.loadUser(nextProps);
|
this.props.coreActions.loadUser(nextProps.params.uri);
|
||||||
|
this.props.coreActions.loadUserPlaylists(this.props.params.uri);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.props.user && nextProps.user){
|
if (!this.props.user && nextProps.user){
|
||||||
@ -46,13 +48,6 @@ class User extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadUser(props = this.props){
|
|
||||||
if (!props.user || props.user.playlists_uris === undefined){
|
|
||||||
this.props.spotifyActions.getUser(props.params.uri, true);
|
|
||||||
this.props.spotifyActions.following(props.params.uri);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadMore(){
|
loadMore(){
|
||||||
this.props.spotifyActions.getMore(
|
this.props.spotifyActions.getMore(
|
||||||
this.props.user.playlists_more,
|
this.props.user.playlists_more,
|
||||||
@ -84,37 +79,29 @@ class User extends React.Component{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var playlists = [];
|
var user = helpers.collate(this.props.user, {playlists: this.props.playlists});
|
||||||
if (this.props.user.playlists_uris){
|
|
||||||
for (var i = 0; i < this.props.user.playlists_uris.length; i++){
|
|
||||||
var uri = this.props.user.playlists_uris[i]
|
|
||||||
if (this.props.playlists.hasOwnProperty(uri)){
|
|
||||||
playlists.push(this.props.playlists[uri])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.user && this.props.user.images){
|
if (user && user.images){
|
||||||
var image = helpers.sizedImages(this.props.user.images).huge
|
var image = helpers.sizedImages(user.images).huge;
|
||||||
} else {
|
} else {
|
||||||
var image = null
|
var image = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="view user-view">
|
<div className="view user-view">
|
||||||
<div className="intro">
|
<div className="intro">
|
||||||
<Parallax image={image} />
|
<Parallax image={image} theme={this.props.theme} />
|
||||||
<div className="liner">
|
<div className="liner">
|
||||||
<h1>{ this.props.user.display_name ? this.props.user.display_name : this.props.user.id }</h1>
|
<h1>{user.name}</h1>
|
||||||
<h2>
|
<h2>
|
||||||
<ul className="details">
|
<ul className="details">
|
||||||
{this.props.user.playlists_total ? <li>{this.props.user.playlists_total ? this.props.user.playlists_total.toLocaleString() : 0} playlists</li> : null}
|
{user.playlists_total ? <li>{user.playlists_total ? user.playlists_total.toLocaleString() : 0} playlists</li> : null}
|
||||||
{this.props.user.followers ? <li>{this.props.user.followers.total.toLocaleString()} followers</li> : null}
|
{user.followers ? <li>{user.followers.toLocaleString()} followers</li> : null}
|
||||||
{this.isMe() ? <li><span className="blue-text">You</span></li> : null}
|
{this.isMe() ? <li><span className="blue-text">You</span></li> : null}
|
||||||
</ul>
|
</ul>
|
||||||
</h2>
|
</h2>
|
||||||
<div className="actions">
|
<div className="actions">
|
||||||
<FollowButton className="primary" uri={this.props.params.uri} addText="Follow" removeText="Unfollow" />
|
<FollowButton className="primary" uri={user.uri} addText="Follow" removeText="Unfollow" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -122,8 +109,8 @@ class User extends React.Component{
|
|||||||
<div className="content-wrapper">
|
<div className="content-wrapper">
|
||||||
<section className="grid-wrapper">
|
<section className="grid-wrapper">
|
||||||
<h4>Playlists</h4>
|
<h4>Playlists</h4>
|
||||||
<PlaylistGrid playlists={playlists} />
|
<PlaylistGrid playlists={user.playlists} />
|
||||||
<LazyLoadListener loading={this.props.user.playlists_more} loadMore={() => this.loadMore()} />
|
<LazyLoadListener loading={user.playlists_more} loadMore={() => this.loadMore()} />
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -134,9 +121,10 @@ class User extends React.Component{
|
|||||||
const mapStateToProps = (state, ownProps) => {
|
const mapStateToProps = (state, ownProps) => {
|
||||||
var uri = ownProps.params.uri;
|
var uri = ownProps.params.uri;
|
||||||
return {
|
return {
|
||||||
|
me: state.spotify.me,
|
||||||
|
theme: state.ui.theme,
|
||||||
load_queue: state.ui.load_queue,
|
load_queue: state.ui.load_queue,
|
||||||
spotify_authorized: state.spotify.authorization,
|
spotify_authorized: state.spotify.authorization,
|
||||||
me: state.spotify.me,
|
|
||||||
playlists: state.core.playlists,
|
playlists: state.core.playlists,
|
||||||
user: (state.core.users[uri] !== undefined ? state.core.users[uri] : false)
|
user: (state.core.users[uri] !== undefined ? state.core.users[uri] : false)
|
||||||
};
|
};
|
||||||
|
|||||||
@ -119,7 +119,7 @@ class DiscoverNewReleases extends React.Component{
|
|||||||
// Pull the first playlist out and we'll use this as a banner
|
// Pull the first playlist out and we'll use this as a banner
|
||||||
var first_album = albums.splice(0,1)
|
var first_album = albums.splice(0,1)
|
||||||
if (first_album){
|
if (first_album){
|
||||||
first_album = first_album[0]
|
first_album = helpers.collate(first_album[0], {artists: this.props.artists});
|
||||||
}
|
}
|
||||||
|
|
||||||
var options = (
|
var options = (
|
||||||
@ -155,6 +155,7 @@ const mapStateToProps = (state, ownProps) => {
|
|||||||
return {
|
return {
|
||||||
theme: state.ui.theme,
|
theme: state.ui.theme,
|
||||||
load_queue: state.ui.load_queue,
|
load_queue: state.ui.load_queue,
|
||||||
|
artists: state.core.artists,
|
||||||
albums: state.core.albums,
|
albums: state.core.albums,
|
||||||
new_releases: state.core.new_releases,
|
new_releases: state.core.new_releases,
|
||||||
new_releases_more: state.core.new_releases_more,
|
new_releases_more: state.core.new_releases_more,
|
||||||
|
|||||||
@ -11,11 +11,15 @@
|
|||||||
height: 0.5em;
|
height: 0.5em;
|
||||||
margin: 0.25em 1px;
|
margin: 0.25em 1px;
|
||||||
background: $light_grey;
|
background: $light_grey;
|
||||||
opacity: 0.25;
|
opacity: 0.2;
|
||||||
|
|
||||||
&.filled {
|
&.filled {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.light-theme & {
|
||||||
|
background: $darkest_grey;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,7 @@
|
|||||||
&:focus,
|
&:focus,
|
||||||
&:active {
|
&:active {
|
||||||
border-color: $turquoise;
|
border-color: $turquoise;
|
||||||
|
background: transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user