mirror of
https://github.com/ragestudio/comty.git
synced 2025-06-10 02:54:15 +00:00
update StreamViewer
This commit is contained in:
parent
ec249b70db
commit
b976a595df
@ -1,15 +1,25 @@
|
||||
import React from 'react'
|
||||
import React from "react"
|
||||
import config from "config"
|
||||
import * as antd from "antd"
|
||||
import Plyr from 'plyr'
|
||||
import Hls from 'hls.js'
|
||||
import mpegts from 'mpegts.js'
|
||||
import { Icons } from "components/Icons"
|
||||
import moment from "moment"
|
||||
|
||||
import Plyr from "plyr"
|
||||
import Hls from "hls.js"
|
||||
import mpegts from "mpegts.js"
|
||||
|
||||
import "plyr/dist/plyr.css"
|
||||
import "./index.less"
|
||||
|
||||
const streamsSource = "http://media.ragestudio.net/live"
|
||||
const streamsSource = config.remotes.streamingApi
|
||||
|
||||
export default class StreamViewer extends React.Component {
|
||||
state = {
|
||||
userData: null,
|
||||
streamInfo: null,
|
||||
spectators: 0,
|
||||
timeFromNow: "00:00:00",
|
||||
|
||||
player: null,
|
||||
streamKey: null,
|
||||
streamSource: null,
|
||||
@ -22,18 +32,98 @@ export default class StreamViewer extends React.Component {
|
||||
|
||||
componentDidMount = async () => {
|
||||
const query = new URLSearchParams(window.location.search)
|
||||
const requested = query.get("key")
|
||||
const requestedUsername = query.get("key")
|
||||
|
||||
const source = `${streamsSource}/${requested}`
|
||||
const player = new Plyr('#player')
|
||||
const source = `${streamsSource}/${requestedUsername}`
|
||||
const player = new Plyr("#player", {
|
||||
autoplay: true,
|
||||
controls: ["play", "mute", "volume", "fullscreen", "options", "settings"],
|
||||
})
|
||||
|
||||
await this.setState({
|
||||
player,
|
||||
streamKey: requested,
|
||||
streamKey: requestedUsername,
|
||||
streamSource: source,
|
||||
})
|
||||
|
||||
await this.loadWithProtocol[this.state.loadedProtocol]()
|
||||
|
||||
// make the interface a bit confortable for a video player
|
||||
app.ThemeController.applyVariant("dark")
|
||||
app.eventBus.emit("toogleCompactMode", true)
|
||||
app.SidebarController.toogleVisible(false)
|
||||
app.HeaderController.toogleVisible(false)
|
||||
|
||||
// fetch user info in the background
|
||||
this.gatherUserInfo()
|
||||
|
||||
// fetch stream info in the background
|
||||
// await for it
|
||||
await this.gatherStreamInfo()
|
||||
|
||||
// create timer
|
||||
if (this.state.streamInfo.connectCreated) {
|
||||
this.createTimerCounter()
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount = () => {
|
||||
app.ThemeController.applyVariant(app.settings.get("themeVariant"))
|
||||
app.eventBus.emit("toogleCompactMode", false)
|
||||
app.SidebarController.toogleVisible(true)
|
||||
app.HeaderController.toogleVisible(true)
|
||||
app.HeaderController.toogleVisible(true)
|
||||
|
||||
if (this.timerCounterInterval) {
|
||||
this.timerCounterInterval = clearInterval(this.timerCounterInterval)
|
||||
}
|
||||
}
|
||||
|
||||
gatherStreamInfo = async () => {
|
||||
const result = await app.request.get.streamInfoFromUsername(undefined, {
|
||||
username: this.state.streamKey,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
antd.message.error(error.message)
|
||||
return false
|
||||
})
|
||||
|
||||
if (result) {
|
||||
this.setState({
|
||||
streamInfo: result,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
gatherUserInfo = async () => {
|
||||
const result = await app.request.get.user(undefined, {
|
||||
username: this.state.streamKey,
|
||||
}).catch((error) => {
|
||||
console.error(error)
|
||||
antd.message.error(error.message)
|
||||
return false
|
||||
})
|
||||
|
||||
if (result) {
|
||||
this.setState({
|
||||
userData: result,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
createTimerCounter = () => {
|
||||
this.timerCounterInterval = setInterval(() => {
|
||||
const secondsFromNow = moment().diff(moment(this.state.streamInfo.connectCreated), "seconds")
|
||||
|
||||
// calculate hours minutes and seconds
|
||||
const hours = Math.floor(secondsFromNow / 3600)
|
||||
const minutes = Math.floor((secondsFromNow - hours * 3600) / 60)
|
||||
const seconds = secondsFromNow - hours * 3600 - minutes * 60
|
||||
|
||||
this.setState({
|
||||
timeFromNow: `${hours}:${minutes}:${seconds}`,
|
||||
})
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
updateQuality = (newQuality) => {
|
||||
@ -60,10 +150,10 @@ export default class StreamViewer extends React.Component {
|
||||
console.log("Switching to " + protocol)
|
||||
this.loadWithProtocol[protocol]()
|
||||
}
|
||||
|
||||
|
||||
loadWithProtocol = {
|
||||
hls: () => {
|
||||
const source = `${this.state.streamSource}.m3u8`
|
||||
const source = `${streamsSource}/stream/hls/${this.state.streamKey}`
|
||||
const hls = new Hls()
|
||||
|
||||
hls.loadSource(source)
|
||||
@ -72,9 +162,13 @@ export default class StreamViewer extends React.Component {
|
||||
this.setState({ protocolInstance: hls, loadedProtocol: "hls" })
|
||||
},
|
||||
flv: () => {
|
||||
const source = `${this.state.streamSource}.flv`
|
||||
const source = `${streamsSource}/stream/flv/${this.state.streamKey}`
|
||||
|
||||
const instance = mpegts.createPlayer({ type: 'flv', url: source, isLive: true })
|
||||
const instance = mpegts.createPlayer({
|
||||
type: "flv",
|
||||
url: source,
|
||||
isLive: true
|
||||
})
|
||||
|
||||
instance.attachMediaElement(this.videoPlayerRef.current)
|
||||
instance.load()
|
||||
@ -85,15 +179,39 @@ export default class StreamViewer extends React.Component {
|
||||
}
|
||||
|
||||
render() {
|
||||
return <div>
|
||||
<antd.Select
|
||||
onChange={(value) => this.switchProtocol(value)}
|
||||
value={this.state.loadedProtocol}
|
||||
>
|
||||
<antd.Select.Option value="hls">HLS</antd.Select.Option>
|
||||
<antd.Select.Option value="flv">FLV</antd.Select.Option>
|
||||
</antd.Select>
|
||||
return <div className="stream">
|
||||
<video ref={this.videoPlayerRef} id="player" />
|
||||
<div className="panel">
|
||||
<div className="info">
|
||||
<div className="title">
|
||||
<div>
|
||||
<antd.Avatar
|
||||
shape="square"
|
||||
src={this.state.userData?.avatar}
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<h2>{this.state.userData?.username}</h2>
|
||||
</div>
|
||||
</div>
|
||||
<div id="spectatorCount">
|
||||
<Icons.Eye />
|
||||
{this.state.spectators}
|
||||
</div>
|
||||
<div id="timeCount">
|
||||
<Icons.Clock />
|
||||
{this.state.timeFromNow}
|
||||
</div>
|
||||
</div>
|
||||
<div className="chatbox">
|
||||
{/* TODO: Use chatbox component and join to stream channel using username */}
|
||||
<antd.Result>
|
||||
<h1>
|
||||
Cannot connect with chat server
|
||||
</h1>
|
||||
</antd.Result>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
92
packages/app/src/pages/streams/viewer/index.less
Normal file
92
packages/app/src/pages/streams/viewer/index.less
Normal file
@ -0,0 +1,92 @@
|
||||
.plyr__controls {
|
||||
width: 100%;
|
||||
display: inline-flex;
|
||||
//justify-content: space-between;
|
||||
}
|
||||
|
||||
.stream {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
|
||||
color: var(--background-color-contrast);
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
span,
|
||||
p {
|
||||
color: var(--background-color-contrast);
|
||||
}
|
||||
|
||||
.panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: 100vh;
|
||||
width: 20vw;
|
||||
|
||||
.info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-start;
|
||||
|
||||
width: 100%;
|
||||
height: 10vh;
|
||||
|
||||
padding: 10px;
|
||||
|
||||
backdrop-filter: 20px;
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5 {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
>div {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
height: fit-content;
|
||||
margin-bottom: 8px;
|
||||
|
||||
>div {
|
||||
margin-right: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.chatbox {
|
||||
width: 20vw;
|
||||
padding: 20px;
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
#spectatorCount {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
#timeCount {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.plyr {
|
||||
border-radius: 0 4px 4px 0;
|
||||
width: 80vw;
|
||||
height: 100vh;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user