Current track images to use Mopidy-Spotify so no immediate dependency on Spotify HTTP API
This commit is contained in:
@ -101,7 +101,6 @@ class App extends React.Component{
|
||||
// Listen for standalone key codes
|
||||
let keyCodes = [27,32,191]
|
||||
if (keyCodes.indexOf(e.keyCode) > -1){
|
||||
if (keyCode == 37)
|
||||
e.preventDefault()
|
||||
return true
|
||||
}
|
||||
|
||||
@ -24,8 +24,8 @@ export default class KioskModeModal extends React.Component{
|
||||
}
|
||||
|
||||
render(){
|
||||
if (this.props.current_track && this.props.current_track.album && this.props.current_track.album.images){
|
||||
var images = this.props.current_track.album.images
|
||||
if (this.props.current_track && this.props.current_track.images){
|
||||
var images = this.props.current_track.images
|
||||
} else {
|
||||
var images = []
|
||||
}
|
||||
|
||||
@ -75,8 +75,8 @@ class PlaybackControls extends React.Component{
|
||||
|
||||
render(){
|
||||
var images = false
|
||||
if (this.props.current_track && this.props.current_track.album && this.props.current_track.album.images){
|
||||
images = this.props.current_track.album.images
|
||||
if (this.props.current_track && this.props.current_track.images){
|
||||
images = this.props.current_track.images
|
||||
}
|
||||
|
||||
return (
|
||||
|
||||
@ -13,50 +13,67 @@ export let sizedImages = function( images ){
|
||||
huge: false
|
||||
}
|
||||
|
||||
if( images.length <= 0 ) return sizes;
|
||||
if (images.length <= 0) return sizes;
|
||||
|
||||
for (var i = 0; i < images.length; i++){
|
||||
let image = images[i]
|
||||
|
||||
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
|
||||
if (image.__model__ && image.__model__ == 'Image'){
|
||||
|
||||
if (image.width < 400){
|
||||
sizes.small = image.url;
|
||||
}else if (image.width < 800){
|
||||
sizes.medium = image.url;
|
||||
}else if (image.width < 1000){
|
||||
sizes.large = image.url;
|
||||
}else{
|
||||
sizes.huge = image.url;
|
||||
}
|
||||
|
||||
// Mopidy image string
|
||||
} else if (typeof(images[i]) == 'string'){
|
||||
sizes.small = images[i]
|
||||
|
||||
} else if (typeof(image) == 'string'){
|
||||
sizes.small = image
|
||||
|
||||
// spotify-styled images
|
||||
} else if (typeof(images[i].width) !== 'undefined'){
|
||||
if( images[i].width < 400 ){
|
||||
sizes.small = images[i].url;
|
||||
}else if( images[i].width < 800 ){
|
||||
sizes.medium = images[i].url;
|
||||
}else if( images[i].width < 1000 ){
|
||||
sizes.large = images[i].url;
|
||||
} else if (image.width !== undefined){
|
||||
|
||||
if (image.width < 400){
|
||||
sizes.small = image.url;
|
||||
}else if (image.width < 800){
|
||||
sizes.medium = image.url;
|
||||
}else if (image.width < 1000){
|
||||
sizes.large = image.url;
|
||||
}else{
|
||||
sizes.huge = images[i].url;
|
||||
sizes.huge = image.url;
|
||||
}
|
||||
|
||||
// lastfm-styled images
|
||||
} else if (typeof(images[i].size) !== 'undefined'){
|
||||
switch( images[i].size ){
|
||||
} else if (image.size !== undefined){
|
||||
switch( image.size ){
|
||||
case 'mega':
|
||||
case 'extralarge':
|
||||
sizes.huge = images[i]['#text']
|
||||
sizes.huge = image['#text']
|
||||
break
|
||||
case 'large':
|
||||
sizes.large = images[i]['#text']
|
||||
sizes.large = image['#text']
|
||||
break
|
||||
case 'medium':
|
||||
sizes.medium = images[i]['#text']
|
||||
sizes.medium = image['#text']
|
||||
break
|
||||
case 'small':
|
||||
sizes.small = images[i]['#text']
|
||||
sizes.small = image['#text']
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!sizes.small){
|
||||
if (sizes.medium) sizes.small = sizes.medium
|
||||
else if (sizes.large) sizes.small = sizes.large
|
||||
else if (sizes.huge) sizes.small = sizes.huge
|
||||
else sizes.small = null
|
||||
}
|
||||
if (!sizes.medium){
|
||||
if (sizes.large) sizes.medium = sizes.large
|
||||
else if (sizes.huge) sizes.medium = sizes.huge
|
||||
@ -68,6 +85,41 @@ export let sizedImages = function( images ){
|
||||
return sizes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Digest an array of Mopidy image objects into a universal format
|
||||
*
|
||||
* @param mopidy = obj (mopidy store object)
|
||||
* @param images = array
|
||||
* @return array
|
||||
**/
|
||||
export let digestMopidyImages = function(mopidy, images){
|
||||
let digested = []
|
||||
|
||||
for (let i = 0; i < images.length; i++){
|
||||
|
||||
// Accommodate backends that provide URIs vs URLs
|
||||
let url = images[i].url
|
||||
if (!url && images[i].uri){
|
||||
url = images[i].uri
|
||||
}
|
||||
/*
|
||||
// Replace local images to point directly to our Mopidy server
|
||||
if (url.startsWith('/images/')){
|
||||
url = '//'+mopidy.host+':'+mopidy.port+url
|
||||
}
|
||||
*/
|
||||
|
||||
// Amend our URL
|
||||
images[i].url = url
|
||||
|
||||
digested.push(images[i])
|
||||
}
|
||||
|
||||
return digested
|
||||
}
|
||||
|
||||
|
||||
export let generateGuid = function(format = 'xxxxxxxxxxxx'){
|
||||
return format.replace(/[xy]/g, function(c) {
|
||||
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
|
||||
@ -75,7 +127,6 @@ export let generateGuid = function(format = 'xxxxxxxxxxxx'){
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export let getCurrentPusherConnection = function( connections, connectionid ){
|
||||
function isCurrentConnection(connection){
|
||||
return connection.connectionid == newProps.pusher.connectionid;
|
||||
@ -93,15 +144,14 @@ export let getCurrentPusherConnection = function( connections, connectionid ){
|
||||
* @param track object
|
||||
* @return string
|
||||
**/
|
||||
export let getTrackIcon = function(current_track = false, ui = false){
|
||||
if (!ui) return false
|
||||
export let getTrackIcon = function(current_track = false, core = false){
|
||||
if (!core) return false
|
||||
if (!current_track) return false
|
||||
if (typeof(current_track.uri) == 'undefined') return false
|
||||
if (typeof(core.tracks[current_track.uri]) === 'undefined') return false
|
||||
var track = core.tracks[current_track.uri]
|
||||
if (!track.album) return false
|
||||
if (!track.album.images) return false
|
||||
return sizedImages(track.album.images).small
|
||||
if (!track.images) return false
|
||||
return sizedImages(track.images).small
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -24,16 +24,6 @@ const CoreMiddleware = (function(){
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'MOPIDY_CONNECTED':
|
||||
ReactGA.event({ category: 'Mopidy', action: 'Connected', label: window.location.hostname })
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'PUSHER_CONNECTED':
|
||||
ReactGA.event({ category: 'Pusher', action: 'Connected', label: action.username })
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'ALBUM_LOADED':
|
||||
if (action.data) ReactGA.event({ category: 'Album', action: 'Load', label: action.album.uri })
|
||||
|
||||
@ -75,11 +65,6 @@ const CoreMiddleware = (function(){
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'MOPIDY_DIRECTORY':
|
||||
if (action.data) ReactGA.event({ category: 'Directory', action: 'Load', label: action.data.uri })
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'PLAY_PLAYLIST':
|
||||
ReactGA.event({ category: 'Playlist', action: 'Play', label: action.uri })
|
||||
next(action)
|
||||
|
||||
@ -164,6 +164,14 @@ export function setTimePosition(time_position){
|
||||
* Asset-oriented actions
|
||||
**/
|
||||
|
||||
export function getImages( context, uris ){
|
||||
return {
|
||||
type: 'MOPIDY_GET_IMAGES',
|
||||
context: context,
|
||||
uris: uris
|
||||
}
|
||||
}
|
||||
|
||||
export function deletePlaylist( uri ){
|
||||
return {
|
||||
type: 'MOPIDY_DELETE_PLAYLIST',
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
|
||||
import ReactGA from 'react-ga'
|
||||
import Mopidy from 'mopidy'
|
||||
import { hashHistory } from 'react-router'
|
||||
import * as helpers from '../../helpers'
|
||||
@ -192,6 +193,11 @@ const MopidyMiddleware = (function(){
|
||||
socket.on( (type, data) => handleMessage( socket, store, type, data ) )
|
||||
break
|
||||
|
||||
case 'MOPIDY_CONNECTED':
|
||||
ReactGA.event({ category: 'Mopidy', action: 'Connected', label: window.location.hostname })
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'MOPIDY_DISCONNECT':
|
||||
if(socket != null) socket.close()
|
||||
socket = null
|
||||
@ -238,7 +244,7 @@ const MopidyMiddleware = (function(){
|
||||
type: 'browser_notification',
|
||||
title: 'Track skipped',
|
||||
body: store.getState().pusher.username +' skipped this track',
|
||||
icon: (store.getState().core.current_track ? helpers.getTrackIcon(store.getState().core.current_track, store.getState().ui) : false)
|
||||
icon: (store.getState().core.current_track ? helpers.getTrackIcon(store.getState().core.current_track, store.getState().core) : false)
|
||||
}
|
||||
store.dispatch( pusherActions.deliverBroadcast(data) )
|
||||
break
|
||||
@ -248,7 +254,7 @@ const MopidyMiddleware = (function(){
|
||||
type: 'browser_notification',
|
||||
title: 'Playback stopped',
|
||||
body: store.getState().pusher.username +' stopped playback',
|
||||
icon: (store.getState().core.current_track ? helpers.getTrackIcon(store.getState().core.current_track, store.getState().ui) : false)
|
||||
icon: (store.getState().core.current_track ? helpers.getTrackIcon(store.getState().core.current_track, store.getState().core) : false)
|
||||
}
|
||||
store.dispatch( pusherActions.deliverBroadcast(data) )
|
||||
break
|
||||
@ -400,13 +406,6 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
break
|
||||
|
||||
case 'CANCEL_PROCESS':
|
||||
if (action.key == 'MOPIDY_ENQUEUE_URIS'){
|
||||
store.dispatch(mopidyActions.enqueueURIsCancel())
|
||||
}
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'MOPIDY_PLAY_URIS':
|
||||
|
||||
// Stop the radio
|
||||
@ -1033,17 +1032,49 @@ const MopidyMiddleware = (function(){
|
||||
// Fire off our universal track index loader
|
||||
store.dispatch({ type: 'TRACK_LOADED', key: action.data.track.uri, track: action.data.track })
|
||||
|
||||
// When current track is Spotify track, go get the full object
|
||||
// This is because Mopidy doesn't give us full artist/album objects, without artwork
|
||||
if (action.data.track.uri.substring(0,14) == 'spotify:track:'){
|
||||
store.dispatch( spotifyActions.getTrack( action.data.track.uri ) )
|
||||
}
|
||||
// Get me some images
|
||||
store.dispatch(mopidyActions.getImages('tracks',[action.data.track.uri]))
|
||||
}
|
||||
|
||||
next(action)
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* =============================================================== IMAGES ===============
|
||||
* ======================================================================================
|
||||
**/
|
||||
|
||||
case 'MOPIDY_GET_IMAGES':
|
||||
|
||||
instruct( socket, store, 'library.getImages', {uris: action.uris})
|
||||
.then( response => {
|
||||
|
||||
let records = []
|
||||
for (var uri in response){
|
||||
if (response.hasOwnProperty(uri)){
|
||||
|
||||
let images = response[uri]
|
||||
images = helpers.digestMopidyImages(store.getState().mopidy, images)
|
||||
|
||||
records.push({
|
||||
uri: uri,
|
||||
images: images
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let action_data = {
|
||||
type: (action.context+'_LOADED').toUpperCase()
|
||||
}
|
||||
action_data[action.context] = records
|
||||
store.dispatch(action_data)
|
||||
})
|
||||
|
||||
next(action)
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* =============================================================== LOCAL ================
|
||||
* ======================================================================================
|
||||
@ -1060,6 +1091,11 @@ const MopidyMiddleware = (function(){
|
||||
})
|
||||
break
|
||||
|
||||
case 'MOPIDY_DIRECTORY':
|
||||
if (action.data) ReactGA.event({ category: 'Directory', action: 'Load', label: action.data.uri })
|
||||
next(action)
|
||||
break
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action)
|
||||
|
||||
@ -98,6 +98,7 @@ const PusherMiddleware = (function(){
|
||||
break;
|
||||
|
||||
case 'PUSHER_CONNECTED':
|
||||
ReactGA.event({ category: 'Pusher', action: 'Connected', label: action.username })
|
||||
request(store, 'get_config')
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -123,6 +123,13 @@ const UIMiddleware = (function(){
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'CANCEL_PROCESS':
|
||||
if (action.key == 'MOPIDY_ENQUEUE_URIS'){
|
||||
store.dispatch(mopidyActions.enqueueURIsCancel())
|
||||
}
|
||||
next(action)
|
||||
break
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action)
|
||||
|
||||
@ -64,7 +64,7 @@ class Queue extends React.Component{
|
||||
return (
|
||||
<span className={this.props.radio_enabled ? 'artwork radio-enabled' : 'artwork'}>
|
||||
{this.props.radio_enabled ? <img className="radio-overlay" src="assets/radio-overlay.png" /> : null}
|
||||
<Thumbnail size="huge" />
|
||||
<Thumbnail />
|
||||
</span>
|
||||
)
|
||||
}
|
||||
@ -74,15 +74,16 @@ class Queue extends React.Component{
|
||||
return (
|
||||
<Link className={this.props.radio_enabled ? 'artwork radio-enabled' : 'artwork'} to={link}>
|
||||
{this.props.radio_enabled ? <img className="radio-overlay" src="assets/radio-overlay.png" /> : null}
|
||||
<Thumbnail size="huge" image={image} />
|
||||
<Thumbnail image={image} />
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
render(){
|
||||
var image = null
|
||||
if (this.props.current_track && this.props.current_track.album !== undefined && this.props.current_track.album.images){
|
||||
image = helpers.sizedImages(this.props.current_track.album.images).huge
|
||||
if (this.props.current_track && this.props.current_track.images !== undefined){
|
||||
image = helpers.sizedImages(this.props.current_track.images)
|
||||
image = image.large
|
||||
}
|
||||
|
||||
var options = (
|
||||
|
||||
@ -16,6 +16,7 @@ import LazyLoadListener from '../components/LazyLoadListener'
|
||||
import SearchForm from '../components/SearchForm'
|
||||
|
||||
import * as helpers from '../helpers'
|
||||
import * as coreActions from '../services/core/actions'
|
||||
import * as uiActions from '../services/ui/actions'
|
||||
import * as mopidyActions from '../services/mopidy/actions'
|
||||
import * as spotifyActions from '../services/spotify/actions'
|
||||
@ -30,7 +31,7 @@ class Search extends React.Component{
|
||||
|
||||
// Make sure we have search parameters to start with
|
||||
if (this.props.params && this.props.params.type && this.props.params.query){
|
||||
this.props.uiActions.startSearch(this.props.params.type, this.props.params.query)
|
||||
this.props.coreActions.startSearch(this.props.params.type, this.props.params.query)
|
||||
}
|
||||
|
||||
// Auto-focus on the input field
|
||||
@ -43,12 +44,12 @@ class Search extends React.Component{
|
||||
if (newProps.params && newProps.params.type && newProps.params.query){
|
||||
|
||||
if (this.props.params.query != newProps.params.query || this.props.params.type != newProps.params.type){
|
||||
this.props.uiActions.startSearch(newProps.params.type, newProps.params.query)
|
||||
this.props.coreActions.startSearch(newProps.params.type, newProps.params.query)
|
||||
}
|
||||
|
||||
// mopidy comes online
|
||||
if (!this.props.mopidy_connected && newProps.mopidy_connected){
|
||||
this.props.uiActions.startSearch(newProps.params.type, newProps.params.query, true)
|
||||
this.props.coreActions.startSearch(newProps.params.type, newProps.params.query, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -260,22 +261,23 @@ const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
mopidy_connected: state.mopidy.connected,
|
||||
search_settings: (state.ui.search_settings ? state.ui.search_settings : null),
|
||||
tracks: (state.ui.search_results ? state.ui.search_results.tracks : []),
|
||||
tracks_more: (state.ui.search_results && state.ui.search_results.tracks_more ? state.ui.search_results.tracks_more : null),
|
||||
tracks: (state.core.search_results ? state.core.search_results.tracks : []),
|
||||
tracks_more: (state.core.search_results && state.core.search_results.tracks_more ? state.core.search_results.tracks_more : null),
|
||||
artists: (state.core.artists ? state.core.artists : []),
|
||||
artists_uris: (state.ui.search_results ? state.ui.search_results.artists_uris : []),
|
||||
artists_more: (state.ui.search_results ? state.ui.search_results.artists_more : null),
|
||||
artists_uris: (state.core.search_results ? state.core.search_results.artists_uris : []),
|
||||
artists_more: (state.core.search_results ? state.core.search_results.artists_more : null),
|
||||
albums: (state.core.albums ? state.core.albums : []),
|
||||
albums_uris: (state.ui.search_results ? state.ui.search_results.albums_uris : []),
|
||||
albums_more: (state.ui.search_results ? state.ui.search_results.albums_more : null),
|
||||
albums_uris: (state.core.search_results ? state.core.search_results.albums_uris : []),
|
||||
albums_more: (state.core.search_results ? state.core.search_results.albums_more : null),
|
||||
playlists: (state.core.playlists ? state.core.playlists : []),
|
||||
playlists_uris: (state.ui.search_results ? state.ui.search_results.playlists_uris : []),
|
||||
playlists_more: (state.ui.search_results ? state.ui.search_results.playlists_more : null)
|
||||
playlists_uris: (state.core.search_results ? state.core.search_results.playlists_uris : []),
|
||||
playlists_more: (state.core.search_results ? state.core.search_results.playlists_more : null)
|
||||
}
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
uiActions: bindActionCreators(uiActions, dispatch),
|
||||
mopidyActions: bindActionCreators(mopidyActions, dispatch),
|
||||
spotifyActions: bindActionCreators(spotifyActions, dispatch)
|
||||
|
||||
Reference in New Issue
Block a user