Removing proxy_request in favor of hosted proxy; Adding icecast control to Outputs; Buttons tidy-up
This commit is contained in:
@ -7,9 +7,10 @@ import VolumeControl from './VolumeControl'
|
||||
import Icon from '../Icon'
|
||||
|
||||
import * as helpers from '../../helpers'
|
||||
import * as coreActions from '../../services/core/actions'
|
||||
import * as pusherActions from '../../services/pusher/actions'
|
||||
|
||||
class SnapcastVolumeControl extends React.Component{
|
||||
class OutputControl extends React.Component{
|
||||
|
||||
constructor(props){
|
||||
super(props);
|
||||
@ -21,14 +22,8 @@ class SnapcastVolumeControl extends React.Component{
|
||||
this.handleClick = this.handleClick.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if (this.props.pusher_connected && this.props.snapcast_enabled){
|
||||
this.props.pusherActions.getSnapcast();
|
||||
}
|
||||
}
|
||||
|
||||
handleClick(e){
|
||||
if ($(e.target).closest('.snapcast-volume-control').length <= 0){
|
||||
if ($(e.target).closest('.output-control').length <= 0){
|
||||
this.setExpanded(false);
|
||||
}
|
||||
}
|
||||
@ -37,13 +32,20 @@ class SnapcastVolumeControl extends React.Component{
|
||||
if (expanded){
|
||||
this.setState({expanded: expanded});
|
||||
window.addEventListener("click", this.handleClick, false);
|
||||
|
||||
// Re-check our snapcast clients
|
||||
// TODO: Once we have push events, remove this as it'll (marginally)
|
||||
// slow down the reveal/render
|
||||
if (this.props.pusher_connected && this.props.snapcast_enabled){
|
||||
this.props.pusherActions.getSnapcast();
|
||||
}
|
||||
} else {
|
||||
this.setState({expanded: expanded});
|
||||
window.removeEventListener("click", this.handleClick, false);
|
||||
}
|
||||
}
|
||||
|
||||
renderVolumes(){
|
||||
renderOutputs(){
|
||||
|
||||
var clients = [];
|
||||
for (var key in this.props.snapcast_clients){
|
||||
@ -56,13 +58,25 @@ class SnapcastVolumeControl extends React.Component{
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="volumes">
|
||||
<div className="outputs">
|
||||
{this.props.http_streaming_enabled ? <div className="output icecast-output">
|
||||
<span className="name">
|
||||
Local browser
|
||||
</span>
|
||||
<VolumeControl
|
||||
className="client-volume-control"
|
||||
volume={this.props.http_streaming_volume}
|
||||
mute={this.props.http_streaming_mute}
|
||||
onVolumeChange={percent => this.props.coreActions.set({http_streaming_volume: percent})}
|
||||
onMuteChange={mute => this.props.coreActions.set({http_streaming_mute: mute})}
|
||||
/>
|
||||
</div> : null}
|
||||
{
|
||||
clients.map(client => {
|
||||
var name = client.config.name ? client.config.name : client.host.name;
|
||||
|
||||
return (
|
||||
<div className="client" key={client.id}>
|
||||
<div className="output snapcast-output" key={client.id}>
|
||||
<span className="name">
|
||||
{name}
|
||||
</span>
|
||||
@ -84,14 +98,14 @@ class SnapcastVolumeControl extends React.Component{
|
||||
render(){
|
||||
if (this.state.expanded){
|
||||
return (
|
||||
<span className="snapcast-volume-control">
|
||||
<span className="output-control">
|
||||
<a className="control speakers active" onClick={e => this.setExpanded()}><Icon name="speaker" /></a>
|
||||
{this.renderVolumes()}
|
||||
{this.renderOutputs()}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span className="snapcast-volume-control">
|
||||
<span className="output-control">
|
||||
<a className="control speakers" onClick={e => this.setExpanded()}><Icon name="speaker" /></a>
|
||||
</span>
|
||||
);
|
||||
@ -101,6 +115,9 @@ class SnapcastVolumeControl extends React.Component{
|
||||
|
||||
const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
http_streaming_enabled: state.core.http_streaming_enabled,
|
||||
http_streaming_volume: state.core.http_streaming_volume,
|
||||
http_streaming_mute: state.core.http_streaming_mute,
|
||||
snapcast_enabled: state.pusher.config.snapcast_enabled,
|
||||
pusher_connected: state.pusher.connected,
|
||||
snapcast_clients: state.pusher.snapcast_clients
|
||||
@ -109,8 +126,9 @@ const mapStateToProps = (state, ownProps) => {
|
||||
|
||||
const mapDispatchToProps = (dispatch) => {
|
||||
return {
|
||||
coreActions: bindActionCreators(coreActions, dispatch),
|
||||
pusherActions: bindActionCreators(pusherActions, dispatch)
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(SnapcastVolumeControl)
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(OutputControl)
|
||||
@ -6,7 +6,7 @@ import { bindActionCreators } from 'redux'
|
||||
|
||||
import ProgressSlider from './Fields/ProgressSlider'
|
||||
import VolumeControl from './Fields/VolumeControl'
|
||||
import SnapcastVolumeControl from './Fields/SnapcastVolumeControl'
|
||||
import OutputControl from './Fields/OutputControl'
|
||||
import Dater from './Dater'
|
||||
import ArtistSentence from './ArtistSentence'
|
||||
import Thumbnail from './Thumbnail'
|
||||
@ -45,20 +45,45 @@ class PlaybackControls extends React.Component{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use our track's URI as a cache mechanism. This prevents the browser from starting
|
||||
// the stream right back at the beginning (which would play from the browser's cache, ie first render)
|
||||
var url = props.http_streaming_url+"?cache_buster="+props.current_track.uri;
|
||||
|
||||
console.log("Playing stream: "+url);
|
||||
|
||||
this.stream.muted = this.props.http_streaming_mute;
|
||||
this.stream.volume = this.props.http_streaming_volume / 100;
|
||||
this.stream.src = url;
|
||||
this.stream.play();
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps){
|
||||
|
||||
// When the track changes, update our stream URL to reflect the cache buster
|
||||
// TODO: This will crop the end of tracks by the duration of the buffer. Perhaps create
|
||||
// a timestamp to only update the stream when a track has been skipped?
|
||||
if (!this.props.current_track && nextProps.current_track ||
|
||||
this.props.current_track && nextProps.current_track && this.props.current_track.uri !== nextProps.current_track.uri){
|
||||
|
||||
this.playStream(nextProps);
|
||||
}
|
||||
|
||||
// Currently have a stream running
|
||||
if (this.stream){
|
||||
|
||||
// Just been muted
|
||||
if (this.props.http_streaming_mute !== nextProps.http_streaming_mute){
|
||||
this.stream.muted = nextProps.http_streaming_mute;
|
||||
}
|
||||
|
||||
// Just had volume changed
|
||||
if (this.props.http_streaming_volume !== nextProps.http_streaming_volume){
|
||||
this.stream.volume = nextProps.http_streaming_volume / 100;
|
||||
}
|
||||
|
||||
// Just been disabled
|
||||
if (nextProps.http_streaming_enabled){
|
||||
this.stream = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
renderPlayButton(){
|
||||
@ -138,7 +163,7 @@ class PlaybackControls extends React.Component{
|
||||
{this.renderConsumeButton()}
|
||||
{this.renderRandomButton()}
|
||||
{this.renderRepeatButton()}
|
||||
{this.props.snapcast_enabled ? <SnapcastVolumeControl /> : null}
|
||||
<OutputControl />
|
||||
</section>
|
||||
|
||||
<section className="progress">
|
||||
@ -182,8 +207,9 @@ const mapStateToProps = (state, ownProps) => {
|
||||
return {
|
||||
snapcast_enabled: state.pusher.config.snapcast_enabled,
|
||||
http_streaming_enabled: state.core.http_streaming_enabled,
|
||||
http_streaming_encoding: state.core.http_streaming_encoding,
|
||||
http_streaming_url: state.core.http_streaming_url,
|
||||
http_streaming_volume: (state.core.http_streaming_volume ? state.core.http_streaming_volume : 50),
|
||||
http_streaming_mute: (state.core.http_streaming_mute ? state.core.http_streaming_mute : false),
|
||||
http_streaming_url: (state.core.http_streaming_url ? state.core.http_streaming_url : null),
|
||||
current_track: (state.core.current_track && state.core.tracks[state.core.current_track.uri] !== undefined ? state.core.tracks[state.core.current_track.uri] : null),
|
||||
next_track: (state.core.next_track_uri && state.core.tracks[state.core.next_track_uri] !== undefined ? state.core.tracks[state.core.next_track_uri] : null),
|
||||
radio_enabled: (state.ui.radio && state.ui.radio.enabled ? true : false),
|
||||
|
||||
@ -223,28 +223,6 @@ class Services extends React.Component{
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field radio">
|
||||
<div className="name">Encoding</div>
|
||||
<div className="input">
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="http_streaming_encoding"
|
||||
checked={this.props.core.http_streaming_encoding == 'mpeg'}
|
||||
onChange={e => this.props.coreActions.set({http_streaming_encoding: 'mpeg'})} />
|
||||
<span className="label">mpeg (mp3)</span>
|
||||
</label>
|
||||
<label>
|
||||
<input
|
||||
type="radio"
|
||||
name="http_streaming_encoding"
|
||||
checked={this.props.core.http_streaming_encoding == 'ogg'}
|
||||
onChange={e => this.props.coreActions.set({http_streaming_encoding: 'ogg'})} />
|
||||
<span className="label">ogg</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="field">
|
||||
<div className="name">Location</div>
|
||||
<div className="input">
|
||||
@ -297,7 +275,7 @@ class Services extends React.Component{
|
||||
</div>
|
||||
<div className="menu-item-wrapper">
|
||||
<Link className={"menu-item"+(this.props.active == 'snapcast' ? ' active' : '')} to={this.props.active == 'snapcast' ? global.baseURL+'settings' : global.baseURL+'settings/service/snapcast'}>
|
||||
<Icon type="fontawesome" name="sliders" />
|
||||
<Icon name="devices" />
|
||||
<div className="title">
|
||||
Snapcast
|
||||
</div>
|
||||
@ -306,7 +284,7 @@ class Services extends React.Component{
|
||||
</div>
|
||||
<div className="menu-item-wrapper">
|
||||
<Link className={"menu-item"+(this.props.active == 'icecast' ? ' active' : '')} to={this.props.active == 'icecast' ? global.baseURL+'settings' : global.baseURL+'settings/service/icecast'}>
|
||||
<Icon name="rss_feed" />
|
||||
<Icon name="wifi_tethering" />
|
||||
<div className="title">
|
||||
Icecast
|
||||
</div>
|
||||
|
||||
@ -184,8 +184,15 @@ class Snapcast extends React.Component{
|
||||
<div className="snapcast">
|
||||
|
||||
<div className="field checkbox">
|
||||
<div className="name">
|
||||
Display
|
||||
</div>
|
||||
<div className="input">
|
||||
<button onClick={e => this.props.pusherActions.getSnapcast()}>Refresh</button>
|
||||
<button
|
||||
className="small"
|
||||
onClick={e => this.props.pusherActions.getSnapcast()}>
|
||||
Refresh
|
||||
</button>
|
||||
<label>
|
||||
<input
|
||||
type="checkbox"
|
||||
@ -199,74 +206,76 @@ class Snapcast extends React.Component{
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{
|
||||
groups.map(group => {
|
||||
<div className="groups">
|
||||
{
|
||||
groups.map(group => {
|
||||
|
||||
// Average our clients' volume for an overall group volume
|
||||
var group_volume = 0;
|
||||
for (var i = 0; i < group.clients.length; i++){
|
||||
var client = group.clients[i];
|
||||
group_volume += client.config.volume.percent;
|
||||
}
|
||||
group_volume = group_volume / group.clients.length;
|
||||
// Average our clients' volume for an overall group volume
|
||||
var group_volume = 0;
|
||||
for (var i = 0; i < group.clients.length; i++){
|
||||
var client = group.clients[i];
|
||||
group_volume += client.config.volume.percent;
|
||||
}
|
||||
group_volume = group_volume / group.clients.length;
|
||||
|
||||
return (
|
||||
<div className="group" key={group.id}>
|
||||
<div className="field">
|
||||
<div className="name">
|
||||
Name
|
||||
return (
|
||||
<div className="group" key={group.id}>
|
||||
<div className="field">
|
||||
<div className="name">
|
||||
Name
|
||||
</div>
|
||||
<div className="input">
|
||||
<div className="text">
|
||||
{group.name ? group.name : 'Group '+group.id.substring(0,3)}
|
||||
<span className="grey-text">({group.id})</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="input">
|
||||
<div className="text">
|
||||
{group.name ? group.name : 'Group '+group.id.substring(0,3)}
|
||||
<span className="grey-text">({group.id})</span>
|
||||
<div className="field dropdown">
|
||||
<div className="name">
|
||||
Stream
|
||||
</div>
|
||||
<div className="input">
|
||||
<select onChange={e => this.props.pusherActions.setSnapcastGroupStream(group.id, e.target.value)} value={group.stream_id}>
|
||||
{
|
||||
streams.map(stream => {
|
||||
return (
|
||||
<option value={stream.id} key={stream.id}>
|
||||
{stream.id} ({stream.status})
|
||||
</option>
|
||||
);
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">
|
||||
Volume
|
||||
</div>
|
||||
<div className="input">
|
||||
<VolumeControl
|
||||
className="group-volume-control"
|
||||
volume={group_volume}
|
||||
mute={group.muted}
|
||||
onVolumeChange={(percent, old_percent) => this.props.pusherActions.setSnapcastGroupVolume(group.id, percent, old_percent)}
|
||||
onMuteChange={mute => this.props.pusherActions.setSnapcastGroupMute(group.id, mute)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">
|
||||
Clients
|
||||
</div>
|
||||
<div className="input">
|
||||
{this.renderClientsList(group, groups)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field dropdown">
|
||||
<div className="name">
|
||||
Stream
|
||||
</div>
|
||||
<div className="input">
|
||||
<select onChange={e => this.props.pusherActions.setSnapcastGroupStream(group.id, e.target.value)} value={group.stream_id}>
|
||||
{
|
||||
streams.map(stream => {
|
||||
return (
|
||||
<option value={stream.id} key={stream.id}>
|
||||
{stream.id} ({stream.status})
|
||||
</option>
|
||||
);
|
||||
})
|
||||
}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">
|
||||
Volume
|
||||
</div>
|
||||
<div className="input">
|
||||
<VolumeControl
|
||||
className="group-volume-control"
|
||||
volume={group_volume}
|
||||
mute={group.muted}
|
||||
onVolumeChange={(percent, old_percent) => this.props.pusherActions.setSnapcastGroupVolume(group.id, percent, old_percent)}
|
||||
onMuteChange={mute => this.props.pusherActions.setSnapcastGroupMute(group.id, mute)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="field">
|
||||
<div className="name">
|
||||
Clients
|
||||
</div>
|
||||
<div className="input">
|
||||
{this.renderClientsList(group, groups)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user