From 57c8a75df164228c185cea6b35200c146b64b1c2 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Wed, 25 Jan 2017 08:55:18 +1300 Subject: [PATCH 1/2] Loading artwork with getImages --- src/js/helpers.js | 16 ++-- src/js/services/mopidy/middleware.js | 25 ++++++ src/js/services/ui/reducer.js | 2 +- src/js/views/library/LibraryLocalAlbums.js | 97 ++++++++++++++++++++-- 4 files changed, 125 insertions(+), 15 deletions(-) diff --git a/src/js/helpers.js b/src/js/helpers.js index 495b5c0d..e24b8e42 100755 --- a/src/js/helpers.js +++ b/src/js/helpers.js @@ -12,9 +12,17 @@ export let sizedImages = function( images ){ if( images.length <= 0 ) return sizes; for( var i = 0; i < images.length; i++ ){ + + // Mopidy image object + if (typeof(images[i].__model__) !== 'undefined' && images[i].__model__ == 'Image'){ + sizes.small = images[i].uri + + // Mopidy image string + } else if (typeof(images[i]) == 'string'){ + sizes.small = images[i] // spotify-styled images - if( typeof(images[i].width) !== 'undefined' ){ + } else if (typeof(images[i].width) !== 'undefined'){ if( images[i].width < 400 ){ sizes.small = images[i].url; }else if( images[i].width < 800 ){ @@ -26,7 +34,7 @@ export let sizedImages = function( images ){ } // lastfm-styled images - }else if( typeof(images[i].size) !== 'undefined' ){ + } else if (typeof(images[i].size) !== 'undefined'){ switch( images[i].size ){ case 'mega': case 'extralarge': @@ -42,10 +50,6 @@ export let sizedImages = function( images ){ sizes.small = images[i]['#text'] break } - - // Mopidy-Images styled images - }else if( typeof(images[i]) == 'string' ){ - sizes.small = images[i] } } diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index f56a232f..21302975 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -547,14 +547,39 @@ const MopidyMiddleware = (function(){ case 'MOPIDY_GET_ALBUMS': instruct( socket, store, 'library.browse', { uri: 'local:directory?type=album' } ) .then( response => { + store.dispatch({ type: 'ALBUMS_LOADED', albums: response }); + store.dispatch({ type: 'LOCAL_ALBUMS_LOADED', uris: helpers.asURIs(response) }); + + // fetch album artwork + instruct( socket, store, 'library.getImages', { uris: helpers.asURIs(response) } ) + .then(response => { + + var albums = [] + + for (var uri in response){ + if (response.hasOwnProperty(uri)){ + albums.push({ + uri: uri, + images: response[uri] + }) + } + } + + console.log(albums) + + store.dispatch({ + type: 'ALBUMS_LOADED', + albums: albums + }); + }) }) break; diff --git a/src/js/services/ui/reducer.js b/src/js/services/ui/reducer.js index 2a734945..e42aed1b 100755 --- a/src/js/services/ui/reducer.js +++ b/src/js/services/ui/reducer.js @@ -198,7 +198,7 @@ export default function reducer(ui = {}, action){ for (var i = 0; i < action.albums.length; i++){ var album = action.albums[i] if (albums[album.uri]){ - artist = Object.assign({}, albums[album.uri], album) + album = Object.assign({}, albums[album.uri], album) } albums[album.uri] = album } diff --git a/src/js/views/library/LibraryLocalAlbums.js b/src/js/views/library/LibraryLocalAlbums.js index 5575806a..023fdd4f 100755 --- a/src/js/views/library/LibraryLocalAlbums.js +++ b/src/js/views/library/LibraryLocalAlbums.js @@ -3,9 +3,13 @@ import React, { PropTypes } from 'react' import { connect } from 'react-redux' import { bindActionCreators } from 'redux' +import AlbumGrid from '../../components/AlbumGrid' import Header from '../../components/Header' +import DropdownField from '../../components/DropdownField' import List from '../../components/List' +import * as helpers from '../../helpers' +import * as uiActions from '../../services/ui/actions' import * as mopidyActions from '../../services/mopidy/actions' import * as spotifyActions from '../../services/spotify/actions' @@ -20,17 +24,63 @@ class LibraryLocalAlbums extends React.Component{ } componentWillReceiveProps( nextProps ){ - if( !this.props.mopidy_connected && nextProps.mopidy_connected ){ + if (!this.props.mopidy_connected && nextProps.mopidy_connected){ this.loadAlbums(nextProps); } } loadAlbums(props = this.props){ - if( props.mopidy_connected ){ + if (props.mopidy_connected && !this.props.local_albums){ this.props.mopidyActions.getAlbums(); } } + setSort(value){ + var reverse = false + if( this.props.sort == value ) reverse = !this.props.sort_reverse + + var data = { + library_local_albums_sort_reverse: reverse, + library_local_albums_sort: value + } + this.props.uiActions.set(data) + } + + renderView(albums){ + if( this.props.view == 'list' ){ + + var columns = [ + { + label: 'Name', + name: 'name', + width: 40 + }, + { + label: 'Artists', + name: 'artists', + width: 30 + }, + { + label: 'Tracks', + name: 'tracks_total', + width: 15 + } + ] + + return ( +
+ +
+ ) + }else{ + return ( +
+ +
+ ) + } + } + render(){ var albums = [] if (this.props.albums && this.props.local_albums){ @@ -40,16 +90,43 @@ class LibraryLocalAlbums extends React.Component{ albums.push(this.props.albums[uri]) } } + + if( this.props.sort ){ + albums = helpers.sortItems(albums, this.props.sort, this.props.sort_reverse) + } } + var view_options = [ + { + value: 'thumbnails', + label: 'Thumbnails' + }, + { + value: 'list', + label: 'List' + } + ] + + var sort_options = [ + { + value: 'name', + label: 'Name' + } + ] + + var actions = ( + + this.setSort(val)} /> + this.props.uiActions.set({ library_local_albums_view: val })} /> + + ) + return (
-
-
- -
+
+ {this.renderView(albums)}
- ); + ) } } @@ -63,13 +140,17 @@ class LibraryLocalAlbums extends React.Component{ const mapStateToProps = (state, ownProps) => { return { mopidy_connected: state.mopidy.connected, + albums: state.ui.albums, local_albums: state.ui.local_albums, - albums: state.ui.albums + view: state.ui.library_local_albums_view, + sort: state.ui.library_local_albums_sort, + sort_reverse: state.ui.library_local_albums_sort_reverse } } const mapDispatchToProps = (dispatch) => { return { + uiActions: bindActionCreators(uiActions, dispatch), mopidyActions: bindActionCreators(mopidyActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch) } From 0d6a53948c308f900756872364a0bc34f140d744 Mon Sep 17 00:00:00 2001 From: James Barnsley Date: Thu, 26 Jan 2017 08:51:35 +1300 Subject: [PATCH 2/2] Lazy-loading local albums - allows us to fetch full data without killing server --- src/js/services/mopidy/actions.js | 11 ++++- src/js/services/mopidy/middleware.js | 54 +++++++++++++--------- src/js/views/library/LibraryLocalAlbums.js | 21 ++++++++- 3 files changed, 60 insertions(+), 26 deletions(-) diff --git a/src/js/services/mopidy/actions.js b/src/js/services/mopidy/actions.js index 1e42f4d7..48b48b09 100755 --- a/src/js/services/mopidy/actions.js +++ b/src/js/services/mopidy/actions.js @@ -199,9 +199,16 @@ export function getAlbum( uri ){ } } -export function getAlbums(){ +export function getAlbums( uris ){ return { - type: 'MOPIDY_GET_ALBUMS' + type: 'MOPIDY_GET_ALBUMS', + uris: uris + } +} + +export function getLocalAlbums(){ + return { + type: 'MOPIDY_GET_LOCAL_ALBUMS' } } diff --git a/src/js/services/mopidy/middleware.js b/src/js/services/mopidy/middleware.js index 21302975..205caa7e 100755 --- a/src/js/services/mopidy/middleware.js +++ b/src/js/services/mopidy/middleware.js @@ -544,42 +544,50 @@ const MopidyMiddleware = (function(){ * ====================================================================================== **/ - case 'MOPIDY_GET_ALBUMS': + case 'MOPIDY_GET_LOCAL_ALBUMS': instruct( socket, store, 'library.browse', { uri: 'local:directory?type=album' } ) .then( response => { + var uris = helpers.asURIs(response) + store.dispatch({ - type: 'ALBUMS_LOADED', - albums: response + type: 'MOPIDY_GET_ALBUMS', + uris: uris.slice(0,50) }); store.dispatch({ type: 'LOCAL_ALBUMS_LOADED', - uris: helpers.asURIs(response) + uris: uris }); + }) + break; - // fetch album artwork - instruct( socket, store, 'library.getImages', { uris: helpers.asURIs(response) } ) - .then(response => { + case 'MOPIDY_GET_ALBUMS': + instruct( socket, store, 'library.lookup', { uris: action.uris } ) + .then( response => { - var albums = [] + var albums = [] - for (var uri in response){ - if (response.hasOwnProperty(uri)){ - albums.push({ - uri: uri, - images: response[uri] - }) - } - } + for (var uri in response){ + if (response.hasOwnProperty(uri) && response[uri].length > 0 && response[uri][0] && response[uri][0].album ){ + var album = Object.assign( + {}, + { + artists: response[uri][0].artists, + tracks: response[uri], + tracks_total: response[uri].length + }, + response[uri][0].album + ) - console.log(albums) + albums.push(album) + } + } - store.dispatch({ - type: 'ALBUMS_LOADED', - albums: albums - }); - }) + store.dispatch({ + type: 'ALBUMS_LOADED', + albums: albums + }); }) break; @@ -679,7 +687,7 @@ const MopidyMiddleware = (function(){ var existingAlbum = albums.find(getByURI); if( !existingAlbum ){ albums.push(album) - } + } } } if (albums){ diff --git a/src/js/views/library/LibraryLocalAlbums.js b/src/js/views/library/LibraryLocalAlbums.js index 023fdd4f..33852112 100755 --- a/src/js/views/library/LibraryLocalAlbums.js +++ b/src/js/views/library/LibraryLocalAlbums.js @@ -7,6 +7,7 @@ import AlbumGrid from '../../components/AlbumGrid' import Header from '../../components/Header' import DropdownField from '../../components/DropdownField' import List from '../../components/List' +import LazyLoadListener from '../../components/LazyLoadListener' import * as helpers from '../../helpers' import * as uiActions from '../../services/ui/actions' @@ -31,10 +32,27 @@ class LibraryLocalAlbums extends React.Component{ loadAlbums(props = this.props){ if (props.mopidy_connected && !this.props.local_albums){ - this.props.mopidyActions.getAlbums(); + this.props.mopidyActions.getLocalAlbums(); } } + loadMore(){ + var uris = [] + if (this.props.albums && this.props.local_albums){ + for (var i = 0; i < this.props.local_albums.length; i++){ + var uri = this.props.local_albums[i] + if (!this.props.albums.hasOwnProperty(uri)){ + uris.push(uri) + } + + // limit each lookup to 50 URIs + if (uris.length >= 50) break + } + } + + if (uris && uris.length > 0) this.props.mopidyActions.getAlbums(uris) + } + setSort(value){ var reverse = false if( this.props.sort == value ) reverse = !this.props.sort_reverse @@ -125,6 +143,7 @@ class LibraryLocalAlbums extends React.Component{
{this.renderView(albums)} + this.loadMore() }/>
) }