Removing proxy_request in favor of hosted proxy; Adding icecast control to Outputs; Buttons tidy-up

This commit is contained in:
James Barnsley
2018-07-01 21:08:35 +12:00
parent 7bd5066fe2
commit 122f99d027
15 changed files with 698 additions and 714 deletions

View File

@ -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)

View File

@ -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),

View File

@ -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>

View File

@ -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)} &nbsp;
<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)} &nbsp;
<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>
);
}