Merge branch 'develop' into master
This commit is contained in:
@ -631,12 +631,28 @@ const CoreMiddleware = (function(){
|
||||
// Already have an artist in the index
|
||||
if (artists_index[artist.uri]){
|
||||
|
||||
// Don't replace existing images, instead add them as supplementary
|
||||
// this is to prevent LastFM overwriting Spotify images
|
||||
if (artists_index[artist.uri].images){
|
||||
artist.images_additional = artist.images;
|
||||
delete artist.images;
|
||||
}
|
||||
// And we've already got some images, make sure we merge the arrays,
|
||||
// rather than overwriting
|
||||
if (artists_index[artist.uri].images && artist.images){
|
||||
var existing_images = artists_index[artist.uri].images;
|
||||
var are_new_images = true;
|
||||
|
||||
// loop all extisting images to make sure we're not adding one that
|
||||
// we already have
|
||||
for (var existing_image of existing_images){
|
||||
|
||||
// We only need to check one size, the formatter should insist on consistency
|
||||
// Note that we depend on having a one-item array of images provided per action
|
||||
if (existing_image.huge == artist.images[0].huge){
|
||||
are_new_images = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Only if they're new images should we merge them in
|
||||
if (are_new_images){
|
||||
artist.images = Object.assign([], [...existing_images, ...artist.images]);
|
||||
}
|
||||
}
|
||||
|
||||
artist = Object.assign({}, artists_index[artist.uri], artist);
|
||||
}
|
||||
@ -652,7 +668,6 @@ const CoreMiddleware = (function(){
|
||||
artists_loaded.push(artist);
|
||||
};
|
||||
|
||||
|
||||
action.artists = artists_loaded;
|
||||
|
||||
if (tracks_loaded.length > 0){
|
||||
@ -759,32 +774,23 @@ const CoreMiddleware = (function(){
|
||||
var records = action.records_data;
|
||||
}
|
||||
|
||||
// TODO: To avoid double-looping, we could
|
||||
// run a single loop to extract both the formatted record
|
||||
// and the URI
|
||||
switch (action.records_type){
|
||||
case 'track':
|
||||
records = helpers.formatTracks(records);
|
||||
break;
|
||||
case 'artist':
|
||||
records = helpers.formatArtists(records);
|
||||
break;
|
||||
case 'album':
|
||||
records = helpers.formatAlbums(records);
|
||||
break;
|
||||
case 'playlist':
|
||||
records = helpers.formatPlaylists(records);
|
||||
break;
|
||||
case 'user':
|
||||
records = helpers.formatUsers(records);
|
||||
break;
|
||||
// Pre-emptively format tracks
|
||||
// Providers give us tracks in all kinds of structures, so this cleans things first
|
||||
if (action.records_type == 'track'){
|
||||
records = helpers.formatTracks(records);
|
||||
}
|
||||
|
||||
var records_type_plural = action.records_type+'s';
|
||||
var records_index = {};
|
||||
var records_uris = helpers.arrayOf('uri', records);
|
||||
|
||||
// Append our records_uris array with our new records
|
||||
// If we're a list of playlists, we need to manually filter Spotify's new URI structure
|
||||
// Really poor form because they haven't updated it everywhere, yet
|
||||
if (action.records_type == 'playlist'){
|
||||
records_uris = helpers.upgradeSpotifyPlaylistUris(records_uris);
|
||||
}
|
||||
|
||||
// Append our parent object's reference to these records
|
||||
var uris = records_uris;
|
||||
if (parent[records_type_plural+'_uris'] !== undefined){
|
||||
uris = [...parent[records_type_plural+'_uris'], ...uris];
|
||||
@ -808,9 +814,6 @@ const CoreMiddleware = (function(){
|
||||
records_action[records_type_plural] = records;
|
||||
store.dispatch(records_action);
|
||||
|
||||
//console.log(parent_action);
|
||||
//console.log(records_action);
|
||||
|
||||
next(action);
|
||||
break;
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
|
||||
var coreActions = require('../core/actions')
|
||||
var uiActions = require('../ui/actions')
|
||||
var helpers = require('../../helpers')
|
||||
var coreActions = require('../core/actions');
|
||||
var uiActions = require('../ui/actions');
|
||||
var helpers = require('../../helpers');
|
||||
|
||||
export function set(data){
|
||||
return {
|
||||
@ -172,7 +172,7 @@ export function getTrackLyrics(uri, path){
|
||||
});
|
||||
|
||||
var lyrics_html = lyrics.html();
|
||||
lyrics_html = lyrics_html.replace(/(\[)/g, '<span class="grey-text">[');
|
||||
lyrics_html = lyrics_html.replace(/(\[)/g, '<span class="mid_grey-text">[');
|
||||
lyrics_html = lyrics_html.replace(/(\])/g, ']</span>');
|
||||
|
||||
dispatch(coreActions.trackLoaded({
|
||||
@ -202,7 +202,7 @@ export function getTrackLyrics(uri, path){
|
||||
|
||||
export function findTrackLyrics(track){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
|
||||
var query = '';
|
||||
query += track.artists[0].name+' ';
|
||||
query += track.name;
|
||||
|
||||
31
src/js/services/google/actions.js
Executable file
31
src/js/services/google/actions.js
Executable file
@ -0,0 +1,31 @@
|
||||
|
||||
export function set(data){
|
||||
return {
|
||||
type: 'GOOGLE_SET',
|
||||
data: data
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryArtists(){
|
||||
return {
|
||||
type: 'GOOGLE_GET_LIBRARY_ARTISTS'
|
||||
}
|
||||
}
|
||||
|
||||
export function clearLibraryArtists(){
|
||||
return {
|
||||
type: 'GOOGLE_CLEAR_LIBRARY_ARTISTS'
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryAlbums(){
|
||||
return {
|
||||
'type': 'GOOGLE_GET_LIBRARY_ALBUMS'
|
||||
}
|
||||
}
|
||||
|
||||
export function clearLibraryAlbums(){
|
||||
return {
|
||||
type: 'GOOGLE_CLEAR_LIBRARY_ALBUMS'
|
||||
}
|
||||
}
|
||||
145
src/js/services/google/middleware.js
Executable file
145
src/js/services/google/middleware.js
Executable file
@ -0,0 +1,145 @@
|
||||
|
||||
import ReactGA from 'react-ga'
|
||||
|
||||
var helpers = require('../../helpers');
|
||||
var coreActions = require('../core/actions');
|
||||
var mopidyActions = require('../mopidy/actions');
|
||||
var uiActions = require('../ui/actions');
|
||||
|
||||
const GoogleMiddleware = (function(){
|
||||
|
||||
// A Google request is an alias of the Mopidy request
|
||||
const request = (store, method, params = null, response_callback = null, error_callback = null) => {
|
||||
store.dispatch(
|
||||
mopidyActions.request(
|
||||
method,
|
||||
params,
|
||||
response_callback,
|
||||
error_callback
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
return store => next => action => {
|
||||
var google = store.getState().google;
|
||||
|
||||
switch(action.type){
|
||||
case 'GOOGLE_GET_LIBRARY_ALBUMS':
|
||||
var last_run = store.getState().ui.processes.GOOGLE_LIBRARY_ALBUMS_PROCESSOR
|
||||
|
||||
if (!last_run){
|
||||
request(
|
||||
store,
|
||||
'library.browse',
|
||||
{
|
||||
uri: 'gmusic:album'
|
||||
},
|
||||
response => {
|
||||
if (response.length <= 0){
|
||||
return;
|
||||
}
|
||||
|
||||
var uris = helpers.arrayOf('uri',response);
|
||||
store.dispatch({
|
||||
type: 'GOOGLE_LIBRARY_ALBUMS_LOADED',
|
||||
uris: uris
|
||||
});
|
||||
|
||||
// Start our process to load the full album objects
|
||||
store.dispatch(uiActions.startProcess(
|
||||
'GOOGLE_LIBRARY_ALBUMS_PROCESSOR',
|
||||
'Loading '+uris.length+' Google albums',
|
||||
{
|
||||
uris: uris,
|
||||
total: uris.length,
|
||||
remaining: uris.length
|
||||
}
|
||||
));
|
||||
}
|
||||
);
|
||||
|
||||
} else if (last_run.status == 'cancelled'){
|
||||
store.dispatch(uiActions.resumeProcess('GOOGLE_LIBRARY_ALBUMS_PROCESSOR'))
|
||||
} else if (last_run.status == 'finished'){
|
||||
// TODO: do we want to force a refresh?
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case 'GOOGLE_LIBRARY_ALBUMS_PROCESSOR':
|
||||
if (store.getState().ui.processes['GOOGLE_LIBRARY_ALBUMS_PROCESSOR'] !== undefined){
|
||||
var processor = store.getState().ui.processes['GOOGLE_LIBRARY_ALBUMS_PROCESSOR']
|
||||
|
||||
if (processor.status == 'cancelling'){
|
||||
store.dispatch(uiActions.processCancelled('GOOGLE_LIBRARY_ALBUMS_PROCESSOR'))
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
var uris = Object.assign([], action.data.uris);
|
||||
var uris_to_load = uris.splice(0,50);
|
||||
|
||||
if (uris_to_load.length > 0){
|
||||
store.dispatch(uiActions.updateProcess(
|
||||
'GOOGLE_LIBRARY_ALBUMS_PROCESSOR',
|
||||
'Loading '+uris.length+' Google albums',
|
||||
{
|
||||
uris: uris,
|
||||
remaining: uris.length
|
||||
}
|
||||
));
|
||||
store.dispatch(mopidyActions.getAlbums(uris_to_load, {name: 'GOOGLE_LIBRARY_ALBUMS_PROCESSOR', data: {uris: uris}}))
|
||||
} else {
|
||||
store.dispatch(uiActions.processFinishing('GOOGLE_LIBRARY_ALBUMS_PROCESSOR'));
|
||||
}
|
||||
|
||||
break
|
||||
|
||||
case 'GOOGLE_GET_LIBRARY_ARTISTS':
|
||||
request(
|
||||
store,
|
||||
'library.browse',
|
||||
{
|
||||
uri: 'gmusic:artist'
|
||||
},
|
||||
response => {
|
||||
if (response.length <= 0){
|
||||
return
|
||||
}
|
||||
|
||||
var uris = [];
|
||||
for (var i = 0; i < response.length; i++){
|
||||
|
||||
// Convert local URI to actual artist URI
|
||||
// See https://github.com/mopidy/mopidy-local-sqlite/issues/39
|
||||
response[i].uri = response[i].uri.replace('local:directory?albumartist=','');
|
||||
uris.push(response[i].uri);
|
||||
}
|
||||
|
||||
store.dispatch(coreActions.artistsLoaded(response));
|
||||
|
||||
store.dispatch({
|
||||
type: 'GOOGLE_LIBRARY_ARTISTS_LOADED',
|
||||
uris: uris
|
||||
});
|
||||
},
|
||||
error => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
'Could not load Google artists',
|
||||
error
|
||||
));
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
}
|
||||
}
|
||||
|
||||
})();
|
||||
|
||||
export default GoogleMiddleware
|
||||
38
src/js/services/google/reducer.js
Executable file
38
src/js/services/google/reducer.js
Executable file
@ -0,0 +1,38 @@
|
||||
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
export default function reducer(google = {}, action){
|
||||
switch (action.type){
|
||||
|
||||
case 'GOOGLE_SET':
|
||||
return Object.assign({}, google, action.data);
|
||||
|
||||
case 'GOOGLE_LIBRARY_ARTISTS_LOADED':
|
||||
if (google.library_artists){
|
||||
var uris = [...google.library_artists,...action.uris];
|
||||
} else {
|
||||
var uris = action.uris;
|
||||
}
|
||||
return Object.assign({}, google, { library_artists: helpers.removeDuplicates(uris) });
|
||||
|
||||
case 'GOOGLE_CLEAR_LIBRARY_ARTISTS':
|
||||
return Object.assign({}, google, { library_artists: null });
|
||||
|
||||
case 'GOOGLE_LIBRARY_ALBUMS_LOADED':
|
||||
if (google.library_albums){
|
||||
var uris = [...google.library_albums,...action.uris];
|
||||
} else {
|
||||
var uris = action.uris;
|
||||
}
|
||||
return Object.assign({}, google, { library_albums: helpers.removeDuplicates(uris) });
|
||||
|
||||
case 'GOOGLE_CLEAR_LIBRARY_ALBUMS':
|
||||
return Object.assign({}, google, { library_albums: null });
|
||||
|
||||
default:
|
||||
return google
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -240,11 +240,11 @@ const localstorageMiddleware = (function(){
|
||||
);
|
||||
break;
|
||||
|
||||
case 'SNAPCAST_CLIENT_COMMANDS_UPDATED':
|
||||
case 'SNAPCAST_COMMANDS_UPDATED':
|
||||
helpers.setStorage(
|
||||
'snapcast',
|
||||
{
|
||||
client_commands: action.client_commands
|
||||
commands: action.commands
|
||||
}
|
||||
);
|
||||
break;
|
||||
|
||||
@ -8,7 +8,7 @@ export function set(data){
|
||||
}
|
||||
}
|
||||
|
||||
export function request(method, params = null, response_callback = null, error_callback = null){
|
||||
export function request(method, params = {}, response_callback = null, error_callback = null){
|
||||
return {
|
||||
type: 'MOPIDY_REQUEST',
|
||||
method: method,
|
||||
@ -30,18 +30,6 @@ export function connecting(){
|
||||
}
|
||||
}
|
||||
|
||||
export function upgrading(){
|
||||
return {
|
||||
type: 'MOPIDY_UPGRADING'
|
||||
}
|
||||
}
|
||||
|
||||
export function restarting(){
|
||||
return {
|
||||
type: 'MOPIDY_RESTARTING'
|
||||
}
|
||||
}
|
||||
|
||||
export function disconnect(){
|
||||
return {
|
||||
type: 'MOPIDY_DISCONNECT'
|
||||
@ -56,6 +44,42 @@ export function debug(call, value){
|
||||
}
|
||||
}
|
||||
|
||||
export function restartStarted(){
|
||||
return {
|
||||
type: 'MOPIDY_RESTART_STARTED'
|
||||
}
|
||||
}
|
||||
|
||||
export function restartFinished(){
|
||||
return {
|
||||
type: 'MOPIDY_RESTART_FINISHED'
|
||||
}
|
||||
}
|
||||
|
||||
export function upgradeStarted(){
|
||||
return {
|
||||
type: 'MOPIDY_UPGRADE_STARTED'
|
||||
}
|
||||
}
|
||||
|
||||
export function upgradeFinished(){
|
||||
return {
|
||||
type: 'MOPIDY_UPGRADE_FINISHED'
|
||||
}
|
||||
}
|
||||
|
||||
export function localScanStarted(){
|
||||
return {
|
||||
type: 'MOPIDY_LOCAL_SCAN_STARTED'
|
||||
}
|
||||
}
|
||||
|
||||
export function localScanFinished(){
|
||||
return {
|
||||
type: 'MOPIDY_LOCAL_SCAN_FINISHED'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Core play actions
|
||||
**/
|
||||
@ -357,9 +381,10 @@ export function getTrack(uri){
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryArtists(){
|
||||
export function getLibraryArtists(uri = null){
|
||||
return {
|
||||
type: 'MOPIDY_GET_LIBRARY_ARTISTS'
|
||||
type: 'MOPIDY_GET_LIBRARY_ARTISTS',
|
||||
uri: uri
|
||||
}
|
||||
}
|
||||
|
||||
@ -399,9 +424,10 @@ export function getAlbums(uris, processor = null){
|
||||
}
|
||||
}
|
||||
|
||||
export function getLibraryAlbums(){
|
||||
export function getLibraryAlbums(uri = null){
|
||||
return {
|
||||
type: 'MOPIDY_GET_LIBRARY_ALBUMS'
|
||||
type: 'MOPIDY_GET_LIBRARY_ALBUMS',
|
||||
uri: uri
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,16 +1,17 @@
|
||||
|
||||
import ReactGA from 'react-ga'
|
||||
import Mopidy from 'mopidy'
|
||||
import ReactGA from 'react-ga';
|
||||
import Mopidy from 'mopidy';
|
||||
import md5 from 'md5';
|
||||
import { hashHistory } from 'react-router'
|
||||
import * as helpers from '../../helpers'
|
||||
import { hashHistory } from 'react-router';
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
var mopidyActions = require('./actions.js')
|
||||
var coreActions = require('../core/actions.js')
|
||||
var uiActions = require('../ui/actions.js')
|
||||
var spotifyActions = require('../spotify/actions.js')
|
||||
var pusherActions = require('../pusher/actions.js')
|
||||
var lastfmActions = require('../lastfm/actions.js')
|
||||
var mopidyActions = require('./actions.js');
|
||||
var coreActions = require('../core/actions.js');
|
||||
var uiActions = require('../ui/actions.js');
|
||||
var spotifyActions = require('../spotify/actions.js');
|
||||
var pusherActions = require('../pusher/actions.js');
|
||||
var googleActions = require('../google/actions.js');
|
||||
var lastfmActions = require('../lastfm/actions.js');
|
||||
|
||||
const MopidyMiddleware = (function(){
|
||||
|
||||
@ -45,15 +46,15 @@ const MopidyMiddleware = (function(){
|
||||
store.dispatch(mopidyActions.getTimePosition());
|
||||
store.dispatch(mopidyActions.getUriSchemes());
|
||||
|
||||
// every 1000s update our play position (when playing)
|
||||
// Every 1s update our play position (when playing)
|
||||
progress_interval = setInterval(() => {
|
||||
if (store.getState().mopidy.play_state == 'playing'){
|
||||
|
||||
// every 10s get real position from server
|
||||
if (progress_interval_counter % 5 == 0){
|
||||
// Every 10s get real position from server, provided we're in-focus
|
||||
if (progress_interval_counter % 5 == 0 && store.getState().ui.window_focus === true){
|
||||
store.dispatch(mopidyActions.getTimePosition());
|
||||
|
||||
// otherwise we just assume to add 1000ms every 1000ms of play time
|
||||
// Otherwise we just assume to add 1000ms every 1000ms of play time
|
||||
} else {
|
||||
store.dispatch(mopidyActions.timePosition(store.getState().mopidy.time_position + 1000));
|
||||
}
|
||||
@ -95,7 +96,10 @@ const MopidyMiddleware = (function(){
|
||||
|
||||
case 'event:trackPlaybackEnded':
|
||||
store.dispatch(mopidyActions.clearCurrentTrack());
|
||||
store.dispatch(mopidyActions.getTimePosition());
|
||||
store.dispatch({
|
||||
type: 'MOPIDY_TIME_POSITION',
|
||||
time_position: 0
|
||||
});
|
||||
break;
|
||||
|
||||
case 'event:trackPlaybackStarted':
|
||||
@ -227,6 +231,7 @@ const MopidyMiddleware = (function(){
|
||||
var hashed_hostname = md5(window.location.hostname);
|
||||
ReactGA.event({ category: 'Mopidy', action: 'Connected', label: hashed_hostname });
|
||||
}
|
||||
store.dispatch(uiActions.createNotification({content: 'Mopidy connected'}));
|
||||
next(action);
|
||||
break;
|
||||
|
||||
@ -236,6 +241,10 @@ const MopidyMiddleware = (function(){
|
||||
store.dispatch({ type: 'MOPIDY_DISCONNECTED' })
|
||||
break;
|
||||
|
||||
case 'MOPIDY_DISCONNECTED':
|
||||
store.dispatch(uiActions.createNotification({type: 'bad', content: 'Mopidy disconnected'}));
|
||||
break;
|
||||
|
||||
case 'MOPIDY_DEBUG':
|
||||
request(socket, store, action.call, action.value )
|
||||
.then(response => {
|
||||
@ -243,6 +252,21 @@ const MopidyMiddleware = (function(){
|
||||
})
|
||||
break;
|
||||
|
||||
case 'SET_WINDOW_FOCUS':
|
||||
|
||||
// Focus has just been regained
|
||||
if (action.window_focus === true){
|
||||
store.dispatch(mopidyActions.getPlayState());
|
||||
store.dispatch(mopidyActions.getVolume());
|
||||
store.dispatch(mopidyActions.getMute());
|
||||
store.dispatch(mopidyActions.getConsume());
|
||||
store.dispatch(mopidyActions.getRandom());
|
||||
store.dispatch(mopidyActions.getRepeat());
|
||||
store.dispatch(mopidyActions.getCurrentTrack());
|
||||
store.dispatch(mopidyActions.getTimePosition());
|
||||
}
|
||||
break;
|
||||
|
||||
case 'MOPIDY_REQUEST':
|
||||
request(socket, store, action.method, action.params)
|
||||
.then(
|
||||
@ -530,21 +554,8 @@ const MopidyMiddleware = (function(){
|
||||
}
|
||||
|
||||
// Enable Iris providers when the backend is available
|
||||
if (uri_schemes.includes('spotify:')){
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_SET',
|
||||
data: {
|
||||
enabled: true
|
||||
}
|
||||
});
|
||||
} else {
|
||||
store.dispatch({
|
||||
type: 'SPOTIFY_SET',
|
||||
data: {
|
||||
enabled: false
|
||||
}
|
||||
});
|
||||
}
|
||||
store.dispatch(spotifyActions.set({enabled: uri_schemes.includes('spotify:')}));
|
||||
store.dispatch(googleActions.set({enabled: uri_schemes.includes('gmusic:')}));
|
||||
|
||||
// If we haven't customised our search schemes, add all to search
|
||||
if (store.getState().ui.uri_schemes_search_enabled === undefined){
|
||||
@ -770,12 +781,19 @@ const MopidyMiddleware = (function(){
|
||||
store.dispatch(mopidyActions.clearTracklist());
|
||||
}
|
||||
|
||||
var first_uri = action.uris[0];
|
||||
// Shuffle/random mode
|
||||
if (store.getState().mopidy.random){
|
||||
var first_uri_index = Math.floor(Math.random() * action.uris.length);
|
||||
} else {
|
||||
var first_uri_index = 0;
|
||||
}
|
||||
var first_uri = action.uris[first_uri_index];
|
||||
|
||||
// add our first track
|
||||
request(socket, store, 'tracklist.add', { uri: first_uri, at_position: 0 })
|
||||
.then(
|
||||
response => {
|
||||
|
||||
// play it (only if we got a successful lookup)
|
||||
if (response.length > 0){
|
||||
store.dispatch(mopidyActions.changeTrack(response[0].tlid));
|
||||
@ -792,11 +810,13 @@ const MopidyMiddleware = (function(){
|
||||
));
|
||||
}
|
||||
|
||||
// add the rest of our uris (if any)
|
||||
action.uris.shift();
|
||||
// Remove our first_uri as we've already added it
|
||||
action.uris.splice(first_uri_index, 1);
|
||||
|
||||
// And add the rest of our uris (if any)
|
||||
if (action.uris.length > 0){
|
||||
|
||||
// wait 100ms so the server can trigger track_changed etc
|
||||
// Wait a moment so the server can trigger track_changed etc
|
||||
// this means our UI feels snappier as the first track shows up quickly
|
||||
setTimeout(
|
||||
function(){
|
||||
@ -1715,7 +1735,7 @@ const MopidyMiddleware = (function(){
|
||||
var last_run = store.getState().ui.processes.MOPIDY_LIBRARY_ALBUMS_PROCESSOR
|
||||
|
||||
if (!last_run){
|
||||
request(socket, store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri } )
|
||||
request(socket, store, 'library.browse', { uri: store.getState().mopidy.library_albums_uri })
|
||||
.then(response => {
|
||||
if (response.length <= 0) return
|
||||
|
||||
@ -2021,9 +2041,9 @@ const MopidyMiddleware = (function(){
|
||||
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))
|
||||
store.dispatch(lastfmActions.getArtist(artist.uri, artist.name));
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -2242,8 +2262,10 @@ const MopidyMiddleware = (function(){
|
||||
for (var item of response){
|
||||
if (item.type === "track"){
|
||||
tracks_uris.push(item.uri);
|
||||
tracks_uris = helpers.sortItems(tracks_uris, 'name');
|
||||
} else {
|
||||
subdirectories.push(item);
|
||||
subdirectories = helpers.sortItems(subdirectories, 'name');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,24 +1,32 @@
|
||||
|
||||
import * as helpers from '../../helpers'
|
||||
import * as helpers from '../../helpers';
|
||||
|
||||
export default function reducer(mopidy = {}, action){
|
||||
switch (action.type){
|
||||
|
||||
case 'MOPIDY_SET':
|
||||
return Object.assign({}, mopidy, action.data);
|
||||
|
||||
case 'MOPIDY_CONNECT':
|
||||
case 'MOPIDY_CONNECTING':
|
||||
return Object.assign({}, mopidy, { connected: false, connecting: true });
|
||||
|
||||
case 'MOPIDY_RESTARTING':
|
||||
return Object.assign({}, mopidy, { restarting: true });
|
||||
|
||||
case 'MOPIDY_UPGRADING':
|
||||
return Object.assign({}, mopidy, { upgrading: true });
|
||||
return Object.assign({}, mopidy, {
|
||||
connected: false,
|
||||
connecting: true
|
||||
});
|
||||
|
||||
case 'MOPIDY_CONNECTED':
|
||||
return Object.assign({}, mopidy, { connected: true, connecting: false, restarting: false, upgrading: false });
|
||||
return Object.assign({}, mopidy, {
|
||||
connected: true,
|
||||
connecting: false,
|
||||
restart_running: false,
|
||||
upgrade_running: false
|
||||
});
|
||||
|
||||
case 'MOPIDY_DISCONNECTED':
|
||||
return Object.assign({}, mopidy, { connected: false, connecting: false });
|
||||
return Object.assign({}, mopidy, {
|
||||
connected: false,
|
||||
connecting: false
|
||||
});
|
||||
|
||||
case 'MOPIDY_CHANGE_TRACK':
|
||||
return Object.assign({}, mopidy, {
|
||||
@ -30,8 +38,23 @@ export default function reducer(mopidy = {}, action){
|
||||
uri_schemes: action.uri_schemes
|
||||
});
|
||||
|
||||
case 'MOPIDY_SET':
|
||||
return Object.assign({}, mopidy, action.data);
|
||||
case 'MOPIDY_RESTART_STARTED':
|
||||
return Object.assign({}, mopidy, { restart_running: true });
|
||||
|
||||
case 'MOPIDY_RESTART_FINISHED':
|
||||
return Object.assign({}, mopidy, { restart_running: false });
|
||||
|
||||
case 'MOPIDY_UPGRADE_STARTED':
|
||||
return Object.assign({}, mopidy, { upgrade_running: true });
|
||||
|
||||
case 'MOPIDY_UPGRADE_FINISHED':
|
||||
return Object.assign({}, mopidy, { upgrade_running: false });
|
||||
|
||||
case 'MOPIDY_LOCAL_SCAN_STARTED':
|
||||
return Object.assign({}, mopidy, { local_scan_running: true });
|
||||
|
||||
case 'MOPIDY_LOCAL_SCAN_FINISHED':
|
||||
return Object.assign({}, mopidy, { local_scan_running: false });
|
||||
|
||||
|
||||
/**
|
||||
|
||||
@ -48,6 +48,12 @@ export function restart(){
|
||||
}
|
||||
}
|
||||
|
||||
export function localScan(){
|
||||
return {
|
||||
type: 'PUSHER_LOCAL_SCAN'
|
||||
}
|
||||
}
|
||||
|
||||
export function getConnections(){
|
||||
return {
|
||||
type: 'PUSHER_GET_CONNECTIONS'
|
||||
@ -192,97 +198,42 @@ export function addQueueMetadata(tlids = [], from_uri = null){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Snapcast actions
|
||||
* TODO: Figure out how to cleanly split this out to it's own service
|
||||
* but still share the pusher middleware connection
|
||||
* Commands (buttons)
|
||||
**/
|
||||
|
||||
export function getSnapcast(){
|
||||
return {
|
||||
type: 'PUSHER_GET_SNAPCAST',
|
||||
data: {
|
||||
method: 'Server.GetStatus'
|
||||
}
|
||||
}
|
||||
export function getCommands(){
|
||||
return {
|
||||
type: 'PUSHER_GET_COMMANDS'
|
||||
}
|
||||
}
|
||||
|
||||
export function snapcastServerLoaded(server){
|
||||
return {
|
||||
type: 'PUSHER_SNAPCAST_SERVER_LOADED',
|
||||
server: server
|
||||
}
|
||||
export function setCommand(command){
|
||||
return {
|
||||
type: 'PUSHER_SET_COMMAND',
|
||||
command: command
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastClientName(id, name){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_CLIENT_NAME',
|
||||
id: id,
|
||||
name: name
|
||||
}
|
||||
export function removeCommand(id){
|
||||
return {
|
||||
type: 'PUSHER_REMOVE_COMMAND',
|
||||
id: id
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastClientMute(id, mute){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_CLIENT_MUTE',
|
||||
id: id,
|
||||
mute: mute
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastClientVolume(id, percent){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_CLIENT_VOLUME',
|
||||
id: id,
|
||||
percent: percent
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastClientLatency(id, latency){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_CLIENT_LATENCY',
|
||||
id: id,
|
||||
latency: latency
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastClientGroup(id, group_id){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_CLIENT_GROUP',
|
||||
id: id,
|
||||
group_id: group_id
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteSnapcastClient(id){
|
||||
return {
|
||||
type: 'PUSHER_DELETE_SNAPCAST_CLIENT',
|
||||
id: id
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastGroupStream(id, stream_id){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_GROUP_STREAM',
|
||||
id: id,
|
||||
stream_id: stream_id
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastGroupMute(id, mute){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_GROUP_MUTE',
|
||||
id: id,
|
||||
mute: mute
|
||||
}
|
||||
}
|
||||
|
||||
export function setSnapcastGroupVolume(id, percent, old_percent = 0){
|
||||
return {
|
||||
type: 'PUSHER_SET_SNAPCAST_GROUP_VOLUME',
|
||||
id: id,
|
||||
percent: percent,
|
||||
old_percent: old_percent
|
||||
}
|
||||
export function sendCommand(id, notify = false){
|
||||
return {
|
||||
type: 'PUSHER_SEND_COMMAND',
|
||||
id: id,
|
||||
notify: notify
|
||||
}
|
||||
}
|
||||
|
||||
export function commandsUpdated(commands){
|
||||
return {
|
||||
type: 'PUSHER_COMMANDS_UPDATED',
|
||||
commands: commands
|
||||
}
|
||||
}
|
||||
@ -1,14 +1,15 @@
|
||||
|
||||
import ReactGA from 'react-ga'
|
||||
import ReactGA from 'react-ga';
|
||||
|
||||
var helpers = require('../../helpers')
|
||||
var coreActions = require('../core/actions')
|
||||
var uiActions = require('../ui/actions')
|
||||
var mopidyActions = require('../mopidy/actions')
|
||||
var pusherActions = require('./actions')
|
||||
var lastfmActions = require('../lastfm/actions')
|
||||
var geniusActions = require('../genius/actions')
|
||||
var spotifyActions = require('../spotify/actions')
|
||||
var helpers = require('../../helpers');
|
||||
var coreActions = require('../core/actions');
|
||||
var uiActions = require('../ui/actions');
|
||||
var mopidyActions = require('../mopidy/actions');
|
||||
var pusherActions = require('./actions');
|
||||
var lastfmActions = require('../lastfm/actions');
|
||||
var geniusActions = require('../genius/actions');
|
||||
var spotifyActions = require('../spotify/actions');
|
||||
var snapcastActions = require('../snapcast/actions');
|
||||
|
||||
const PusherMiddleware = (function(){
|
||||
|
||||
@ -108,18 +109,61 @@ const PusherMiddleware = (function(){
|
||||
case 'radio_stopped':
|
||||
store.dispatch(pusherActions.radioStopped());
|
||||
break;
|
||||
case 'commands_changed':
|
||||
store.dispatch(pusherActions.commandsUpdated(message.params.commands));
|
||||
break;
|
||||
case 'reload':
|
||||
window.location.reload(true);
|
||||
break;
|
||||
case 'upgrading':
|
||||
|
||||
// Local scan
|
||||
case 'local_scan_started':
|
||||
store.dispatch(uiActions.updateProcess('local_scan', 'Scanning local library'));
|
||||
break;
|
||||
case 'local_scan_finished':
|
||||
store.dispatch(uiActions.processFinished('local_scan'));
|
||||
store.dispatch(uiActions.createNotification({key: 'local_scan', type: 'info', content: 'Local scan finished', description: message.params.output}));
|
||||
break;
|
||||
case 'local_scan_error':
|
||||
store.dispatch(uiActions.processFinished('local_scan'));
|
||||
store.dispatch(uiActions.createNotification({key: 'local_scan', type: 'bad', content: 'Local scan failed'}));
|
||||
break;
|
||||
|
||||
// Upgrade
|
||||
case 'upgrade_started':
|
||||
store.dispatch(mopidyActions.upgrading());
|
||||
store.dispatch(uiActions.createNotification({content: 'Upgrading...', type: 'info'}));
|
||||
store.dispatch(uiActions.updateProcess('upgrade', 'Upgrading'));
|
||||
break;
|
||||
case 'restarting':
|
||||
store.dispatch(mopidyActions.restarting());
|
||||
store.dispatch(uiActions.createNotification({content: 'Restarting...', type: 'info'}));
|
||||
case 'upgrade_finished':
|
||||
store.dispatch(uiActions.updateProcess('upgrade', 'Restarting to complete upgrade'));
|
||||
break;
|
||||
case 'upgrade_error':
|
||||
store.dispatch(uiActions.processFinished('upgrade'));
|
||||
store.dispatch(uiActions.createNotification({type: 'bad', content: 'Upgrade failed'}));
|
||||
break;
|
||||
|
||||
// Restart
|
||||
case 'restart_started':
|
||||
store.dispatch(uiActions.processFinished('upgrade'));
|
||||
store.dispatch(uiActions.createNotification({type: 'info', content: 'Restarting server...'}));
|
||||
break;
|
||||
|
||||
// Test
|
||||
case 'test_started':
|
||||
store.dispatch(uiActions.updateProcess('test', 'Running test'));
|
||||
break;
|
||||
case 'test_finished':
|
||||
store.dispatch(uiActions.processFinished('test'));
|
||||
store.dispatch(uiActions.createNotification({type: 'info', content: 'Test finished', description: message.params.output}));
|
||||
break;
|
||||
case 'test_error':
|
||||
store.dispatch(uiActions.processFinished('test'));
|
||||
store.dispatch(uiActions.createNotification({type: 'bad', content: 'Test failed'}));
|
||||
break;
|
||||
}
|
||||
|
||||
// Pass snapcast events to the Snapcast service
|
||||
if (message.method.startsWith('snapcast_')){
|
||||
store.dispatch(snapcastActions.eventReceived(message));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -168,6 +212,8 @@ const PusherMiddleware = (function(){
|
||||
}
|
||||
|
||||
return store => next => action => {
|
||||
var pusher = store.getState().pusher;
|
||||
|
||||
switch(action.type){
|
||||
|
||||
case 'PUSHER_CONNECT':
|
||||
@ -227,6 +273,7 @@ const PusherMiddleware = (function(){
|
||||
|
||||
store.dispatch(pusherActions.getConfig());
|
||||
store.dispatch(pusherActions.getRadio());
|
||||
store.dispatch(pusherActions.getCommands());
|
||||
store.dispatch(pusherActions.getQueueMetadata());
|
||||
|
||||
// Give things a few moments to setup before we check for version.
|
||||
@ -236,7 +283,7 @@ const PusherMiddleware = (function(){
|
||||
function(){
|
||||
store.dispatch(pusherActions.getVersion());
|
||||
},
|
||||
2000
|
||||
500
|
||||
);
|
||||
next(action);
|
||||
break;
|
||||
@ -303,7 +350,7 @@ const PusherMiddleware = (function(){
|
||||
request(store, 'add_queue_metadata', {
|
||||
tlids: action.tlids,
|
||||
added_from: action.from_uri,
|
||||
added_by: store.getState().pusher.username
|
||||
added_by: pusher.username
|
||||
})
|
||||
break;
|
||||
|
||||
@ -387,6 +434,112 @@ const PusherMiddleware = (function(){
|
||||
return next(action);
|
||||
break;
|
||||
|
||||
|
||||
/**
|
||||
* Commands
|
||||
**/
|
||||
|
||||
case 'PUSHER_GET_COMMANDS':
|
||||
request(store, 'get_commands')
|
||||
.then(
|
||||
response => {
|
||||
store.dispatch(pusherActions.commandsUpdated(response.commands));
|
||||
},
|
||||
error => {
|
||||
// We're not too worried about capturing errors here
|
||||
// It's also likely to fail where UI has been updated but
|
||||
// server hasn't been restarted yet.
|
||||
}
|
||||
);
|
||||
next(action);
|
||||
break
|
||||
|
||||
case 'PUSHER_SET_COMMAND':
|
||||
var commands_index = Object.assign({}, pusher.commands);
|
||||
|
||||
if (commands_index[action.command.id]){
|
||||
var command = Object.assign({}, commands_index[action.command.id], action.command);
|
||||
} else {
|
||||
var command = action.command;
|
||||
}
|
||||
commands_index[action.command.id] = command;
|
||||
|
||||
request(store, 'set_commands', {commands: commands_index})
|
||||
.then(
|
||||
response => {
|
||||
// No action required, the change will be broadcast
|
||||
},
|
||||
error => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
'Could not set commands',
|
||||
error
|
||||
));
|
||||
}
|
||||
);
|
||||
|
||||
next(action);
|
||||
break
|
||||
|
||||
case 'PUSHER_REMOVE_COMMAND':
|
||||
var commands_index = Object.assign({}, pusher.commands);
|
||||
delete commands_index[action.id];
|
||||
|
||||
request(store, 'set_commands', {commands: commands_index})
|
||||
.then(
|
||||
response => {
|
||||
// No action required, the change will be broadcast
|
||||
},
|
||||
error => {
|
||||
store.dispatch(coreActions.handleException(
|
||||
'Could not remove command',
|
||||
error
|
||||
));
|
||||
}
|
||||
);
|
||||
|
||||
next(action);
|
||||
break
|
||||
|
||||
case 'PUSHER_SEND_COMMAND':
|
||||
var command = Object.assign({}, pusher.commands[action.id]);
|
||||
var notification_key = 'command_'+action.id;
|
||||
|
||||
if (action.notify){
|
||||
store.dispatch(uiActions.startProcess(notification_key, 'Sending command'));
|
||||
}
|
||||
|
||||
try {
|
||||
var ajax_settings = JSON.parse(command.command);
|
||||
} catch(error){
|
||||
store.dispatch(uiActions.createNotification({key: notification_key, type: 'bad', content: 'Command failed', description: error}));
|
||||
break;
|
||||
}
|
||||
|
||||
// Handle success and failure
|
||||
ajax_settings.success = function(response){
|
||||
console.log("Command sent, response was:",response);
|
||||
|
||||
if (action.notify){
|
||||
store.dispatch(uiActions.processFinished(notification_key));
|
||||
store.dispatch(uiActions.createNotification({key: notification_key, type: 'info', content: 'Command sent'}));
|
||||
}
|
||||
}
|
||||
ajax_settings.error = function(xhr, status, error){
|
||||
console.error("Command failed, response was:",xhr,error);
|
||||
store.dispatch(uiActions.processFinished(notification_key));
|
||||
store.dispatch(uiActions.createNotification({key: notification_key, type: 'bad', content: 'Command failed', description: xhr.status+": "+error}));
|
||||
}
|
||||
|
||||
// Actually send the request
|
||||
$.ajax(ajax_settings);
|
||||
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* Radio
|
||||
**/
|
||||
|
||||
case 'PUSHER_GET_RADIO':
|
||||
request(store, 'get_radio')
|
||||
.then(
|
||||
@ -445,7 +598,7 @@ const PusherMiddleware = (function(){
|
||||
{
|
||||
notification: {
|
||||
type: 'info',
|
||||
content: store.getState().pusher.username + ' is starting radio mode'
|
||||
content: pusher.username + ' is starting radio mode'
|
||||
}
|
||||
}
|
||||
));
|
||||
@ -482,7 +635,7 @@ const PusherMiddleware = (function(){
|
||||
{
|
||||
notification: {
|
||||
type: 'info',
|
||||
content: store.getState().pusher.username + ' stopped radio mode'
|
||||
content: pusher.username + ' stopped radio mode'
|
||||
}
|
||||
}
|
||||
));
|
||||
@ -506,6 +659,11 @@ const PusherMiddleware = (function(){
|
||||
);
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* Notifications and alerts
|
||||
**/
|
||||
|
||||
case 'PUSHER_BROWSER_NOTIFICATION':
|
||||
store.dispatch(uiActions.createBrowserNotification(action))
|
||||
break
|
||||
@ -520,6 +678,11 @@ const PusherMiddleware = (function(){
|
||||
store.dispatch(uiActions.createNotification(data));
|
||||
break
|
||||
|
||||
|
||||
/**
|
||||
* Server actions
|
||||
**/
|
||||
|
||||
case 'PUSHER_RELOAD':
|
||||
// Hard reload. This doesn't strictly clear the cache, but our compiler's
|
||||
// cache buster should handle that
|
||||
@ -527,15 +690,7 @@ const PusherMiddleware = (function(){
|
||||
break
|
||||
|
||||
case 'PUSHER_RESTART':
|
||||
request(store, 'restart')
|
||||
.then(
|
||||
response => {
|
||||
store.dispatch(mopidyActions.restarting());
|
||||
},
|
||||
error => {
|
||||
store.dispatch(uiActions.createNotification({content: error.message, description: (error.description ? error.description : null), type: 'bad'}));
|
||||
}
|
||||
);
|
||||
request(store, 'restart');
|
||||
next(action);
|
||||
break
|
||||
|
||||
@ -543,15 +698,18 @@ const PusherMiddleware = (function(){
|
||||
if (store.getState().ui.allow_reporting){
|
||||
ReactGA.event({ category: 'Pusher', action: 'Upgrade', label: '' });
|
||||
}
|
||||
request(store, 'upgrade')
|
||||
.then(
|
||||
response => {
|
||||
store.dispatch(mopidyActions.upgrading());
|
||||
},
|
||||
error => {
|
||||
store.dispatch(uiActions.createNotification({content: error.message, description: (error.description ? error.description : null), type: 'bad'}));
|
||||
}
|
||||
);
|
||||
request(store, 'upgrade');
|
||||
break;
|
||||
|
||||
case 'PUSHER_LOCAL_SCAN':
|
||||
if (store.getState().ui.allow_reporting){
|
||||
ReactGA.event({ category: 'Pusher', action: 'Local scan', label: '' });
|
||||
}
|
||||
request(store, 'local_scan');
|
||||
break;
|
||||
|
||||
case 'PUSHER_TEST':
|
||||
request(store, 'test');
|
||||
break;
|
||||
|
||||
case 'PUSHER_VERSION':
|
||||
|
||||
@ -54,30 +54,8 @@ export default function reducer(pusher = {}, action){
|
||||
case 'PUSHER_CONFIG':
|
||||
return Object.assign({}, pusher, { config: action.config });
|
||||
|
||||
case 'PUSHER_SNAPCAST':
|
||||
return Object.assign({}, pusher, {
|
||||
snapcast_streams: action.snapcast_streams,
|
||||
snapcast_groups: action.snapcast_groups,
|
||||
snapcast_clients: action.snapcast_clients
|
||||
});
|
||||
|
||||
case 'PUSHER_SNAPCAST_GROUP_UPDATED':
|
||||
var snapcast_groups = Object.assign({}, pusher.snapcast_groups);
|
||||
var group = snapcast_groups[action.key];
|
||||
snapcast_groups[action.key] = Object.assign({}, group, action.group);
|
||||
return Object.assign({}, pusher, { snapcast_groups: snapcast_groups });
|
||||
|
||||
case 'PUSHER_SNAPCAST_CLIENT_UPDATED':
|
||||
var snapcast_clients = Object.assign({}, pusher.snapcast_clients);
|
||||
var client = snapcast_clients[action.key];
|
||||
client.config = Object.assign({}, client.config, action.client.config);
|
||||
snapcast_clients[action.key] = client;
|
||||
return Object.assign({}, pusher, { snapcast_clients: snapcast_clients });
|
||||
|
||||
case 'PUSHER_SNAPCAST_CLIENT_REMOVED':
|
||||
var snapcast_clients = Object.assign({}, pusher.snapcast_clients);
|
||||
delete snapcast_clients[action.key];
|
||||
return Object.assign({}, pusher, { snapcast_clients: snapcast_clients });
|
||||
case 'PUSHER_COMMANDS_UPDATED':
|
||||
return Object.assign({}, pusher, { commands: action.commands });
|
||||
|
||||
default:
|
||||
return pusher
|
||||
|
||||
@ -37,29 +37,6 @@ export function setClientLatency(id, latency){
|
||||
}
|
||||
}
|
||||
|
||||
export function setClientCommand(id, command){
|
||||
return {
|
||||
type: 'SNAPCAST_SET_CLIENT_COMMAND',
|
||||
id: id,
|
||||
command: command
|
||||
}
|
||||
}
|
||||
|
||||
export function sendClientCommand(id, command){
|
||||
return {
|
||||
type: 'SNAPCAST_SEND_CLIENT_COMMAND',
|
||||
id: id,
|
||||
command: command
|
||||
}
|
||||
}
|
||||
|
||||
export function clientCommandsUpdated(client_commands){
|
||||
return {
|
||||
type: 'SNAPCAST_CLIENT_COMMANDS_UPDATED',
|
||||
client_commands: client_commands
|
||||
}
|
||||
}
|
||||
|
||||
export function setClientGroup(id, group_id){
|
||||
return {
|
||||
type: 'SNAPCAST_SET_CLIENT_GROUP',
|
||||
@ -100,6 +77,14 @@ export function setGroupVolume(id, percent, old_percent = 0){
|
||||
}
|
||||
}
|
||||
|
||||
export function eventReceived(message){
|
||||
return {
|
||||
type: 'SNAPCAST_EVENT_RECEIVED',
|
||||
method: message.method,
|
||||
params: message.params
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ const SnapcastMiddleware = (function(){
|
||||
const request = (store, params = null, response_callback = null, error_callback = null) => {
|
||||
store.dispatch(
|
||||
pusherActions.request(
|
||||
'snapcast_instruct',
|
||||
'snapcast',
|
||||
params,
|
||||
response_callback,
|
||||
error_callback
|
||||
@ -228,37 +228,6 @@ const SnapcastMiddleware = (function(){
|
||||
);
|
||||
break
|
||||
|
||||
case 'SNAPCAST_SET_CLIENT_COMMAND':
|
||||
var client_commands_index = Object.assign({}, snapcast.client_commands);
|
||||
|
||||
if (client_commands_index[action.id]){
|
||||
var client_command = Object.assign({}, client_commands_index[action.id], action.command);
|
||||
} else {
|
||||
var client_command = action.command;
|
||||
}
|
||||
client_commands_index[action.id] = client_command;
|
||||
|
||||
store.dispatch(snapcastActions.clientCommandsUpdated(client_commands_index));
|
||||
|
||||
next(action);
|
||||
break
|
||||
|
||||
case 'SNAPCAST_SEND_CLIENT_COMMAND':
|
||||
|
||||
// Prepare our command
|
||||
// We try and make it cross-origin compatible
|
||||
var command = JSON.parse(action.command);
|
||||
command.crossDomain = true;
|
||||
command.dataType = "jsonp";
|
||||
command.success = function(response){
|
||||
store.dispatch(uiActions.createNotification({type: 'info', content: 'Command sent', description: command.url}));
|
||||
}
|
||||
|
||||
// Actually send the request
|
||||
$.ajax(command);
|
||||
|
||||
break
|
||||
|
||||
case 'SNAPCAST_SET_CLIENT_GROUP':
|
||||
|
||||
var group = snapcast.groups[action.group_id];
|
||||
@ -423,6 +392,77 @@ const SnapcastMiddleware = (function(){
|
||||
}
|
||||
break;
|
||||
|
||||
case 'SNAPCAST_EVENT_RECEIVED':
|
||||
|
||||
// Drop the prefix
|
||||
action.method = action.method.replace('snapcast_','');
|
||||
|
||||
switch (action.method){
|
||||
|
||||
case 'Client.OnConnect':
|
||||
store.dispatch(snapcastActions.clientLoaded(
|
||||
{
|
||||
id: action.params.client.id,
|
||||
name: action.params.client.name,
|
||||
volume: action.params.client.volume.percent,
|
||||
mute: action.params.client.volume.muted,
|
||||
connected: action.params.client.connected
|
||||
}
|
||||
));
|
||||
break;
|
||||
|
||||
case 'Client.OnDisconnect':
|
||||
store.dispatch(snapcastActions.clientLoaded(
|
||||
{
|
||||
id: action.params.client.id,
|
||||
connected: action.params.client.connected
|
||||
}
|
||||
));
|
||||
break;
|
||||
|
||||
case 'Client.OnVolumeChanged':
|
||||
store.dispatch(snapcastActions.clientLoaded(
|
||||
{
|
||||
id: action.params.id,
|
||||
mute: action.params.volume.muted,
|
||||
volume: action.params.volume.percent
|
||||
}
|
||||
));
|
||||
break;
|
||||
|
||||
case 'Client.OnLatencyChanged':
|
||||
store.dispatch(snapcastActions.clientLoaded(
|
||||
{
|
||||
id: action.params.id,
|
||||
latency: action.params.latency
|
||||
}
|
||||
));
|
||||
break;
|
||||
|
||||
case 'Client.OnNameChanged':
|
||||
store.dispatch(snapcastActions.clientLoaded(
|
||||
{
|
||||
id: action.params.id,
|
||||
name: action.params.name
|
||||
}
|
||||
));
|
||||
break;
|
||||
|
||||
case 'Group.OnMute':
|
||||
store.dispatch(snapcastActions.groupLoaded(
|
||||
{
|
||||
id: action.params.id,
|
||||
mute: action.params.mute
|
||||
}
|
||||
));
|
||||
break;
|
||||
|
||||
case 'Server.OnUpdate':
|
||||
store.dispatch(snapcastActions.serverLoaded(action.params));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// This action is irrelevant to us, pass it on to the next middleware
|
||||
default:
|
||||
return next(action);
|
||||
|
||||
@ -6,9 +6,6 @@ export default function reducer(snapcast = {}, action){
|
||||
var server = Object.assign({}, action.server);
|
||||
return Object.assign({}, snapcast, { server: server });
|
||||
|
||||
case 'SNAPCAST_CLIENT_COMMANDS_UPDATED':
|
||||
return Object.assign({}, snapcast, { client_commands: action.client_commands });
|
||||
|
||||
case 'SNAPCAST_CLIENTS_LOADED':
|
||||
if (action.flush){
|
||||
var clients = {};
|
||||
|
||||
@ -15,10 +15,16 @@ var helpers = require('../../helpers')
|
||||
* @param data mixed = request payload
|
||||
* @return Promise
|
||||
**/
|
||||
const sendRequest = (dispatch, getState, endpoint, method = 'GET', data = false) => {
|
||||
const request = (dispatch, getState, endpoint, method = 'GET', data = false) => {
|
||||
|
||||
// Add reference to loader queue
|
||||
// We do this straight away so that even if we're refreshing the token, it still registers as
|
||||
// loading said endpoint
|
||||
var loader_key = helpers.generateGuid()
|
||||
dispatch(uiActions.startLoading(loader_key, 'spotify_'+endpoint));
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
getToken(dispatch, getState )
|
||||
getToken(dispatch, getState)
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -49,10 +55,6 @@ const sendRequest = (dispatch, getState, endpoint, method = 'GET', data = false)
|
||||
}
|
||||
}
|
||||
|
||||
// add reference to loader queue
|
||||
var loader_key = helpers.generateGuid()
|
||||
dispatch(uiActions.startLoading(loader_key, 'spotify_'+endpoint))
|
||||
|
||||
$.ajax(config).then(
|
||||
response => {
|
||||
dispatch(uiActions.stopLoading(loader_key))
|
||||
@ -105,21 +107,45 @@ function getToken(dispatch, getState){
|
||||
}
|
||||
|
||||
// token is expiring/expired, so go get a new one and resolve that
|
||||
refreshToken(dispatch, getState)
|
||||
.then(
|
||||
response => {
|
||||
resolve(response.access_token)
|
||||
},
|
||||
error => {
|
||||
reject(error)
|
||||
}
|
||||
);
|
||||
// TODO: Detect whether we already have a pending refresh, in which case we
|
||||
// need to wait until it's done, and then return that
|
||||
|
||||
// We've already got a refresh in progress
|
||||
if (getState().ui.load_queue.spotify_refresh_token !== undefined){
|
||||
|
||||
console.log("Already refreshing token, we'll wait 1000ms and try again");
|
||||
|
||||
// Re-check the queue periodically to see if it's finished yet
|
||||
// TODO: Look at properly hooking up with the ajax finish event
|
||||
setTimeout(
|
||||
() => {
|
||||
// Return myself for a re-check
|
||||
return getToken(dispatch, getState);
|
||||
},
|
||||
1000
|
||||
);
|
||||
} else {
|
||||
refreshToken(dispatch, getState)
|
||||
.then(
|
||||
response => {
|
||||
resolve(response.access_token)
|
||||
},
|
||||
error => {
|
||||
reject(error)
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function refreshToken(dispatch, getState){
|
||||
return new Promise((resolve, reject) => {
|
||||
|
||||
// add reference to loader queue
|
||||
var loader_key = helpers.generateGuid();
|
||||
dispatch(uiActions.startLoading(loader_key, 'spotify_refresh_token'));
|
||||
|
||||
// Fully-authorized, so we can use the local Spotify credentials
|
||||
if (getState().spotify.authorization){
|
||||
|
||||
var config = {
|
||||
@ -132,6 +158,8 @@ function refreshToken(dispatch, getState){
|
||||
$.ajax(config)
|
||||
.then(
|
||||
response => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
|
||||
response.token_expiry = new Date().getTime() + (response.expires_in * 1000 )
|
||||
response.source = 'spotify'
|
||||
dispatch({
|
||||
@ -141,6 +169,8 @@ function refreshToken(dispatch, getState){
|
||||
resolve(response)
|
||||
},
|
||||
(xhr, status, error) => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
|
||||
reject({
|
||||
config: config,
|
||||
xhr: xhr,
|
||||
@ -149,7 +179,9 @@ function refreshToken(dispatch, getState){
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
// Server-side authorized (with limited scope) so we need to refresh
|
||||
// using the Mopidy-Spotify credentials
|
||||
} else {
|
||||
|
||||
var config = {
|
||||
@ -162,6 +194,8 @@ function refreshToken(dispatch, getState){
|
||||
$.ajax(config)
|
||||
.then(
|
||||
(response, status, xhr) => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
|
||||
if (response.error){
|
||||
reject({
|
||||
config: config,
|
||||
@ -184,6 +218,8 @@ function refreshToken(dispatch, getState){
|
||||
|
||||
},
|
||||
(xhr, status, error) => {
|
||||
dispatch(uiActions.stopLoading(loader_key));
|
||||
|
||||
reject({
|
||||
config: config,
|
||||
xhr: xhr,
|
||||
@ -252,7 +288,7 @@ export function importAuthorization(authorization){
|
||||
**/
|
||||
export function getMe(){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'me' )
|
||||
request(dispatch, getState, 'me' )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -278,7 +314,7 @@ export function getMe(){
|
||||
**/
|
||||
export function getTrack(uri){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'tracks/'+ helpers.getFromUri('trackid', uri))
|
||||
request(dispatch, getState, 'tracks/'+ helpers.getFromUri('trackid', uri))
|
||||
.then(
|
||||
response => {
|
||||
dispatch(coreActions.trackLoaded(response));
|
||||
@ -295,7 +331,7 @@ export function getTrack(uri){
|
||||
|
||||
export function getLibraryTracks(){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'me/tracks?limit=50')
|
||||
request(dispatch, getState, 'me/tracks?limit=50')
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -334,7 +370,7 @@ export function getFeaturedPlaylists(){
|
||||
|
||||
var timestamp = year+'-'+month+'-'+day+'T'+hour+':'+min+':'+sec;
|
||||
|
||||
sendRequest(dispatch, getState, 'browse/featured-playlists?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale+'timestamp='+timestamp)
|
||||
request(dispatch, getState, 'browse/featured-playlists?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale+'timestamp='+timestamp)
|
||||
.then(
|
||||
response => {
|
||||
var playlists = []
|
||||
@ -363,7 +399,7 @@ export function getFeaturedPlaylists(){
|
||||
type: 'SPOTIFY_FEATURED_PLAYLISTS_LOADED',
|
||||
data: {
|
||||
message: response.message,
|
||||
playlists: helpers.upgradePlaylistsUris(helpers.arrayOf('uri',response.playlists.items))
|
||||
playlists: helpers.upgradeSpotifyPlaylistUris(helpers.arrayOf('uri',response.playlists.items))
|
||||
}
|
||||
});
|
||||
},
|
||||
@ -379,7 +415,7 @@ export function getFeaturedPlaylists(){
|
||||
|
||||
export function getCategories(){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'browse/categories?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
request(dispatch, getState, 'browse/categories?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -399,7 +435,7 @@ export function getCategories(){
|
||||
|
||||
export function getCategory(id){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'browse/categories/'+id+'?country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
request(dispatch, getState, 'browse/categories/'+id+'?country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -425,7 +461,7 @@ export function getCategory(id){
|
||||
|
||||
export function getCategoryPlaylists(id){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'browse/categories/'+id+'/playlists?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
request(dispatch, getState, 'browse/categories/'+id+'/playlists?limit=50&country='+getState().spotify.country+'&locale='+getState().spotify.locale )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -446,7 +482,7 @@ export function getCategoryPlaylists(id){
|
||||
|
||||
export function getNewReleases(){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'browse/new-releases?country='+getState().spotify.country+'&limit=50' )
|
||||
request(dispatch, getState, 'browse/new-releases?country='+getState().spotify.country+'&limit=50' )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -466,7 +502,7 @@ export function getNewReleases(){
|
||||
|
||||
export function getURL(url, action_name, key = false){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, url )
|
||||
request(dispatch, getState, url )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -487,7 +523,7 @@ export function getURL(url, action_name, key = false){
|
||||
|
||||
export function getMore(url, core_action = null, custom_action = null){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, url)
|
||||
request(dispatch, getState, url)
|
||||
.then(
|
||||
response => {
|
||||
if (core_action){
|
||||
@ -538,7 +574,7 @@ export function getSearchResults(type, query, limit = 50, offset = 0){
|
||||
url += '&limit='+limit
|
||||
url += '&offset='+offset
|
||||
|
||||
sendRequest(dispatch, getState, url )
|
||||
request(dispatch, getState, url )
|
||||
.then(
|
||||
response => {
|
||||
if (response.tracks !== undefined){
|
||||
@ -628,7 +664,7 @@ export function getAutocompleteResults(field_id, query, types = ['album','artist
|
||||
endpoint += '&type='+types.join(',')
|
||||
endpoint += '&country='+getState().spotify.country
|
||||
|
||||
sendRequest(dispatch, getState, endpoint)
|
||||
request(dispatch, getState, endpoint)
|
||||
.then(
|
||||
response => {
|
||||
var genres = []
|
||||
@ -740,7 +776,7 @@ export function following(uri, method = 'GET'){
|
||||
break;
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, endpoint, method, data)
|
||||
request(dispatch, getState, endpoint, method, data)
|
||||
.then(
|
||||
response => {
|
||||
if (response ) is_following = response
|
||||
@ -777,7 +813,7 @@ export function resolveRadioSeeds(radio){
|
||||
artist_ids += helpers.getFromUri('artistid', radio.seed_artists[i])
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, 'artists?ids='+ artist_ids )
|
||||
request(dispatch, getState, 'artists?ids='+ artist_ids )
|
||||
.then(
|
||||
response => {
|
||||
if (response && response.artists){
|
||||
@ -805,7 +841,7 @@ export function resolveRadioSeeds(radio){
|
||||
track_ids += helpers.getFromUri('trackid', radio.seed_tracks[i])
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, 'tracks?ids='+ track_ids )
|
||||
request(dispatch, getState, 'tracks?ids='+ track_ids )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -842,8 +878,8 @@ export function getFavorites(limit = 50, term = 'long_term'){
|
||||
dispatch({type: 'SPOTIFY_FAVORITES_LOADED', artists: [], tracks: []})
|
||||
|
||||
$.when(
|
||||
sendRequest(dispatch, getState, 'me/top/artists?limit='+limit+'&time_range='+term),
|
||||
sendRequest(dispatch, getState, 'me/top/tracks?limit='+limit+'&time_range='+term)
|
||||
request(dispatch, getState, 'me/top/artists?limit='+limit+'&time_range='+term),
|
||||
request(dispatch, getState, 'me/top/tracks?limit='+limit+'&time_range='+term)
|
||||
|
||||
).then(
|
||||
(artists_response, tracks_response) => {
|
||||
@ -918,7 +954,7 @@ export function getRecommendations(uris = [], limit = 20, tunabilities = null){
|
||||
}
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, endpoint)
|
||||
request(dispatch, getState, endpoint)
|
||||
.then(
|
||||
response => {
|
||||
var tracks = Object.assign([], response.tracks);
|
||||
@ -991,7 +1027,7 @@ export function getRecommendations(uris = [], limit = 20, tunabilities = null){
|
||||
**/
|
||||
export function getGenres(){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'recommendations/available-genre-seeds')
|
||||
request(dispatch, getState, 'recommendations/available-genre-seeds')
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1032,7 +1068,7 @@ export function getArtist(uri, full = false){
|
||||
|
||||
// We need our artist, obviously
|
||||
var requests = [
|
||||
sendRequest(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) )
|
||||
request(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) )
|
||||
.then(
|
||||
response => {
|
||||
Object.assign(artist, response);
|
||||
@ -1050,7 +1086,7 @@ export function getArtist(uri, full = false){
|
||||
if (full){
|
||||
|
||||
requests.push(
|
||||
sendRequest(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/top-tracks?country='+getState().spotify.country )
|
||||
request(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/top-tracks?country='+getState().spotify.country )
|
||||
.then(
|
||||
response => {
|
||||
Object.assign(artist, response);
|
||||
@ -1065,7 +1101,7 @@ export function getArtist(uri, full = false){
|
||||
);
|
||||
|
||||
requests.push(
|
||||
sendRequest(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/related-artists' )
|
||||
request(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/related-artists' )
|
||||
.then(
|
||||
response => {
|
||||
dispatch(coreActions.artistsLoaded(response.artists));
|
||||
@ -1094,7 +1130,7 @@ export function getArtist(uri, full = false){
|
||||
|
||||
// Now go get our artist albums
|
||||
if (full){
|
||||
sendRequest(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/albums?market='+getState().spotify.country )
|
||||
request(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/albums?market='+getState().spotify.country )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1125,7 +1161,7 @@ export function getArtists(uris){
|
||||
ids += helpers.getFromUri('artistid', uris[i] );
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, 'artists/?ids='+ids )
|
||||
request(dispatch, getState, 'artists/?ids='+ids )
|
||||
.then(
|
||||
response => {
|
||||
for (var i = i; i < response.length; i++){
|
||||
@ -1163,7 +1199,7 @@ export function playArtistTopTracks(uri){
|
||||
|
||||
// We need to load the artist's top tracks first
|
||||
} else {
|
||||
sendRequest(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/top-tracks?country='+getState().spotify.country )
|
||||
request(dispatch, getState, 'artists/'+ helpers.getFromUri('artistid', uri) +'/top-tracks?country='+getState().spotify.country )
|
||||
.then(
|
||||
response => {
|
||||
const uris = helpers.arrayOf('uri',response.tracks)
|
||||
@ -1189,7 +1225,7 @@ export function playArtistTopTracks(uri){
|
||||
|
||||
export function getUser(uri){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri))
|
||||
request(dispatch, getState, 'users/'+ helpers.getFromUri('userid',uri))
|
||||
.then(
|
||||
response => {
|
||||
dispatch(coreActions.userLoaded(helpers.formatUser(response)));
|
||||
@ -1208,7 +1244,7 @@ export function getUserPlaylists(uri){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// get the first page of playlists
|
||||
sendRequest(dispatch, getState, 'users/'+ helpers.getFromUri('userid', uri) +'/playlists?limit=40' )
|
||||
request(dispatch, getState, 'users/'+ helpers.getFromUri('userid', uri) +'/playlists?limit=40' )
|
||||
.then(
|
||||
response => {
|
||||
var playlists = [];
|
||||
@ -1260,7 +1296,7 @@ export function getAlbum(uri){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// get the album
|
||||
sendRequest(dispatch, getState, 'albums/'+ helpers.getFromUri('albumid', uri) )
|
||||
request(dispatch, getState, 'albums/'+ helpers.getFromUri('albumid', uri) )
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -1299,7 +1335,7 @@ export function getAlbum(uri){
|
||||
}
|
||||
|
||||
// get all album artists as full objects
|
||||
sendRequest(dispatch, getState, 'artists/?ids='+artist_ids )
|
||||
request(dispatch, getState, 'artists/?ids='+artist_ids )
|
||||
.then(
|
||||
response => {
|
||||
dispatch(coreActions.artistsLoaded(response.artists));
|
||||
@ -1328,7 +1364,7 @@ export function toggleAlbumInLibrary(uri, method){
|
||||
if (method == 'DELETE' ) var new_state = 0
|
||||
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'me/albums?ids='+ helpers.getFromUri('albumid',uri), method )
|
||||
request(dispatch, getState, 'me/albums?ids='+ helpers.getFromUri('albumid',uri), method )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1366,7 +1402,7 @@ export function createPlaylist(name, description, is_public, is_collaborative){
|
||||
collaborative: is_collaborative
|
||||
}
|
||||
|
||||
sendRequest(dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/', 'POST', data)
|
||||
request(dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/', 'POST', data)
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1411,7 +1447,7 @@ export function savePlaylist(uri, name, description, is_public, is_collaborative
|
||||
}
|
||||
|
||||
// Update the playlist fields
|
||||
sendRequest(
|
||||
request(
|
||||
dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/'+ helpers.getFromUri('playlistid',uri), 'PUT', data)
|
||||
.then(
|
||||
response => {
|
||||
@ -1419,7 +1455,7 @@ export function savePlaylist(uri, name, description, is_public, is_collaborative
|
||||
|
||||
// Save the image
|
||||
if (image){
|
||||
sendRequest(dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/'+ helpers.getFromUri('playlistid',uri)+'/images', 'PUT', image)
|
||||
request(dispatch, getState, 'users/'+ getState().spotify.me.id +'/playlists/'+ helpers.getFromUri('playlistid',uri)+'/images', 'PUT', image)
|
||||
.then(
|
||||
|
||||
response => {
|
||||
@ -1470,7 +1506,7 @@ export function getPlaylist(uri){
|
||||
return (dispatch, getState) => {
|
||||
|
||||
// get the main playlist object
|
||||
sendRequest(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
|
||||
request(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) +'?market='+getState().spotify.country )
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -1533,7 +1569,7 @@ export function getLibraryTracksAndPlay(uri){
|
||||
|
||||
export function getLibraryTracksAndPlayProcessor(data){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, data.next)
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -1614,7 +1650,7 @@ export function getPlaylistTracksAndPlay(uri, shuffle){
|
||||
|
||||
export function getPlaylistTracksAndPlayProcessor(data){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, data.next)
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
response => {
|
||||
|
||||
@ -1685,7 +1721,7 @@ export function toggleFollowingPlaylist(uri, method){
|
||||
if (method == 'DELETE' ) var new_state = 0
|
||||
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/followers', method )
|
||||
request(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/followers', method )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1706,7 +1742,7 @@ export function toggleFollowingPlaylist(uri, method){
|
||||
|
||||
export function addTracksToPlaylist(uri, tracks_uris){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'POST', { uris: tracks_uris } )
|
||||
request(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'POST', { uris: tracks_uris } )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1728,7 +1764,7 @@ export function addTracksToPlaylist(uri, tracks_uris){
|
||||
|
||||
export function deleteTracksFromPlaylist(uri, snapshot_id, tracks_indexes){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'DELETE', { snapshot_id: snapshot_id, positions: tracks_indexes } )
|
||||
request(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'DELETE', { snapshot_id: snapshot_id, positions: tracks_indexes } )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1750,7 +1786,7 @@ export function deleteTracksFromPlaylist(uri, snapshot_id, tracks_indexes){
|
||||
|
||||
export function reorderPlaylistTracks(uri, range_start, range_length, insert_before, snapshot_id){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'PUT', { uri: uri, range_start: range_start, range_length: range_length, insert_before: insert_before, snapshot_id: snapshot_id } )
|
||||
request(dispatch, getState, 'playlists/'+ helpers.getFromUri('playlistid',uri) + '/tracks', 'PUT', { uri: uri, range_start: range_start, range_length: range_length, insert_before: insert_before, snapshot_id: snapshot_id } )
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1808,7 +1844,7 @@ export function getLibraryPlaylists(){
|
||||
|
||||
export function getLibraryPlaylistsProcessor(data){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, data.next)
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1879,7 +1915,7 @@ export function getLibraryArtists(){
|
||||
|
||||
export function getLibraryArtistsProcessor(data){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, data.next)
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
@ -1949,7 +1985,7 @@ export function getLibraryAlbums(){
|
||||
|
||||
export function getLibraryAlbumsProcessor(data){
|
||||
return (dispatch, getState) => {
|
||||
sendRequest(dispatch, getState, data.next)
|
||||
request(dispatch, getState, data.next)
|
||||
.then(
|
||||
response => {
|
||||
dispatch({
|
||||
|
||||
@ -197,7 +197,7 @@ const SpotifyMiddleware = (function(){
|
||||
delete action.playlists;
|
||||
|
||||
// Upgrade our URIs
|
||||
action.uris = helpers.upgradePlaylistsUris(action.uris);
|
||||
action.uris = helpers.upgradeSpotifyPlaylistUris(action.uris);
|
||||
|
||||
next(action);
|
||||
break;
|
||||
|
||||
@ -50,12 +50,25 @@ export function setSlimMode(slim_mode){
|
||||
}
|
||||
}
|
||||
|
||||
export function setWindowFocus(window_focus){
|
||||
return {
|
||||
type: 'SET_WINDOW_FOCUS',
|
||||
window_focus: window_focus
|
||||
}
|
||||
}
|
||||
|
||||
export function hideContextMenu(){
|
||||
return {
|
||||
type: 'HIDE_CONTEXT_MENU'
|
||||
}
|
||||
}
|
||||
|
||||
export function removeContextMenu(){
|
||||
return {
|
||||
type: 'REMOVE_CONTEXT_MENU'
|
||||
}
|
||||
}
|
||||
|
||||
export function showTouchContextMenu(data){
|
||||
return {
|
||||
type: 'SHOW_TOUCH_CONTEXT_MENU',
|
||||
@ -69,6 +82,12 @@ export function hideTouchContextMenu(){
|
||||
}
|
||||
}
|
||||
|
||||
export function removeTouchContextMenu(){
|
||||
return {
|
||||
type: 'REMOVE_TOUCH_CONTEXT_MENU'
|
||||
}
|
||||
}
|
||||
|
||||
export function lazyLoading(start){
|
||||
return {
|
||||
type: 'LAZY_LOADING',
|
||||
@ -136,6 +155,12 @@ export function createBrowserNotification(data){
|
||||
}
|
||||
|
||||
export function createNotification(data){
|
||||
|
||||
// Allow 'message' as an alias of our content
|
||||
if (data.message){
|
||||
data.content = data.message;
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'CREATE_NOTIFICATION',
|
||||
notification: Object.assign(
|
||||
|
||||
@ -64,12 +64,36 @@ const UIMiddleware = (function(){
|
||||
|
||||
case 'CLOSE_MODAL':
|
||||
if (store.getState().ui.allow_reporting){
|
||||
ReactGA.event({ category: 'Modal', action: 'Closed', label: null });
|
||||
}
|
||||
ReactGA.event({ category: 'Modal', action: 'Closed', label: null });
|
||||
}
|
||||
$('body').removeClass('modal-open')
|
||||
next(action)
|
||||
break
|
||||
|
||||
case 'HIDE_CONTEXT_MENU':
|
||||
if (store.getState().ui.context_menu){
|
||||
setTimeout(
|
||||
() => {
|
||||
store.dispatch(uiActions.removeContextMenu())
|
||||
},
|
||||
200
|
||||
);
|
||||
next(action);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'HIDE_TOUCH_CONTEXT_MENU':
|
||||
if (store.getState().ui.context_menu){
|
||||
setTimeout(
|
||||
() => {
|
||||
store.dispatch(uiActions.removeTouchContextMenu())
|
||||
},
|
||||
200
|
||||
);
|
||||
next(action);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'BROWSER_NOTIFICATION':
|
||||
|
||||
var notification = window.Notification || window.mozNotification || window.webkitNotification;
|
||||
|
||||
@ -10,6 +10,9 @@ export default function reducer(ui = {}, action){
|
||||
case 'SET_SLIM_MODE':
|
||||
return Object.assign({}, ui, { slim_mode: action.slim_mode });
|
||||
|
||||
case 'SET_WINDOW_FOCUS':
|
||||
return Object.assign({}, ui, { window_focus: action.window_focus });
|
||||
|
||||
case 'DEBUG':
|
||||
return Object.assign({}, ui, { debug_response: action.response })
|
||||
|
||||
@ -50,6 +53,15 @@ export default function reducer(ui = {}, action){
|
||||
});
|
||||
|
||||
case 'HIDE_CONTEXT_MENU':
|
||||
return Object.assign(
|
||||
{},
|
||||
ui,
|
||||
{
|
||||
context_menu: Object.assign({}, ui.context_menu, {closing: true})
|
||||
}
|
||||
);
|
||||
|
||||
case 'REMOVE_CONTEXT_MENU':
|
||||
return Object.assign({}, ui, {context_menu: null});
|
||||
|
||||
case 'SHOW_TOUCH_CONTEXT_MENU':
|
||||
@ -58,6 +70,15 @@ export default function reducer(ui = {}, action){
|
||||
});
|
||||
|
||||
case 'HIDE_TOUCH_CONTEXT_MENU':
|
||||
return Object.assign(
|
||||
{},
|
||||
ui,
|
||||
{
|
||||
touch_context_menu: Object.assign({}, ui.touch_context_menu, {closing: true})
|
||||
}
|
||||
);
|
||||
|
||||
case 'REMOVE_TOUCH_CONTEXT_MENU':
|
||||
return Object.assign({}, ui, {touch_context_menu: null});
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user