Play shuffled playlist, fixes #302

This commit is contained in:
James Barnsley
2018-06-26 08:51:11 +12:00
parent 1d492bbfef
commit 8ede56d876
11 changed files with 22918 additions and 20901 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -77,7 +77,7 @@
// Release details
// These are automatically injected to built HTML
var build = "1529257445";
var build = "1529956787";
var version = "3.21.2";
// Construct the script tag

View File

@ -215,6 +215,11 @@ class ContextMenu extends React.Component{
this.props.mopidyActions.playPlaylist(this.props.menu.uris[0]);
}
shufflePlayPlaylist(e){
this.props.uiActions.hideContextMenu();
this.props.mopidyActions.playPlaylist(this.props.menu.uris[0], true);
}
playArtistTopTracks(e){
this.props.uiActions.hideContextMenu();
this.props.spotifyActions.playArtistTopTracks(this.props.menu.uris[0]);
@ -454,6 +459,14 @@ class ContextMenu extends React.Component{
</span>
)
var shuffle_play_playlist = (
<span className="menu-item-wrapper">
<a className="menu-item" onClick={e => this.shufflePlayPlaylist(e)}>
<span className="label">Shuffle play</span>
</a>
</span>
)
var play_queue_item = (
<span className="menu-item-wrapper">
<a className="menu-item" onClick={e => this.playQueueItem(e)}>
@ -645,6 +658,7 @@ class ContextMenu extends React.Component{
return (
<div>
{play_playlist}
{shuffle_play_playlist}
{this.canBeInLibrary() ? <div className="divider" /> : null}
{this.canBeInLibrary() ? toggle_in_library : null}
<div className="divider" />
@ -658,6 +672,7 @@ class ContextMenu extends React.Component{
return (
<div>
{play_playlist}
{shuffle_play_playlist}
{this.canBeInLibrary() ? <div className="divider" /> : null}
{this.canBeInLibrary() ? toggle_in_library : null}
<div className="divider" />

View File

@ -715,6 +715,23 @@ export let sortItems = function (array, property, reverse = false, sort_map = nu
return sorted;
}
/**
* Shuffle items in place
*
* @param Array items
* @return Array
**/
export let shuffle = function(array){
var j, x, i;
for (i = array.length - 1; i > 0; i--) {
j = Math.floor(Math.random() * (i + 1));
x = array[i];
array[i] = array[j];
array[j] = x;
}
return array;
}
/**
* Figure out if a value is a number
* @param value = mixed

View File

@ -246,10 +246,11 @@ export function enqueueURIsBatchDone(){
}
}
export function playPlaylist(uri){
export function playPlaylist(uri, shuffle = false){
return {
type: 'MOPIDY_PLAY_PLAYLIST',
uri: uri
uri: uri,
shuffle: shuffle
}
}

View File

@ -546,14 +546,14 @@ const MopidyMiddleware = (function(){
// make sure we didn't get this playlist from Mopidy-Spotify
// if we did, we'd have a cached version on server so no need to fetch
if (!store.getState().core.playlists[action.uri].is_mopidy){
store.dispatch(spotifyActions.getPlaylistTracksAndPlay(action.uri))
store.dispatch(spotifyActions.getPlaylistTracksAndPlay(action.uri, action.shuffle))
break
}
// it's a spotify playlist that we haven't loaded
// we need to fetch via HTTP API to avoid timeout
} else if (helpers.uriSource(action.uri) == 'spotify' && store.getState().spotify.enabled){
store.dispatch(spotifyActions.getPlaylistTracksAndPlay(action.uri))
store.dispatch(spotifyActions.getPlaylistTracksAndPlay(action.uri, action.shuffle))
break
// Not in index, and Spotify HTTP not enabled, so just play it as-is
@ -567,7 +567,10 @@ const MopidyMiddleware = (function(){
if (response.tracks === undefined){
store.dispatch(uiActions.createNotification({content: 'Failed to load playlist tracks', type: 'bad'}));
} else {
var tracks_uris = helpers.arrayOf('uri',response.tracks)
var tracks_uris = helpers.arrayOf('uri',response.tracks);
if (action.shuffle){
tracks_uris = helpers.shuffle(tracks_uris);
}
store.dispatch(mopidyActions.playURIs(tracks_uris, action.uri))
}
},

View File

@ -1655,14 +1655,15 @@ export function getLibraryTracksAndPlayProcessor(data){
* Recursively get .next until we have all tracks
**/
export function getPlaylistTracksAndPlay(uri){
export function getPlaylistTracksAndPlay(uri, shuffle){
return (dispatch, getState) => {
dispatch(uiActions.startProcess(
'SPOTIFY_GET_PLAYLIST_TRACKS_AND_PLAY_PROCESSOR',
'Loading playlist tracks',
{
uri: uri,
next: 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'/tracks?market='+getState().spotify.country
next: 'users/'+ helpers.getFromUri('userid',uri) +'/playlists/'+ helpers.getFromUri('playlistid',uri) +'/tracks?market='+getState().spotify.country,
shuffle: shuffle
}
))
}
@ -1704,17 +1705,24 @@ export function getPlaylistTracksAndPlayProcessor(data){
{
next: response.next,
total: response.total,
remaining: response.total - uris.length
remaining: response.total - uris.length,
shuffle: data.shuffle
}
))
dispatch(uiActions.runProcess(
'SPOTIFY_GET_PLAYLIST_TRACKS_AND_PLAY_PROCESSOR',
{
next: response.next,
uris: uris
uris: uris,
shuffle: data.shuffle
}
))
} else {
if (data.shuffle){
uris = helpers.shuffle(uris);
}
dispatch(mopidyActions.playURIs(uris, data.uri))
dispatch(uiActions.processFinishing('SPOTIFY_GET_PLAYLIST_TRACKS_AND_PLAY_PROCESSOR'))
}

View File

@ -60,7 +60,7 @@ class LibraryAlbums extends React.Component{
if (newProps.mopidy_uri_schemes.includes('spotify:') && (newProps.source == 'all' || newProps.source == 'spotify')){
// Filter changed, but we haven't got this provider's library yet
if (this.props.source != 'all' && this.props.source != 'spotify' && newProps.spotify_library_albums_status != 'finished' && newProps.spotify_library_albums_status != 'started'){
if (newProps.spotify_library_albums_status != 'finished' && newProps.spotify_library_albums_status != 'started'){
this.props.spotifyActions.getLibraryAlbums();
}
}

View File

@ -56,7 +56,7 @@ class LibraryArtists extends React.Component{
if (newProps.mopidy_uri_schemes.includes('spotify:') && (newProps.source == 'all' || newProps.source == 'spotify')){
// Filter changed, but we haven't got this provider's library yet
if (this.props.source != 'all' && this.props.source != 'spotify' && newProps.spotify_library_artists_status != 'finished'){
if (newProps.spotify_library_artists_status != 'finished' && newProps.spotify_library_artists_status != 'started'){
this.props.spotifyActions.getLibraryArtists();
}
}

View File

@ -58,7 +58,7 @@ class LibraryPlaylists extends React.Component{
if (newProps.mopidy_uri_schemes.includes('spotify:') && (newProps.source == 'all' || newProps.source == 'spotify')){
// Filter changed, but we haven't got this provider's library yet
if (this.props.source != 'all' && this.props.source != 'spotify' && newProps.spotify_library_playlists_status !== 'finished'){
if (newProps.spotify_library_playlists_status != 'finished' && newProps.spotify_library_playlists_status != 'started'){
this.props.spotifyActions.getLibraryPlaylists()
}
}