import React, { Component } from "react";
import { render } from "react-dom";
import {
Container,
Header,
Icon,
Grid,
Segment,
List,
Input,
Message,
Dropdown
} from "semantic-ui-react";
import "fomantic-ui-css/semantic.min.css";
import { w3cwebsocket as W3CWebSocket } from "websocket";
import Moment from "react-moment";
import "moment/locale/es";
import "./App.css";
import StreamInfo from "./StreamInfo";
const client = new W3CWebSocket("wss://radio.bienvenidoainternet.org/daemon/");
const chatColors = [
"grey",
"red",
"pink",
"orange",
"yellow",
"green",
"teal",
"blue",
"purple",
"black"
];
class App extends Component {
constructor(props) {
super(props);
this.state = {
ready: false,
response: {},
history: [],
chat: [],
chatMessage: "",
infoUpdate: {},
currentSong: "",
streamsAvailable: [],
multipleSources: false,
selectedStream: 0,
chatUserCount: 0,
isChatOnline: false
};
this.handleOnChange = this.handleOnChange.bind(this);
this.sendMessage = this.sendMessage.bind(this);
this.streamCount = 0;
}
checkStream(result) {
const prevCount = this.streamCount;
if (result.source !== undefined) {
if (Array.isArray(result)) {
this.streamCount = result.length;
} else {
this.streamCount = 1;
}
} else {
this.streamCount = 0;
}
return prevCount === this.streamCount;
}
addMessage(message, color, own = false, sender = "") {
var ts = new Date();
this.setState(
prevState => ({
chat: [
...prevState.chat,
{ content: message, color: color, own, timestamp: ts, author: sender }
],
chatMessage: ""
}),
() => {
let chatContainer = document.getElementById("chatContainer");
if (chatContainer != null) {
chatContainer.scrollTop = chatContainer.scrollHeight;
}
}
);
}
log(object) {
if (process.env.NODE_ENV === "development") {
console.log(object);
}
}
refreshPlayer() {
let audio = document.getElementById("player");
if (audio !== null) {
audio.pause();
audio.load();
audio.play();
}
}
addToHistory(song) {
this.setState(prevState => ({
history: [...prevState.history, song]
}));
let historyContainer = document.getElementById("historyContainer");
if (historyContainer != null) {
historyContainer.scrollTop = historyContainer.scrollHeight;
}
}
sendMessage() {
const { chatMessage } = this.state;
client.send("MSG:1:" + chatMessage);
this.addMessage(chatMessage, "black", true);
this.setState({ chatMessage: "" });
}
componentWillMount() {
client.onopen = () => {
//console.info("[Chat] Connected to BaiTV Chat!");
this.setState({ isChatOnline: true });
};
client.onmessage = message => {
//console.info("[Chat] Message: " + message.data);
this.processChatMessage(message.data);
};
client.onerror = () => {
this.setState({ isChatOnline: false });
this.addMessage("Ha ocurrido un error conectándose al chat.", "red");
//console.error("[Chat] Ha ocurrido un error");
};
}
translateColon(msg) {
return msg ? msg.replace(/%3A/g, ":") : "";
}
processChatMessage(line) {
console.log("<< " + line);
const args = line.split(":");
switch (args[0]) {
case "MSG":
this.addMessage(this.translateColon(args[2]), chatColors[args[1]]);
break;
case "FMSG":
this.addMessage(
this.translateColon(args[3]),
chatColors[args[2]],
false,
args[1]
);
break;
case "WELCOME":
this.addMessage("Conectado al chat, " + args[1], "green");
break;
case "COUNT":
this.setState({ chatUserCount: args[1] });
break;
case "FLOOD":
this.addMessage(
"Error: Estas enviando mensajes demasido rápido!",
"red"
);
break;
default:
console.error("[Chat] Unsupported command " + args[0]);
break;
}
}
handleOnChange(e, data) {
this.setState({ chatMessage: data.value });
}
compareSongs() {
const {
currentSong,
multipleSources,
selectedStream,
response
} = this.state;
const currentStream = multipleSources
? response.source[selectedStream]
: response.source;
if (`${currentStream.artist} - ${currentStream.title}` !== currentSong) {
this.addToHistory(currentSong);
this.setState({
currentSong: `${currentStream.artist} - ${currentStream.title}`
});
}
}
updateInfo() {
const {
currentSong,
multipleSources,
selectedStream,
response
} = this.state;
const currentStream = multipleSources
? response.source[selectedStream]
: response.source;
if (currentSong === "") {
this.setState({
currentSong: `${currentStream.artist} - ${currentStream.title}`
});
}
fetch("https://bienvenidoainternet.org:8443/status-json.xsl")
.then(response => response.json())
.then(result => {
this.log(result);
this.checkStream(result);
const source = result.icestats.source;
if (source !== undefined) {
let multipleStreams = Array.isArray(source);
if (!multipleStreams && Array.isArray(this.state.response.source)) {
this.setState(
{
response: result.icestats,
streamsAvailable: [],
multipleSources: multipleStreams,
selectedStream: 0
},
() => this.compareSongs()
);
this.refreshPlayer();
} else {
let streams = [];
if (Array.isArray(source)) {
source.map((stream, index) =>
streams.push({
key: index,
value: index,
text: `[${stream.listeners}] ${stream.server_name} - ${stream.server_description}`
})
);
}
this.setState(
{
response: result.icestats,
streamsAvailable: streams,
multipleSources: multipleStreams
},
() => this.compareSongs()
);
}
} else {
// No hay streams disponibles
this.setState(
{
response: result.icestats,
multipleSources: true,
streamsAvailable: {},
selectedStream: 0
},
() => this.compareSongs()
);
}
});
}
componentDidMount() {
fetch("https://bienvenidoainternet.org:8443/status-json.xsl")
.then(response => response.json())
.then(result =>
this.setState(
{
response: result.icestats,
infoUpdate: setInterval(() => this.updateInfo(), 10000)
},
() => {
const { source } = this.state.response;
if (source !== undefined && Array.isArray(source)) {
let streams = [];
source.map((stream, index) =>
streams.push({
key: index,
value: index,
text: `[${stream.listeners}] ${stream.server_name} - ${stream.server_description}`
})
);
console.log(streams);
this.setState({
multipleSources: true,
streamsAvailable: streams,
ready: true
});
} else if (source !== undefined) {
this.setState({
multipleSources: false,
selectedStream: 0,
ready: true
});
}
}
)
);
}
render() {
const {
ready,
response,
history,
chat,
chatMessage,
streamsAvailable,
multipleSources,
selectedStream,
chatUserCount,
isChatOnline
} = this.state;
const isOnline = response.source !== undefined;
if (!ready) {
return "Loading";
}
const currentStream = multipleSources
? response.source[selectedStream]
: response.source;
const currentStreamURL = currentStream.listenurl.replace(
"http://bienvenidoainternet.org:8000",
"https://bienvenidoainternet.org:8443"
);
return (
<Container style={{ paddingTop: "50px" }}>
<Segment style={{ padding: "2em" }}>
<Grid stackable>
<Grid.Row columns={2}>
<Grid.Column>
<Header as="h2">
<Icon name="broadcast tower" />
<Header.Content>
BaiRadio
<Header.Subheader>
{ready ? response.server_id : "Sin información"}
</Header.Subheader>
</Header.Content>
</Header>
</Grid.Column>
<Grid.Column floated="right">
<audio
xmlns="http://www.w3.org/1999/xhtml"
controls="controls"
preload="none"
autoPlay
id="player"
>
<source src={currentStreamURL} type="application/ogg" />
</audio>
</Grid.Column>
</Grid.Row>
<Grid.Row divided columns={2}>
<Grid.Column width={6}>
{isOnline ? (
<>
{multipleSources && (
<>
<label className="dropdownLabel">
Transmisiones disponibles:
</label>
<Dropdown
defaultValue={0}
fluid
selection
options={streamsAvailable}
onChange={(e, d) =>
this.setState({ selectedStream: d.value }, () => {
let audio = document.getElementById("player");
if (audio !== null) {
audio.pause();
audio.load();
audio.play();
}
})
}
/>
</>
)}
<Header as="h3">Información de la transmisión</Header>
<StreamInfo stream={currentStream} />
</>
) : (
<Message negative>
<Message.Header>Oops</Message.Header>
Actualmente no hay nadie transmitiendo en Bai Radio
</Message>
)}
<Header as="h3">Historial de canciones</Header>
<div id="historyContainer">
<List>
{history.map((song, i) => (
<List.Item key={i}>
<List.Icon name="music" />
<List.Content>{song}</List.Content>
</List.Item>
))}
</List>
</div>
</Grid.Column>
<Grid.Column width={10}>
<Header as="h3">
Chat
<Header.Subheader>{`Usuarios en el chat: ${chatUserCount}`}</Header.Subheader>
</Header>
<div id="chatContainer">
<List>
{chat.map((message, i) => (
<List.Item key={i}>
[<Moment format="HH:mm:ss" date={message.timestamp} />]{" "}
<span className={`ui text ${message.color}`}>
{message.content}
</span>
</List.Item>
))}
</List>
</div>
<Input
fluid
size="mini"
action={{
content: "Enviar",
onClick: () => {
this.sendMessage();
},
disabled: !isChatOnline
}}
placeholder=""
value={chatMessage}
onChange={this.handleOnChange}
style={{ marginTop: "0.75em" }}
maxLength={128}
onKeyUp={e => {
let char = e.which || e.keyCode;
if (char === 13) {
this.sendMessage();
}
}}
disabled={!isChatOnline}
/>
</Grid.Column>
</Grid.Row>
</Grid>
</Segment>
<Container textAlign="center">
<span className="ui text grey">
Bienvenido a Internet 2010 - 2020
</span>
</Container>
</Container>
);
}
}
export default App;