Merge branch 'develop'
This commit is contained in:
@ -1 +1 @@
|
||||
3.13.0
|
||||
3.13.1
|
||||
@ -2,13 +2,15 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { createStore, bindActionCreators } from 'redux'
|
||||
import { hashHistory } from 'react-router'
|
||||
import FontAwesome from 'react-fontawesome'
|
||||
|
||||
import Thumbnail from './Thumbnail'
|
||||
import URILink from './URILink'
|
||||
import GridItem from './GridItem'
|
||||
|
||||
import * as helpers from '../helpers'
|
||||
import * as uiActions from '../services/ui/actions'
|
||||
import * as lastfmActions from '../services/lastfm/actions'
|
||||
|
||||
class ArtistGrid extends React.Component{
|
||||
|
||||
@ -40,22 +42,16 @@ class ArtistGrid extends React.Component{
|
||||
this.props.artists.map(
|
||||
(artist, index) => {
|
||||
return (
|
||||
<URILink
|
||||
className="grid-item"
|
||||
<GridItem
|
||||
key={artist.uri}
|
||||
type="artist"
|
||||
uri={artist.uri}
|
||||
key={index}
|
||||
onContextMenu={e => this.handleContextMenu(e,artist)}>
|
||||
<Thumbnail size="medium" images={artist.images} />
|
||||
<div className="name">
|
||||
{artist.name}
|
||||
</div>
|
||||
<div className="secondary">
|
||||
{this.props.show_source_icon ? <FontAwesome name={helpers.sourceIcon(artist.uri)} className="source" /> : null}
|
||||
{artist.followers ? artist.followers.total.toLocaleString()+' followers' : null}
|
||||
{artist.albums_uris && !artist.followers ? artist.albums_uris.length+' albums' : null}
|
||||
</div>
|
||||
</URILink>
|
||||
item={artist}
|
||||
show_source_icon={this.props.show_source_icon}
|
||||
onClick={e => {hashHistory.push(global.baseURL+'artist/'+encodeURIComponent(artist.uri))}}
|
||||
onLoad={() => this.handleLoad(artist.uri)}
|
||||
lastfmActions={this.props.lastfmActions}
|
||||
onContextMenu={e => this.handleContextMenu(e,artist)}
|
||||
/>
|
||||
)
|
||||
}
|
||||
)
|
||||
@ -73,7 +69,8 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
uiActions: bindActionCreators(uiActions, dispatch)
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
lastfmActions: bindActionCreators(lastfmActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -14,6 +14,16 @@ export default class GridItem extends React.Component{
|
||||
super(props)
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if (this.props.item && !this.props.item.images){
|
||||
switch (this.props.item.type){
|
||||
case 'artist':
|
||||
this.props.lastfmActions.getArtist(this.props.item.uri, this.props.item.name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
if (this.props.onClick && e.target.tagName.toLowerCase() !== 'a'){
|
||||
this.props.onClick(e)
|
||||
@ -27,7 +37,7 @@ export default class GridItem extends React.Component{
|
||||
}
|
||||
|
||||
shouldComponentUpdate(nextProps, nextState){
|
||||
return nextProps.item != this.props.item
|
||||
return nextProps.item != this.props.item;
|
||||
}
|
||||
|
||||
renderSecondary(item){
|
||||
@ -46,7 +56,8 @@ export default class GridItem extends React.Component{
|
||||
case 'artist':
|
||||
return (
|
||||
<span>
|
||||
{item.followers ? item.followers.total.toLocaleString()+' followers' : item.albums_uris.length+' albums'}
|
||||
{item.followers ? item.followers.total.toLocaleString()+' followers' : null}
|
||||
{item.albums_uris ? item.albums_uris.length+' albums' : null}
|
||||
</span>
|
||||
)
|
||||
break
|
||||
|
||||
@ -91,8 +91,8 @@ class Sidebar extends React.Component{
|
||||
<Link className={this.linkClassName('settings')} to={global.baseURL+"settings"}>
|
||||
<Icon name="cog" />
|
||||
Settings
|
||||
{this.props.test_mode ? <span className="has-tooltip right-tooltip pull-right"><FontAwesome name="info-circle" className="orange-text" /><span className="tooltip">Test mode active</span></span>: null}
|
||||
{!this.props.mopidy_connected || (!this.props.spotify_connected && this.props.spotify_enabled) || !this.props.pusher_connected ? <FontAwesome name="exclamation-triangle" className="red-text pull-right" /> : null}
|
||||
{this.props.test_mode ? <span className="status has-tooltip right-tooltip"><FontAwesome name="info-circle" className="orange-text" /><span className="tooltip">Test mode active</span></span>: null}
|
||||
{!this.props.mopidy_connected || (!this.props.spotify_connected && this.props.spotify_enabled) || !this.props.pusher_connected ? <span className="status has-tooltip right-tooltip"><FontAwesome name="exclamation-triangle" className="red-text" /><span className="tooltip">{!this.props.mopidy_connected ? <span>Mopidy not connected<br /></span> : null}{!this.props.pusher_connected ? <span>Pusher not connected<br /></span> : null}{!this.props.spotify_connected && this.props.spotify_enabled ? <span>Spotify not connected</span> : null}</span></span> : null}
|
||||
</Link>
|
||||
</section>
|
||||
|
||||
|
||||
@ -131,17 +131,13 @@ export let sizedImages = function(images){
|
||||
switch(image.size){
|
||||
case 'mega':
|
||||
case 'extralarge':
|
||||
sizes.huge = image['#text']
|
||||
break
|
||||
case 'large':
|
||||
sizes.large = image['#text']
|
||||
break
|
||||
case 'medium':
|
||||
sizes.medium = image['#text']
|
||||
break
|
||||
break;
|
||||
case 'medium':
|
||||
case 'small':
|
||||
sizes.small = image['#text']
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -224,11 +224,13 @@ export function getTrack(uri){
|
||||
}
|
||||
|
||||
export function getArtist(uri, artist, mbid = false){
|
||||
|
||||
return (dispatch, getState) => {
|
||||
if (mbid){
|
||||
var params = 'method=artist.getInfo&mbid='+mbid
|
||||
} else {
|
||||
artist = encodeURIComponent(artist );
|
||||
artist = artist.replace("&","and");
|
||||
artist = encodeURIComponent(artist);
|
||||
var params = 'method=artist.getInfo&artist='+artist
|
||||
}
|
||||
sendRequest(dispatch, getState, params)
|
||||
@ -240,6 +242,7 @@ export function getArtist(uri, artist, mbid = false){
|
||||
artist: {
|
||||
uri: uri,
|
||||
images: response.artist.image,
|
||||
mbid: response.artist.mbid,
|
||||
bio: response.artist.bio,
|
||||
listeners: parseInt(response.artist.stats.listeners),
|
||||
play_count: parseInt(response.artist.stats.playcount),
|
||||
|
||||
@ -1544,7 +1544,6 @@ const MopidyMiddleware = (function(){
|
||||
* =============================================================== ARTIST(S) ============
|
||||
* ======================================================================================
|
||||
**/
|
||||
|
||||
case 'MOPIDY_GET_LIBRARY_ARTISTS':
|
||||
instruct(socket, store, 'library.browse', { uri: 'local:directory?type=artist' } )
|
||||
.then(response => {
|
||||
@ -1555,15 +1554,13 @@ const MopidyMiddleware = (function(){
|
||||
store.dispatch({
|
||||
type: 'ARTISTS_LOADED',
|
||||
artists: response
|
||||
})
|
||||
});
|
||||
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_LIBRARY_ARTISTS_LOADED',
|
||||
uris: uris
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
});
|
||||
break;
|
||||
|
||||
/**
|
||||
@ -1571,7 +1568,6 @@ const MopidyMiddleware = (function(){
|
||||
*
|
||||
* We can't get specific artist artwork from Mopidy. Perhaps we fetch additional
|
||||
* artist metadata via LastFM? Their API limits will make this quite slow.
|
||||
*
|
||||
case 'MOPIDY_GET_LIBRARY_ARTISTS':
|
||||
|
||||
var last_run = store.getState().ui.processes.MOPIDY_LIBRARY_ARTISTS_PROCESSOR
|
||||
@ -1579,9 +1575,9 @@ const MopidyMiddleware = (function(){
|
||||
if (!last_run){
|
||||
instruct(socket, store, 'library.browse', { uri: 'local:directory?type=artist' } )
|
||||
.then(response => {
|
||||
if (response.length <= 0) return
|
||||
if (response.length <= 0) return;
|
||||
|
||||
var uris = helpers.arrayOf('uri',response)
|
||||
var uris = helpers.arrayOf('uri',response);
|
||||
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_LIBRARY_ARTISTS_LOADED',
|
||||
@ -1589,7 +1585,7 @@ const MopidyMiddleware = (function(){
|
||||
});
|
||||
|
||||
// Start our process to load the full album objects
|
||||
store.dispatch(uiActions.startProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR','Loading '+uris.length+' local artists', {uris: uris}))
|
||||
store.dispatch(uiActions.startProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR','Loading '+uris.length+' local artists', {uris: uris}));
|
||||
})
|
||||
|
||||
} else if (last_run.status == 'cancelled'){
|
||||
@ -1602,11 +1598,11 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
case 'MOPIDY_LIBRARY_ARTISTS_PROCESSOR':
|
||||
if (store.getState().ui.processes['MOPIDY_LIBRARY_ARTISTS_PROCESSOR'] !== undefined){
|
||||
var processor = store.getState().ui.processes['MOPIDY_LIBRARY_ARTISTS_PROCESSOR']
|
||||
var processor = store.getState().ui.processes['MOPIDY_LIBRARY_ARTISTS_PROCESSOR'];
|
||||
|
||||
if (processor.status == 'cancelling'){
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'))
|
||||
return false
|
||||
store.dispatch(uiActions.processCancelled('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1614,15 +1610,14 @@ const MopidyMiddleware = (function(){
|
||||
var uris_to_load = uris.splice(0,50)
|
||||
|
||||
if (uris_to_load.length > 0){
|
||||
store.dispatch(uiActions.updateProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR', 'Loading '+uris.length+' local artists', {uris: uris}))
|
||||
store.dispatch(mopidyActions.getArtists(uris_to_load, {name: 'MOPIDY_LIBRARY_ARTISTS_PROCESSOR', data: {uris: uris}}))
|
||||
store.dispatch(uiActions.updateProcess('MOPIDY_LIBRARY_ARTISTS_PROCESSOR', 'Loading '+uris.length+' local artists', {uris: uris}));
|
||||
store.dispatch(mopidyActions.getArtists(uris_to_load, {name: 'MOPIDY_LIBRARY_ARTISTS_PROCESSOR', data: {uris: uris}}));
|
||||
} else {
|
||||
store.dispatch(uiActions.processFinished('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'))
|
||||
store.dispatch(uiActions.processFinished('MOPIDY_LIBRARY_ARTISTS_PROCESSOR'));
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
*/
|
||||
break;
|
||||
**/
|
||||
|
||||
case 'MOPIDY_GET_ARTIST':
|
||||
instruct(socket, store, 'library.lookup', action.data )
|
||||
@ -1665,7 +1660,7 @@ const MopidyMiddleware = (function(){
|
||||
albums_uris: helpers.arrayOf('uri',albums),
|
||||
tracks: response.slice(0,10)
|
||||
}
|
||||
);
|
||||
);
|
||||
store.dispatch({
|
||||
type: 'ARTIST_LOADED',
|
||||
key: artist.uri,
|
||||
@ -1673,11 +1668,12 @@ const MopidyMiddleware = (function(){
|
||||
});
|
||||
|
||||
// load artwork from LastFM
|
||||
if (!artist.images || artist.images.length <= 0){
|
||||
var existing_artist = store.getState().core.artists[artist.uri];
|
||||
if (existing_artist && !existing_artist.images){
|
||||
if (artist.musicbrainz_id){
|
||||
store.dispatch(lastfmActions.getArtist(artist.uri, false, artist.musicbrainz_id ) )
|
||||
store.dispatch(lastfmActions.getArtist(artist.uri, false, artist.musicbrainz_id))
|
||||
} else {
|
||||
store.dispatch(lastfmActions.getArtist(artist.uri, artist.name.replace('&','and') ) )
|
||||
store.dispatch(lastfmActions.getArtist(artist.uri, artist.name))
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -1698,8 +1694,8 @@ const MopidyMiddleware = (function(){
|
||||
{
|
||||
is_mopidy: true
|
||||
}
|
||||
)
|
||||
artists.push(artist)
|
||||
);
|
||||
artists.push(artist);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -68,7 +68,7 @@ class Artist extends React.Component{
|
||||
|
||||
default:
|
||||
if (props.mopidy_connected){
|
||||
if (props.artist && props.artist.images){
|
||||
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);
|
||||
|
||||
@ -29,12 +29,12 @@ class LibraryArtists extends React.Component{
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if (this.props.mopidy_library_artists_status != 'finished' && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'local')){
|
||||
this.props.mopidyActions.getLibraryArtists()
|
||||
if (!this.props.mopidy_library_artists && this.props.mopidy_connected && (this.props.source == 'all' || this.props.source == 'local')){
|
||||
this.props.mopidyActions.getLibraryArtists();
|
||||
}
|
||||
|
||||
if (this.props.mopidy_uri_schemes.includes('spotify:') && this.props.spotify_library_artists_status != 'finished' && this.props.spotify_connected && (this.props.source == 'all' || this.props.source == 'spotify')){
|
||||
this.props.spotifyActions.getLibraryArtists()
|
||||
this.props.spotifyActions.getLibraryArtists();
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,12 +43,12 @@ class LibraryArtists extends React.Component{
|
||||
|
||||
// We've just connected
|
||||
if (!this.props.mopidy_connected){
|
||||
this.props.mopidyActions.getLibraryArtists()
|
||||
this.props.mopidyActions.getLibraryArtists();
|
||||
}
|
||||
|
||||
// Filter changed, but we haven't got this provider's library yet
|
||||
if (this.props.source != 'all' && this.props.source != 'local' && newProps.mopidy_library_artists_status != 'finished'){
|
||||
this.props.mopidyActions.getLibraryArtists()
|
||||
if (this.props.source != 'all' && this.props.source != 'local' && !newProps.mopidy_library_artists){
|
||||
this.props.mopidyActions.getLibraryArtists();
|
||||
}
|
||||
}
|
||||
|
||||
@ -56,12 +56,12 @@ class LibraryArtists extends React.Component{
|
||||
|
||||
// We've just connected
|
||||
if (!this.props.spotify_connected){
|
||||
this.props.spotifyActions.getLibraryArtists()
|
||||
this.props.spotifyActions.getLibraryArtists();
|
||||
}
|
||||
|
||||
// Filter changed, but we haven't got this provider's library yet
|
||||
if (this.props.source != 'all' && this.props.source != 'spotify' && newProps.spotify_library_artists_status != 'finished'){
|
||||
this.props.spotifyActions.getLibraryArtists()
|
||||
this.props.spotifyActions.getLibraryArtists();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -76,6 +76,11 @@ class LibraryArtists extends React.Component{
|
||||
this.props.uiActions.showContextMenu(data)
|
||||
}
|
||||
|
||||
loadMore(){
|
||||
console.log('Load more');
|
||||
this.setState({limit: this.state.limit + this.state.per_page});
|
||||
}
|
||||
|
||||
setSort(value){
|
||||
var reverse = false
|
||||
if (this.props.sort == value ) reverse = !this.props.sort_reverse
|
||||
@ -84,11 +89,11 @@ class LibraryArtists extends React.Component{
|
||||
library_artists_sort_reverse: reverse,
|
||||
library_artists_sort: value
|
||||
}
|
||||
this.props.uiActions.set(data)
|
||||
this.props.uiActions.set(data);
|
||||
}
|
||||
|
||||
renderView(){
|
||||
var artists = []
|
||||
var artists = [];
|
||||
|
||||
// Mopidy library items
|
||||
if (this.props.mopidy_library_artists && (this.props.source == 'all' || this.props.source == 'local')){
|
||||
@ -154,7 +159,7 @@ class LibraryArtists extends React.Component{
|
||||
columns={columns}
|
||||
className="artist-list"
|
||||
link_prefix={global.baseURL+"artist/"} />
|
||||
<LazyLoadListener loading={this.state.limit < total_artists} loadMore={() => this.setState({limit: this.state.limit + this.state.per_page})} />
|
||||
<LazyLoadListener loading={this.state.limit < total_artists} loadMore={() => this.loadMore()} />
|
||||
</section>
|
||||
)
|
||||
} else {
|
||||
@ -163,7 +168,7 @@ class LibraryArtists extends React.Component{
|
||||
<ArtistGrid
|
||||
handleContextMenu={(e,item) => this.handleContextMenu(e,item)}
|
||||
artists={artists} />
|
||||
<LazyLoadListener loading={this.state.limit < total_artists} loadMore={() => this.setState({limit: this.state.limit + this.state.per_page})} />
|
||||
<LazyLoadListener loading={this.state.limit < total_artists} loadMore={() => this.loadMore()} />
|
||||
</section>
|
||||
)
|
||||
}
|
||||
|
||||
@ -66,6 +66,11 @@ aside{
|
||||
}
|
||||
}
|
||||
|
||||
.status {
|
||||
margin-left: 5px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background: $turquoise;
|
||||
color: $white;
|
||||
|
||||
Reference in New Issue
Block a user