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 (
{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);