import React from 'react'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import Link from '../components/Link'; import Icon from '../components/Icon'; import Parallax from '../components/Parallax'; import TrackList from '../components/TrackList'; import Dater from '../components/Dater'; import LinksSentence from '../components/LinksSentence'; import Thumbnail from '../components/Thumbnail'; import Header from '../components/Header'; import URILink from '../components/URILink'; import LazyLoadListener from '../components/LazyLoadListener'; import * as coreActions from '../services/core/actions'; import * as uiActions from '../services/ui/actions'; import * as pusherActions from '../services/pusher/actions'; import * as spotifyActions from '../services/spotify/actions'; import * as mopidyActions from '../services/mopidy/actions'; import { getFromUri, uriType, } from '../util/helpers'; class Queue extends React.Component { constructor(props) { super(props); this.state = { limit: 50, per_page: 50, }; } componentDidMount() { // Restore any limit defined in our location state const state = this.props.location.state ? this.props.location.state : {}; if (state.limit) { this.setState({ limit: state.limit, }); } this.props.uiActions.setWindowTitle('Now playing'); } shouldComponentUpdate(nextProps) { return nextProps !== this.props; } componentDidUpdate = ({ added_from_uri: prev_added_from_uri, }) => { const { coreActions: { loadAlbum, loadArtist, loadPlaylist, }, added_from_uri, } = this.props; if (added_from_uri && added_from_uri !== prev_added_from_uri) { const item_type = uriType(added_from_uri); switch (item_type) { case 'album': loadAlbum(added_from_uri); break; case 'artist': loadArtist(added_from_uri); break; case 'playlist': loadPlaylist(added_from_uri); break; default: break; } } } loadMore() { const { limit, per_page } = this.state; const { location, history } = this.props; const new_limit = limit + per_page; this.setState({ limit: new_limit }); // Set our pagination to location state const state = location && location.state ? location.state : {}; state.limit = new_limit; history.replace({ state }); } removeTracks(track_indexes) { const { queue_tracks, mopidyActions } = this.props; const tlids = []; for (let i = 0; i < track_indexes.length; i++) { const track = queue_tracks[track_indexes[i]]; if (track.tlid !== undefined) { tlids.push(track.tlid); } } if (tlids.length > 0) { mopidyActions.removeTracks(tlids); } } playTrack(track) { this.props.mopidyActions.changeTrack(track.tlid); } playTracks(tracks) { this.props.mopidyActions.changeTrack(tracks[0].tlid); } reorderTracks(indexes, index) { this.props.mopidyActions.reorderTracklist(indexes, index); } renderArtwork(image) { const { current_track } = this.props; const uri = (current_track && current_track.album && current_track.album.uri) ? current_track.album.uri : null; if (!image) { return (
); } return (
); } renderAddedFrom() { const { added_from_uri } = this.props; if (!added_from_uri) return null; const uri_type = uriType(added_from_uri); const items = []; // Radio nests it's seed URIs in an encoded URI format switch (uri_type){ case 'radio': const radio_seeds = getFromUri('seeds', added_from_uri); for (let seed of radio_seeds) { let item_type = uriType(seed); let item_library = this.props[`${item_type}s`]; if (item_library && item_library[seed]) { items.push(item_library[seed]); } } break; case 'search': items.push({ uri: added_from_uri, name: `"${getFromUri('searchterm', added_from_uri)}" search`, }) break; default: const item_library = this.props[`${uri_type}s`]; if (item_library && item_library[added_from_uri]) { items.push(item_library[added_from_uri]); } break; } if (items.length <= 0) return null; return (
{items[0].images && ( )}
{'Playing from '} {uri_type === 'radio' && Radio}
); } render() { const { current_track, queue_tracks } = this.props; const { limit } = this.state; const total_queue_tracks = queue_tracks.length; const tracks = queue_tracks.slice(0, limit); let current_track_image = null; if (current_track && this.props.current_track_uri) { if (current_track.images !== undefined && current_track.images) { current_track_image = current_track.images.large; } } const options = ( {this.props.spotify_enabled && ( Radio )} History Add URI ); return (
Now playing
{this.renderArtwork(current_track_image)}
{current_track ? ( {current_track.name} ) : ( - )}
{current_track ? ( ) : ( )} {this.renderAddedFrom()}
  • {`${queue_tracks.length} tracks`}
  • {queue_tracks.length > 0 && (
  • Clear queue
  • )}
this.removeTracks(track_indexes)} playTracks={(tracks) => this.playTracks(tracks)} playTrack={(track) => this.playTrack(track)} reorderTracks={(indexes, index) => this.reorderTracks(indexes, index)} />
limit ? limit : total_queue_tracks } showLoader={limit < total_queue_tracks} loadMore={() => this.loadMore()} />
); } } const mapStateToProps = (state, ownProps) => { let { current_track } = state.core; const queue_tracks = []; if (state.core.queue && state.core.tracks) { for (const queue_track of state.core.queue) { let track = { ...queue_track, playing: current_track && current_track.tlid == queue_track.tlid, }; // If we have the track in our index, merge it in. // We prioritise queue track over index track as queue has unique data, like which track // is playing and tlids. if (state.core.tracks.hasOwnProperty(track.uri)) { track = { ...state.core.tracks[track.uri], ...track, }; } // Now merge in our queue metadata if (state.core.queue_metadata[`tlid_${track.tlid}`] !== undefined) { track = { ...track, ...state.core.queue_metadata[`tlid_${track.tlid}`], }; } // Siphon off this track if it's a full representation of our current track if (track.playing) { current_track = track; } // Now add our compiled track for our tracklist queue_tracks.push(track); } } return { theme: state.ui.theme, spotify_enabled: state.spotify.enabled, radio: state.core.radio, radio_enabled: !!(state.core.radio && state.core.radio.enabled), artists: state.core.artists, albums: state.core.albums, playlists: state.core.playlists, tracks: state.core.tracks, queue_tracks, current_track_uri: state.core.current_track_uri, current_track, added_from_uri: current_track && current_track.added_from ? current_track.added_from : null, }; }; const mapDispatchToProps = (dispatch) => ({ coreActions: bindActionCreators(coreActions, dispatch), uiActions: bindActionCreators(uiActions, dispatch), pusherActions: bindActionCreators(pusherActions, dispatch), spotifyActions: bindActionCreators(spotifyActions, dispatch), mopidyActions: bindActionCreators(mopidyActions, dispatch), }); export default connect( mapStateToProps, mapDispatchToProps, )(Queue);