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'; import { i18n, I18n } from '../locale'; import Button from '../components/Button'; import { indexToArray } from '../util/arrays'; const Artwork = ({ image, album_uri, }) => { if (!image) { return (
); } return (
); } class Queue extends React.Component { constructor(props) { super(props); this.state = { limit: 50, per_page: 50, }; } componentDidMount() { const { uiActions: { setWindowTitle, }, location: { limit, } = {}, } = this.props; if (limit) this.setState({ limit }); setWindowTitle(i18n('now_playing.title')); } shouldComponentUpdate(nextProps) { return nextProps !== this.props; } componentDidUpdate = ({ added_from_uri: prev_added_from_uri, }) => { const { coreActions: { loadItem, }, added_from_uri, } = this.props; if (added_from_uri && added_from_uri !== prev_added_from_uri) { loadItem(added_from_uri, { full: false }); } } 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: { removeTracks: doRemoveTracks, }, } = 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) { doRemoveTracks(tlids); } } playTrack = (track) => { const { mopidyActions: { changeTrack } } = this.props; changeTrack(track.tlid); } playTracks = (tracks) => { const { mopidyActions: { changeTrack } } = this.props; changeTrack(tracks[0].tlid); } reorderTracks = (indexes, index) => { const { mopidyActions: { reorderTracklist } } = this.props; reorderTracklist(indexes, index); } renderAddedFrom = () => { const { items, added_from_uri, } = this.props; if (!added_from_uri) return null; const uri_type = uriType(added_from_uri); let addedFromItems = []; // Radio nests it's seed URIs in an encoded URI format switch (uri_type){ case 'radio': addedFromItems = indexToArray(items, getFromUri('seeds', added_from_uri)); break; case 'search': addedFromItems = [{ uri: added_from_uri, name: `"${getFromUri('searchterm', added_from_uri)}" search`, }]; break; default: addedFromItems = indexToArray(items, [added_from_uri]); break; } if (!addedFromItems.length) return null; return (
{addedFromItems[0].images && ( )}
{'Playing from '} {uri_type === 'radio' && ( {i18n('now_playing.current_track.radio')} )}
); } render = () => { const { current_track, queue_tracks, stream_title, theme, current_track_uri, spotify_enabled, uiActions, mopidyActions: { clearTracklist, shuffleTracklist, }, } = 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 && current_track_uri) { if (current_track.images !== undefined && current_track.images) { current_track_image = current_track.images.large; } } const options = ( <> {spotify_enabled && ( )} ); return (
{theme === 'dark' && }
{current_track ? ( {current_track.name} ) : ( - )}
{ (current_track && current_track.artists && ( )) || (stream_title && ( {stream_title} )) || } {this.renderAddedFrom()}
  • {`${queue_tracks.length} tracks`}
  • {queue_tracks.length > 0 && (
  • )} {queue_tracks.length > 0 && (
  • )}
limit ? limit : total_queue_tracks } showLoader={limit < total_queue_tracks} loadMore={this.loadMore} />
); } } const mapStateToProps = (state) => { const { current_track: core_current_track, stream_title, items, queue, queue_metadata, } = state.core; const queue_tracks = []; let current_track = {}; if (queue && items) { for (const queue_track of queue) { let track = { ...queue_track, playing: core_current_track && core_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 (items[track.uri]) { track = { ...items[track.uri], ...track, }; } // Now merge in our queue metadata if (queue_metadata[`tlid_${track.tlid}`] !== undefined) { track = { ...track, ...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), items, 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, stream_title, }; }; 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);