Tracks and Queue overhaul

This commit is contained in:
James Barnsley
2017-11-10 15:56:01 +13:00
parent e2dbbac98b
commit 93cbbaa7fa
15 changed files with 256 additions and 281 deletions

View File

@ -81,8 +81,8 @@ export function set(data){
**/
export function reorderPlaylistTracks(uri, indexes, insert_before, snapshot_id = false){
var range = helpers.createRange(indexes );
switch(helpers.uriSource(uri )){
var range = helpers.createRange(indexes);
switch(helpers.uriSource(uri)){
case 'spotify':
return {

View File

@ -186,81 +186,6 @@ const CoreMiddleware = (function(){
next(action)
break
case 'MOPIDY_CURRENTTLTRACK':
if (action.data && action.data.track){
helpers.setWindowTitle(action.data.track, store.getState().mopidy.play_state);
// make sure our images use mopidy host:port
if (action.data.track.album && action.data.track.album.images && action.data.track.album.images.length > 0){
var images = Object.assign([], action.data.track.album.images)
for (var i = 0; i < images.length; i++){
if (typeof(images[i]) === 'string' && images[i].startsWith('/images/')){
images[i] = '//'+store.getState().mopidy.host+':'+store.getState().mopidy.port+images[i]
}
}
action.data.track.album.images = images
}
}
var current_tracklist = []
Object.assign(current_tracklist, core.current_tracklist)
for (var i = 0; i < current_tracklist.length; i++){
Object.assign(
current_tracklist[i],
{ playing: (current_tracklist[i].tlid == action.data.tlid) }
)
}
// Update action
action.current_tracklist = current_tracklist;
action.current_track = action.data.track.uri;
next(action);
break;
case 'MOPIDY_TLTRACKS':
var core = store.getState().core;
var tracklist = []
for (var i = 0; i < action.data.length; i++){
var tltrack = helpers.formatTracks(action.data[i]);
// load our metadata (if we have any for that tlid)
if (core.queue_metadata !== undefined && core.queue_metadata['tlid_'+tltrack.tlid] !== undefined){
var metadata = core.queue_metadata['tlid_'+tltrack.tlid]
} else {
var metadata = {}
}
var current_tlid = null;
if (core.current_track && core.tracks && core.tracks[core.current_track] !== undefined && core.tracks[core.current_track].tlid !== undefined){
current_tlid = core.tracks[core.current_track].tlid;
}
var track = Object.assign(
{},
tltrack,
metadata,
{
playing: (tltrack.tlid == current_tlid)
})
tracklist.push(track)
}
// Append to our action
tracklist = helpers.formatTracks(tracklist);
action.tracklist = tracklist;
// Load our tracks into index
store.dispatch({
type: 'TRACKS_LOADED',
tracks: tracklist
});
next(action);
break
// Get assets from all of our providers
case 'GET_LIBRARY_PLAYLISTS':
if (store.getState().spotify.connected){
@ -295,8 +220,115 @@ const CoreMiddleware = (function(){
break
case 'RESTART':
location.reload()
break
location.reload();
break;
/**
* Playlist manipulation
**/
case 'PLAYLIST_KEY_UPDATED':
var playlists = Object.assign({}, core.playlists);
if (playlists[action.key] === undefined){
dispatch(coreActions.handleException("Cannot change key of playlist not in index"));
}
// Delete our old playlist by key, and add by new key
var playlist = Object.assign({}, playlists[action.key]);
delete playlists[action.key];
playlists[action.new_key] = playlist;
store.dispatch({
type: 'UPDATE_PLAYLISTS_INDEX',
playlists: playlists
});
break;
case 'PLAYLIST_TRACKS_REORDERED':
var playlists = Object.assign({}, core.playlists);
var playlist = Object.assign({}, playlists[action.key]);
var tracks_uris = Object.assign([], playlist.tracks_uris);
// handle insert_before offset if we're moving BENEATH where we're slicing tracks
var insert_before = action.insert_before
if (insert_before > action.range_start){
insert_before = insert_before - action.range_length;
}
// cut our moved tracks into a new array
var tracks_to_move = tracks_uris.splice(action.range_start, action.range_length)
tracks_to_move.reverse()
for (i = 0; i < tracks_to_move.length; i++){
tracks_uris.splice(insert_before, 0, tracks_to_move[i])
}
var snapshot_id = null;
if (action.snapshot_id){
snapshot_id = action.snapshot_id;
}
// Update our playlist
playlist.tracks_uris = tracks_uris;
playlist.snapshot_id = snapshot_id;
// Trigger normal playlist updating
store.dispatch({
type: 'PLAYLISTS_LOADED',
playlists: [playlist]
});
break;
case 'PLAYLIST_TRACKS_REMOVED':
var playlists = Object.assign({}, core.playlists);
var playlist = Object.assign({}, playlists[action.key]);
var tracks_uris = Object.assign([], playlist.tracks_uris);
var indexes = action.tracks_indexes.reverse()
for(var i = 0; i < indexes.length; i++){
tracks_uris.splice(indexes[i], 1);
}
var snapshot_id = null;
if (action.snapshot_id){
snapshot_id = action.snapshot_id;
}
// Update our playlist
playlist.tracks_uris = tracks_uris;
playlist.snapshot_id = snapshot_id;
// Trigger normal playlist updating
store.dispatch({
type: 'PLAYLISTS_LOADED',
playlists: [playlist]
});
break;
/**
* Queue and playback info
**/
case 'CURRENT_TRACK_LOADED':
store.dispatch({
type: 'TRACKS_LOADED',
tracks: [action.current_track]
});
next(action);
break;
case 'QUEUE_LOADED':
store.dispatch({
type: 'TRACKS_LOADED',
tracks: action.tracks
});
action.tracks_uris = helpers.arrayOf('uri',action.tracks);
next(action);
break;
/**
@ -309,8 +341,7 @@ const CoreMiddleware = (function(){
store.dispatch({
type: 'TRACKS_LOADED',
tracks: [action.track]
})
next(action);
});
break;
// Array wrapper for ALBUMS_LOADED
@ -319,7 +350,6 @@ const CoreMiddleware = (function(){
type: 'ALBUMS_LOADED',
albums: [action.album]
});
next(action);
break;
// Array wrapper for ARTISTS_LOADED
@ -328,7 +358,6 @@ const CoreMiddleware = (function(){
type: 'ARTISTS_LOADED',
artists: [action.artist]
});
next(action);
break;
// Array wrapper for PLAYLISTS_LOADED
@ -337,7 +366,6 @@ const CoreMiddleware = (function(){
type: 'PLAYLISTS_LOADED',
playlists: [action.playlist]
});
next(action);
break;
// Array wrapper for USERS_LOADED
@ -346,7 +374,6 @@ const CoreMiddleware = (function(){
type: 'USERS_LOADED',
users: [action.user]
});
next(action);
break;
case 'TRACKS_LOADED':
@ -361,6 +388,7 @@ const CoreMiddleware = (function(){
if (track.album && track.album.images && track.album.images.length > 0){
track.album.images = helpers.digestMopidyImages(store.getState().mopidy, track.album.images);
track.images = track.album.images;
}
tracks[track.uri] = track;
@ -523,7 +551,7 @@ const CoreMiddleware = (function(){
user = Object.assign({}, users[user.uri], user);
}
users[action.key] = user;
users[user.uri] = user;
}
// Update index
@ -542,6 +570,7 @@ const CoreMiddleware = (function(){
**/
case 'LOADED_MORE':
console.log(action);
var parent_type_plural = action.parent_type+'s';
var parent_index = Object.assign({}, core[action.parent_type+'s']);
var parent = Object.assign({}, parent_index[action.parent_key]);
@ -569,7 +598,10 @@ const CoreMiddleware = (function(){
var records_uris = helpers.arrayOf('uri', records);
// Append our records_uris array with our new records
var uris = [...parent[records_type_plural+'_uris'], ...records_uris];
var uris = records_uris;
if (parent[records_type_plural+'_uris'] !== undefined){
uris = [...parent[records_type_plural+'_uris'], ...uris];
}
parent[records_type_plural+'_uris'] = uris;
if (action.records_data.next !== undefined){
parent[records_type_plural+'_more'] = action.records_data.next;

View File

@ -11,19 +11,14 @@ export default function reducer(core = {}, action){
* Current track and tracklist
**/
case 'MOPIDY_TLTRACKS':
if (!action.tracklist){
return core;
}
return Object.assign({}, core, { current_tracklist: action.tracklist });
case 'MOPIDY_CURRENTTLTRACK':
if (!action.data){
return core;
}
case 'CURRENT_TRACK_LOADED':
return Object.assign({}, core, {
current_tracklist: action.current_tracklist,
current_track: action.current_track
current_track_uri: action.current_track_uri
});
case 'QUEUE_LOADED':
return Object.assign({}, core, {
queue: action.tracks_uris
});
case 'PUSHER_QUEUE_METADATA':
@ -190,50 +185,6 @@ export default function reducer(core = {}, action){
* Playlists
**/
case 'PLAYLIST_KEY_UPDATED':
var playlists = Object.assign([], core.playlists)
// URI not in our index? No change needed then
if (typeof(playlists[action.key]) === 'undefined'){
return core
}
// Delete our old playlist by key, and add by new key
var playlist = Object.assign({}, playlists[action.key])
delete playlists[action.key]
playlists[playlist.uri] = playlist
return Object.assign({}, core, { playlists: playlists });
case 'PLAYLIST_LOADED_MORE_TRACKS':
var playlists = Object.assign([], core.playlists)
var playlist = Object.assign(
{},
playlists[action.key],
{
tracks: [...playlists[action.key].tracks, ...helpers.formatTracks(action.data.items)],
tracks_more: action.data.next,
tracks_total: action.data.total
}
)
playlists[action.key] = playlist
return Object.assign({}, core, { playlists: playlists });
case 'PLAYLIST_TRACKS_REMOVED':
var playlists = Object.assign([], core.playlists)
var playlist = Object.assign({}, playlists[action.key])
var tracks = Object.assign([], playlist.tracks)
var indexes = action.tracks_indexes.reverse()
for(var i = 0; i < indexes.length; i++){
tracks.splice(indexes[i], 1 )
}
var snapshot_id = null
if (action.snapshot_id ) snapshot_id = action.snapshot_id
Object.assign(playlist, { tracks: tracks, snapshot_id: snapshot_id })
playlists[action.key] = playlist
return Object.assign({}, core, { playlists: playlists });
case 'PLAYLIST_TRACKS':
var playlists = Object.assign([], core.playlists)
var playlist = Object.assign({}, playlists[action.key], { tracks: helpers.formatTracks(action.tracks) })
@ -241,29 +192,6 @@ export default function reducer(core = {}, action){
playlists[action.key] = playlist
return Object.assign({}, core, { playlists: playlists });
case 'PLAYLIST_TRACKS_REORDERED':
var playlists = Object.assign([], core.playlists)
var playlist = Object.assign({}, playlists[action.key])
var tracks = Object.assign([], playlist.tracks)
// handle insert_before offset if we're moving BENEATH where we're slicing tracks
var insert_before = action.insert_before
if (insert_before > action.range_start ) insert_before = insert_before - action.range_length
// cut our moved tracks into a new array
var tracks_to_move = tracks.splice(action.range_start, action.range_length)
tracks_to_move.reverse()
for(i = 0; i < tracks_to_move.length; i++){
tracks.splice(insert_before, 0, tracks_to_move[i])
}
var snapshot_id = null
if (action.snapshot_id ) snapshot_id = action.snapshot_id
Object.assign(playlist, { tracks: tracks, snapshot_id: snapshot_id })
playlists[action.key] = playlist
return Object.assign({}, core, { playlists: playlists });
case 'LIBRARY_PLAYLISTS_LOADED':
if (core.library_playlists){
var library_playlists = [...core.library_playlists, ...action.uris]

View File

@ -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');
/**
* Send an ajax request to the LastFM API
@ -150,34 +150,9 @@ export function revokeAuthorization(){
return { type: 'LASTFM_AUTHORIZATION_REVOKED' }
}
export function connect(){
return (dispatch, getState) => {
dispatch({ type: 'LASTFM_CONNECTING' });
// Authorized? Multi-purpose our connection test to get the current user
if (getState().lastfm.session){
dispatch(getMe());
// Not authorized? Just use a generic lookup to test our connection
} else {
sendRequest(dispatch, getState, 'method=artist.getInfo&artist=Moby')
.then(
response => {
dispatch({ type: 'LASTFM_CONNECTED' })
},
error => {
dispatch({ type: 'LASTFM_DISCONNECTED' })
}
)
}
}
}
/**
* Signed requests
* TODO
**/
export function loveTrack(uri, artist, track){
@ -218,6 +193,35 @@ export function unloveTrack(uri, artist, track){
}
}
export function scrobble(track){
return (dispatch, getState) => {
var track_name = track.name;
var artist_name = "Unknown";
if (track.artists){
artist_name = track.artists[0].name;
}
var artist_name = encodeURIComponent(artist_name);
var params = 'method=track.scrobble';
params += '&track='+track_name+'&artist='+artist_name;
params += '&timestamp='+Math.floor(Date.now() / 1000);
sendSignedRequest(dispatch, getState, params)
.then(
response => {
console.log("Scrobbled", response);
},
error => {
dispatch(coreActions.handleException(
'Could not scrobble track',
error,
(error.description ? error.description : null)
));
}
)
}
}
/**
* Non-signed requests
@ -331,32 +335,3 @@ export function getTrack(track, artist_name = null, track_name = null){
}
}
export function scrobble(track){
return (dispatch, getState) => {
var track_name = track.name;
var artist_name = "Unknown";
if (track.artists){
artist_name = track.artists[0].name;
}
var artist_name = encodeURIComponent(artist_name);
var params = 'method=track.scrobble';
params += '&track='+track_name+'&artist='+artist_name;
params += '&timestamp='+Math.floor(Date.now() / 1000);
sendSignedRequest(dispatch, getState, params)
.then(
response => {
console.log("Scrobbled", response);
},
error => {
dispatch(coreActions.handleException(
'Could not scrobble track',
error,
(error.description ? error.description : null)
));
}
)
}
}

View File

@ -1259,11 +1259,11 @@ const MopidyMiddleware = (function(){
type: 'PLAYLIST_KEY_UPDATED',
key: action.key,
new_key: response.uri
})
hashHistory.push(global.baseURL+'playlist/'+response.uri)
});
hashHistory.push(global.baseURL+'playlist/'+encodeURIComponent(response.uri));
}
store.dispatch(uiActions.createNotification('Saved'))
store.dispatch(uiActions.createNotification('Saved'));
})
});
break
@ -1703,17 +1703,17 @@ const MopidyMiddleware = (function(){
* ======================================================================================
**/
case 'MOPIDY_TLTRACKS':
store.dispatch({
type: 'QUEUE_LOADED',
tracks: helpers.formatTracks(action.data)
})
break;
case 'MOPIDY_CURRENTTLTRACK':
if (action.data && action.data.track){
var track = helpers.formatTracks(action.data);
// Fire off our universal track index loader
store.dispatch({
type: 'TRACK_LOADED',
key: track.uri,
track: track
});
// We've got Spotify running, and it's a spotify track - go straight to the source!
if (helpers.uriSource(track.uri) == 'spotify' && store.getState().spotify.enabled){
store.dispatch(spotifyActions.getTrack(track.uri))
@ -1722,9 +1722,16 @@ const MopidyMiddleware = (function(){
} else {
store.dispatch(mopidyActions.getImages('tracks',[track.uri]))
}
}
next(action);
// Set our window title to the track title
helpers.setWindowTitle(track, store.getState().mopidy.play_state);
store.dispatch({
type: 'CURRENT_TRACK_LOADED',
current_track: track,
current_track_uri: track.uri
});
}
break;
case 'MOPIDY_GET_TRACK':

View File

@ -232,10 +232,6 @@ export function importAuthorization(data){
**/
export function getMe(){
return (dispatch, getState) => {
// flush out the previous store value
dispatch({ type: 'SPOTIFY_ME_LOADED', data: false });
sendRequest(dispatch, getState, 'me' )
.then(
response => {
@ -1192,7 +1188,7 @@ export function playArtistTopTracks(uri){
* ======================================================================================
**/
export function getUser(uri){
export function getUser(uri, and_playlists = false){
return (dispatch, getState) => {
// get the user
@ -1212,7 +1208,9 @@ export function getUser(uri){
}
)
dispatch(getUserPlaylists(uri))
if (and_playlists){
dispatch(getUserPlaylists(uri));
}
}
}
@ -1242,14 +1240,11 @@ export function getUserPlaylists(user_uri){
}
dispatch({
type: 'PLAYLISTS_LOADED',
playlists: playlists
});
dispatch({
type: 'SPOTIFY_USER_PLAYLISTS_LOADED',
key: user_uri,
data: response
type: 'LOADED_MORE',
parent_type: 'user',
parent_key: user_uri,
records_type: 'playlist',
records_data: response
});
},
error => {

View File

@ -415,7 +415,7 @@ const SpotifyMiddleware = (function(){
store.dispatch({
type: 'USERS_LOADED',
users: [action.data]
})
});
next(action);
break;