Mopidy artist
This commit is contained in:
@ -1,6 +1,9 @@
|
||||
RewriteEngine On
|
||||
|
||||
RewriteBase /
|
||||
|
||||
RewriteRule ^images/(.*)$ http://%{HTTP_HOST}:6680/images/$1 [NC,L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule . /index.html [L]
|
||||
|
||||
@ -3703,6 +3703,7 @@ main header h1 {
|
||||
.album-view .intro .thumbnail {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.album-view .intro .details {
|
||||
@ -3774,6 +3775,7 @@ main header h1 {
|
||||
.playlist-view .intro .thumbnail {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.playlist-view .intro .details {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,6 +1,11 @@
|
||||
RewriteEngine On
|
||||
|
||||
RewriteBase /
|
||||
|
||||
# Handle Mopidy-Images requests
|
||||
# TODO: Look to move this into the Thumbnail component
|
||||
RewriteRule ^images/(.*)$ http://%{HTTP_HOST}:6680/images/$1 [NC,L]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteCond %{REQUEST_FILENAME} !-d
|
||||
RewriteRule . /index.html [L]
|
||||
|
||||
@ -9,9 +9,12 @@ export let SizedImages = function( images ){
|
||||
huge: false
|
||||
}
|
||||
|
||||
if( images.length > 0 ){
|
||||
if( images.length <= 0 ) return sizes;
|
||||
|
||||
for( var i = 0; i < images.length; i++ ){
|
||||
for( var i = 0; i < images.length; i++ ){
|
||||
|
||||
// spotify-styled images
|
||||
if( images[i].height ){
|
||||
if( images[i].height > 800 ){
|
||||
sizes.huge = images[i].url;
|
||||
}else if( images[i].height > 600 ){
|
||||
@ -21,13 +24,17 @@ export let SizedImages = function( images ){
|
||||
}else{
|
||||
sizes.small = images[i].url;
|
||||
}
|
||||
}
|
||||
|
||||
if( !sizes.medium ) sizes.medium = sizes.small;
|
||||
if( !sizes.large ) sizes.large = sizes.medium;
|
||||
if( !sizes.huge ) sizes.huge = sizes.large;
|
||||
// Mopidy-Images styled images
|
||||
}else if( typeof(images[i]) == 'string' ){
|
||||
sizes.small = images[i]
|
||||
}
|
||||
}
|
||||
|
||||
if( !sizes.medium ) sizes.medium = sizes.small;
|
||||
if( !sizes.large ) sizes.large = sizes.medium;
|
||||
if( !sizes.huge ) sizes.huge = sizes.large;
|
||||
|
||||
return sizes;
|
||||
}
|
||||
|
||||
|
||||
@ -38,25 +38,25 @@ ReactDOM.render(
|
||||
<Route path="/" component={App}>
|
||||
|
||||
<IndexRoute component={Queue} />
|
||||
<Route path="/queue" component={Queue} />
|
||||
<Route path="queue" component={Queue} />
|
||||
|
||||
<Route path="/discover" component={Discover} />
|
||||
<Route path="/discover/featured" component={DiscoverFeatured} />
|
||||
<Route path="/discover/categories" component={DiscoverCategories} />
|
||||
<Route path="/discover/categories/:id" component={DiscoverCategory} />
|
||||
<Route path="/discover/new-releases" component={DiscoverNewReleases} />
|
||||
<Route path="discover" component={Discover} />
|
||||
<Route path="discover/featured" component={DiscoverFeatured} />
|
||||
<Route path="discover/categories" component={DiscoverCategories} />
|
||||
<Route path="discover/categories/:id" component={DiscoverCategory} />
|
||||
<Route path="discover/new-releases" component={DiscoverNewReleases} />
|
||||
|
||||
<Route path="/library/artists" component={LibraryArtists} />
|
||||
<Route path="/library/albums" component={LibraryAlbums} />
|
||||
<Route path="/library/tracks" component={LibraryTracks} />
|
||||
<Route path="/library/playlists" component={LibraryPlaylists} />
|
||||
<Route path="/library/local" component={LibraryLocal} />
|
||||
<Route path="/library/local/directory/:uri" component={LibraryLocalDirectory} />
|
||||
<Route path="library/artists" component={LibraryArtists} />
|
||||
<Route path="library/albums" component={LibraryAlbums} />
|
||||
<Route path="library/tracks" component={LibraryTracks} />
|
||||
<Route path="library/playlists" component={LibraryPlaylists} />
|
||||
<Route path="library/local" component={LibraryLocal} />
|
||||
<Route path="library/local/directory/:uri" component={LibraryLocalDirectory} />
|
||||
|
||||
<Route path="/album/:uri" component={Album} />
|
||||
<Route path="/artist/:uri" component={Artist} />
|
||||
<Route path="/playlist/:uri" component={Playlist} />
|
||||
<Route path="/settings" component={Settings} />
|
||||
<Route path="album/:uri" component={Album} />
|
||||
<Route path="artist/:uri" component={Artist} />
|
||||
<Route path="playlist/:uri" component={Playlist} />
|
||||
<Route path="settings" component={Settings} />
|
||||
|
||||
</Route>
|
||||
</Router>
|
||||
|
||||
@ -117,3 +117,10 @@ export function getAlbum( uri ){
|
||||
}
|
||||
}
|
||||
|
||||
export function getArtist( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_ARTIST',
|
||||
data: { uri: uri }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -199,6 +199,7 @@ const MopidyMiddleware = (function(){
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
var album = response[0].album;
|
||||
album.artists = response[0].artists;
|
||||
album.tracks = {
|
||||
items: response,
|
||||
total: response.length
|
||||
@ -236,6 +237,32 @@ const MopidyMiddleware = (function(){
|
||||
})
|
||||
break;
|
||||
|
||||
case 'MOPIDY_ARTIST':
|
||||
instruct( socket, store, 'library.lookup', action.data )
|
||||
.then( response => {
|
||||
var artist = {
|
||||
name: 'yeah',
|
||||
images: [],
|
||||
albums: [],
|
||||
tracks: response.slice(0,10)
|
||||
}
|
||||
|
||||
for( var i = 0; i < response.length; i++ ){
|
||||
var album = response[i].album;
|
||||
|
||||
function getByURI( albumToCheck ){
|
||||
return album.uri == albumToCheck.uri
|
||||
}
|
||||
var existingAlbum = artist.albums.find(getByURI);
|
||||
if( !existingAlbum ){
|
||||
artist.albums.push(album)
|
||||
}
|
||||
}
|
||||
|
||||
store.dispatch({ type: 'MOPIDY_ARTIST_LOADED', data: artist });
|
||||
})
|
||||
break;
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
|
||||
@ -87,6 +87,11 @@ export default function reducer(mopidy = {}, action){
|
||||
album: action.data
|
||||
});
|
||||
|
||||
case 'MOPIDY_ARTIST_LOADED':
|
||||
return Object.assign({}, mopidy, {
|
||||
artist: action.data
|
||||
});
|
||||
|
||||
default:
|
||||
return mopidy
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ class Album extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.loadAlbum();
|
||||
}
|
||||
@ -44,12 +43,11 @@ class Album extends React.Component{
|
||||
}
|
||||
}
|
||||
|
||||
totalTime(){
|
||||
if( !this.props.spotify.album ) return null
|
||||
var tracks = this.props.spotify.tracks.items;
|
||||
totalTime( tracks = [] ){
|
||||
var duration = 0;
|
||||
for( var i = 0; i < tracks.length; i++ ){
|
||||
duration += tracks[i].duration_ms;
|
||||
if( tracks[i].duration_ms ) duration += parseInt(tracks[i].duration_ms);
|
||||
if( tracks[i].length ) duration += parseInt(tracks[i].length);
|
||||
}
|
||||
return duration;
|
||||
}
|
||||
@ -63,11 +61,11 @@ class Album extends React.Component{
|
||||
return (
|
||||
<div className="view album-view">
|
||||
<div className="intro">
|
||||
<Thumbnail size="large" images={ album.images } />
|
||||
<Thumbnail size="large" images={ ( album.images ? album.images : [] ) } />
|
||||
<ArtistGrid artists={ album.artists } />
|
||||
<div className="details">
|
||||
<div>{ album.tracks.total } tracks, { this.totalTime }</div>
|
||||
<div>Released <Dater type="date" data={ album.release_date } /></div>
|
||||
<div>{ album.tracks.total } tracks, <Dater type="length" data={this.totalTime(album.tracks.items)} /> mins</div>
|
||||
{ album.release_date ? <div>Released <Dater type="date" data={ album.release_date } /></div> : null }
|
||||
</div>
|
||||
</div>
|
||||
<div className="main">
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
import React, { PropTypes } from 'react'
|
||||
import { connect } from 'react-redux'
|
||||
import { bindActionCreators } from 'redux'
|
||||
let helpers = require('../helpers.js')
|
||||
|
||||
import LazyLoadListener from '../components/LazyLoadListener'
|
||||
import Header from '../components/Header'
|
||||
@ -11,6 +12,7 @@ import Thumbnail from '../components/Thumbnail'
|
||||
import Parallax from '../components/Parallax'
|
||||
import ArtistList from '../components/ArtistList'
|
||||
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
|
||||
class Artist extends React.Component{
|
||||
@ -19,15 +21,26 @@ class Artist extends React.Component{
|
||||
super(props);
|
||||
}
|
||||
|
||||
// on render
|
||||
componentDidMount(){
|
||||
this.props.spotifyActions.getArtist( this.props.params.uri );
|
||||
this.loadArtist();
|
||||
}
|
||||
|
||||
// when props changed
|
||||
componentWillReceiveProps( nextProps ){
|
||||
if( nextProps.params.uri != this.props.params.uri ){
|
||||
this.props.spotifyActions.getArtist( nextProps.params.uri );
|
||||
this.loadArtist( nextProps )
|
||||
}else if( !this.props.mopidy.connected && nextProps.mopidy.connected ){
|
||||
if( helpers.uriSource( this.props.params.uri ) == 'local' ){
|
||||
this.loadArtist( nextProps )
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
loadArtist( props = this.props ){
|
||||
var source = helpers.uriSource( props.params.uri );
|
||||
if( source == 'spotify' ){
|
||||
this.props.spotifyActions.getArtist( props.params.uri );
|
||||
}else if( source == 'local' && props.mopidy.connected ){
|
||||
this.props.mopidyActions.getArtist( props.params.uri );
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,39 +49,79 @@ class Artist extends React.Component{
|
||||
this.props.spotifyActions.getURL( this.props.spotify.artist_albums.next, 'SPOTIFY_ARTIST_ALBUMS_LOADED_MORE' );
|
||||
}
|
||||
|
||||
render(){
|
||||
if( this.props.spotify.artist ){
|
||||
return (
|
||||
<div className="view artist-view">
|
||||
<Parallax images={ this.props.spotify.artist.images } />
|
||||
renderSpotifyAlbum(){
|
||||
if( !this.props.spotify.artist ) return null
|
||||
var artist = this.props.spotify.artist
|
||||
var albums = this.props.spotify.artist_albums
|
||||
|
||||
<div className="intro">
|
||||
<Thumbnail size="huge" images={ this.props.spotify.artist.images } />
|
||||
<h1>{ this.props.spotify.artist.name }</h1>
|
||||
<p>{ this.props.spotify.artist.followers.total.toLocaleString() } followers</p>
|
||||
</div>
|
||||
return (
|
||||
<div className="view artist-view">
|
||||
<Parallax images={ artist.images } />
|
||||
|
||||
<div className="col w70">
|
||||
<h4 className="left-padding">Top tracks</h4>
|
||||
{ this.props.spotify.artist.tracks ? <TrackList tracks={ this.props.spotify.artist.tracks } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="col w5"></div>
|
||||
|
||||
<div className="col w25">
|
||||
<h4>Related artists</h4>
|
||||
{ this.props.spotify.artist.related_artists ? <ArtistList artists={ this.props.spotify.artist.related_artists.slice(0,6) } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="cf"></div>
|
||||
|
||||
<h4 className="left-padding">Albums</h4>
|
||||
{ this.props.spotify.artist_albums ? <AlbumGrid className="no-top-padding" albums={ this.props.spotify.artist_albums.items } /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
<div className="intro">
|
||||
<Thumbnail size="huge" images={ artist.images } />
|
||||
<h1>{ artist.name }</h1>
|
||||
<p>{ artist.followers.total.toLocaleString() } followers</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
||||
<div className="col w70">
|
||||
<h4 className="left-padding">Top tracks</h4>
|
||||
{ artist.tracks ? <TrackList tracks={ artist.tracks } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="col w5"></div>
|
||||
|
||||
<div className="col w25">
|
||||
<h4>Related artists</h4>
|
||||
{ artist.related_artists ? <ArtistList artists={ artist.related_artists.slice(0,6) } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="cf"></div>
|
||||
|
||||
<h4 className="left-padding">Albums</h4>
|
||||
{ albums ? <AlbumGrid className="no-top-padding" albums={ albums.items } /> : null }
|
||||
<LazyLoadListener loadMore={ () => this.loadMore() }/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
renderMopidyAlbum(){
|
||||
if( !this.props.mopidy.artist ) return null
|
||||
var artist = this.props.mopidy.artist
|
||||
|
||||
return (
|
||||
<div className="view artist-view">
|
||||
<Parallax images={ artist.images } />
|
||||
|
||||
<div className="intro">
|
||||
<Thumbnail size="huge" images={ artist.images } />
|
||||
<h1>{ artist.name }</h1>
|
||||
</div>
|
||||
|
||||
<div className="col w70">
|
||||
<h4 className="left-padding">Top tracks</h4>
|
||||
{ artist.tracks ? <TrackList tracks={ artist.tracks } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="col w5"></div>
|
||||
|
||||
<div className="col w25">
|
||||
<h4>Related artists</h4>
|
||||
{ artist.related_artists ? <ArtistList artists={ artist.artist.related_artists.slice(0,6) } /> : null }
|
||||
</div>
|
||||
|
||||
<div className="cf"></div>
|
||||
|
||||
<h4 className="left-padding">Albums</h4>
|
||||
{ artist.albums ? <AlbumGrid className="no-top-padding" albums={ artist.albums } /> : null }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
render(){
|
||||
var source = helpers.uriSource( this.props.params.uri );
|
||||
if( source == 'spotify' ) return this.renderSpotifyAlbum()
|
||||
if( source == 'local' ) return this.renderMopidyAlbum()
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,6 +138,7 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
.thumbnail {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.details {
|
||||
|
||||
@ -26,6 +26,7 @@
|
||||
.thumbnail {
|
||||
float: none;
|
||||
margin: 0 auto;
|
||||
max-width: none;
|
||||
}
|
||||
|
||||
.details {
|
||||
|
||||
Reference in New Issue
Block a user