improve a little bit livestream player

This commit is contained in:
SrGooglo 2025-04-02 01:51:41 +00:00
parent c3d99e0d83
commit c9e222d686
2 changed files with 288 additions and 295 deletions

View File

@ -139,12 +139,10 @@ export default class StreamViewer extends React.Component {
} }
loadStream = async (stream_id) => { loadStream = async (stream_id) => {
let stream = await SpectrumModel.getLivestream(stream_id).catch( let stream = await SpectrumModel.getStream(stream_id).catch((error) => {
(error) => { console.error(error)
console.error(error) return null
return null })
},
)
if (!stream) { if (!stream) {
return false return false
@ -169,8 +167,6 @@ export default class StreamViewer extends React.Component {
this.state.decoderInstance.destroy() this.state.decoderInstance.destroy()
} }
this.state.player.destroy()
this.setState({ this.setState({
isEnded: true, isEnded: true,
loading: false, loading: false,
@ -221,15 +217,10 @@ export default class StreamViewer extends React.Component {
componentDidMount = async () => { componentDidMount = async () => {
this.enterPlayerAnimation() this.enterPlayerAnimation()
const stream_id = this.props.params.id
console.log("Stream ID >", stream_id)
this.attachPlayer() this.attachPlayer()
// get stream info // load stream
const stream = await this.loadStream(stream_id) const stream = await this.loadStream(this.props.params.id)
if (!stream) { if (!stream) {
return this.onSourceEnd() return this.onSourceEnd()
@ -254,16 +245,15 @@ export default class StreamViewer extends React.Component {
} }
componentWillUnmount = () => { componentWillUnmount = () => {
if (this.state.player) {
this.state.player.destroy()
}
if (typeof this.state.decoderInstance?.unload === "function") { if (typeof this.state.decoderInstance?.unload === "function") {
this.state.decoderInstance.unload() this.state.decoderInstance.unload()
} }
this.exitPlayerAnimation() if (typeof this.state.decoderInstance?.destroy === "function") {
this.state.decoderInstance.destroy()
}
this.exitPlayerAnimation()
this.toggleCinemaMode(false) this.toggleCinemaMode(false)
if (this.streamInfoInterval) { if (this.streamInfoInterval) {
@ -272,17 +262,21 @@ export default class StreamViewer extends React.Component {
} }
enterPlayerAnimation = () => { enterPlayerAnimation = () => {
app.cores.style.applyTemporalVariant("dark")
app.layout.toggleCompactMode(true)
app.layout.toggleCenteredContent(false) app.layout.toggleCenteredContent(false)
app.controls.toggleUIVisibility(false) app.layout.toggleTotalWindowHeight(true)
if (app.layout.tools_bar) {
app.layout.tools_bar.toggleVisibility(false)
}
} }
exitPlayerAnimation = () => { exitPlayerAnimation = () => {
app.cores.style.applyVariant(app.cores.style.currentVariantKey)
app.layout.toggleCompactMode(false)
app.layout.toggleCenteredContent(true) app.layout.toggleCenteredContent(true)
app.controls.toggleUIVisibility(true) app.layout.toggleTotalWindowHeight(false)
if (app.layout.tools_bar) {
app.layout.tools_bar.toggleVisibility(true)
}
} }
updateQuality = (newQuality) => { updateQuality = (newQuality) => {
@ -308,6 +302,9 @@ export default class StreamViewer extends React.Component {
to = !this.state.cinemaMode to = !this.state.cinemaMode
} }
app.controls.toggleUIVisibility(!to)
app.layout.toggleCompactMode(to)
this.setState({ cinemaMode: to }) this.setState({ cinemaMode: to })
} }
@ -318,21 +315,14 @@ export default class StreamViewer extends React.Component {
["cinemaMode"]: this.state.cinemaMode, ["cinemaMode"]: this.state.cinemaMode,
})} })}
> >
{this.props.query.id}
<div className="livestream_player"> <div className="livestream_player">
<div className="livestream_player_header"> <div className="livestream_player_header">
<div
className="livestream_player_header_exit"
onClick={() => app.location.back()}
>
<Icons.IoMdExit />
</div>
{this.state.stream ? ( {this.state.stream ? (
<> <>
<div className="livestream_player_header_user"> <div className="livestream_player_header_user">
<UserPreview <UserPreview
user={this.state.stream.user} user_id={this.state.stream.user_id}
onlyIcon
/> />
<div className="livestream_player_indicators"> <div className="livestream_player_indicators">
@ -350,24 +340,19 @@ export default class StreamViewer extends React.Component {
{this.state.stream.info && ( {this.state.stream.info && (
<div className="livestream_player_header_info"> <div className="livestream_player_header_info">
<div className="livestream_player_header_info_title"> <div className="livestream_player_header_title">
<h1> <h1>
{this.state.stream.info?.title} {this.state.stream.info?.title}
</h1> </h1>
</div> </div>
<div className="livestream_player_header_info_description"> <div className="livestream_player_header_description">
<Marquee mode="smooth"> <Marquee mode="smooth">
{({ index }) => { <h4>
return ( {
<h4> this.state.stream.info
{ ?.description
this.state }
.stream.info </h4>
?.description
}
</h4>
)
}}
</Marquee> </Marquee>
</div> </div>
</div> </div>

View File

@ -1,344 +1,352 @@
@panel-width: 500px;
@chatbox-header-height: 50px; @chatbox-header-height: 50px;
.content_layout {
padding: 10px;
}
html { html {
&.mobile { &.mobile {
.livestream { .livestream {
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
} }
.livestream_panel { .livestream_panel {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
height: 20%; height: 20%;
} }
.livestream_player { .livestream_player {
height: 100%; height: 100%;
width: 100%; width: 100%;
.plyr { .plyr {
width: 100%; width: 100%;
height: 100%; height: 100%;
} }
} }
} }
} }
.plyr__controls { .plyr__controls {
width: 100%; width: 100%;
display: inline-flex; display: inline-flex;
//justify-content: space-between; //justify-content: space-between;
} }
.livestream { .livestream {
position: relative; position: relative;
display: flex; display: flex;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
height: 100vh; gap: 10px;
width: 100%;
overflow: hidden; height: 100%;
width: 100%;
color: var(--background-color-contrast); color: var(--background-color-contrast);
h1, overflow: hidden;
h2,
h3,
h4,
h5,
span,
p {
color: var(--background-color-contrast);
}
&.cinemaMode { h1,
.livestream_player { h2,
width: 100vw; h3,
h4,
h5,
span,
p {
color: var(--background-color-contrast);
}
video { &.cinemaMode {
width: 100vw; .livestream_player {
} border-radius: 0px;
.plyr { .livestream_player_header {
width: 100vw; animation: disappear 0.3s ease-in-out forwards;
} }
}
.livestream_player_header { .livestream_panel {
animation: disappear 0.3s ease-in-out forwards; position: absolute;
} z-index: 99;
}
.livestream_panel { right: 0;
position: absolute; top: 0;
z-index: 99;
right: 0; height: 60vh;
top: 0; width: 20vw;
height: 60vh; padding: 20px;
width: 20vw;
padding: 20px; background-color: transparent;
overflow-x: hidden; .chatbox {
padding: 0;
.chatbox { overflow-x: hidden;
padding: 0; overflow-y: hidden;
overflow-x: hidden; .liveChat {
overflow-y: hidden; .liveChat_timeline {
padding-top: 0 !important;
.liveChat { &::after {
.liveChat_timeline { content: "";
padding-top: 0 !important; display: none;
}
}
}
}
}
}
&::after { .livestream_player {
content: ""; display: flex;
display: none; position: relative;
}
}
}
}
}
}
.livestream_player { align-items: center;
display: flex; justify-content: center;
position: relative;
align-items: center; width: 100%;
justify-content: center; height: 100%;
width: calc(100% - @panel-width); overflow-y: hidden;
height: 100%;
overflow-y: hidden; transition: all 0.3s ease-in-out;
transition: all 0.3s ease-in-out; border-radius: 24px;
.livestream_player_loading { .livestream_player_loading {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
position: absolute; position: absolute;
z-index: 90; z-index: 90;
width: 100%; width: 100%;
height: 100%; height: 100%;
backdrop-filter: blur(10px); backdrop-filter: blur(10px);
transition: all 0.3s ease-in-out; transition: all 0.3s ease-in-out;
opacity: 0; opacity: 0;
pointer-events: none; pointer-events: none;
&.active { &.active {
opacity: 1; opacity: 1;
} }
} }
video { video {
z-index: 80; z-index: 80;
} }
.livestream_player_header { .livestream_player_header {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
position: absolute; position: absolute;
z-index: 100; z-index: 100;
top: 0; top: 0;
left: 0; left: 0;
width: fit-content; width: fit-content;
height: fit-content; height: fit-content;
min-width: 20vw; min-width: 20vw;
max-width: 50vw; max-width: 50vw;
margin: 25px; margin: 25px;
padding: 10px; padding: 10px;
gap: 10px; gap: 10px;
background-color: var(--background-color-accent); background-color: var(--background-color-accent);
border-radius: 12px; border-radius: 12px;
h1, h1,
h2, h2,
h3, h3,
h4, h4,
span { span {
margin: 0; margin: 0;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.livestream_player_header_exit { .livestream_player_header_user {
display: flex; display: flex;
flex-direction: row; flex-direction: column;
width: fit-content; .livestream_player_indicators {
height: fit-content; display: flex;
flex-direction: row;
svg { align-items: center;
font-size: 1.5rem; justify-content: space-between;
margin: 0;
}
}
.livestream_player_header_user {
display: flex;
flex-direction: column;
.livestream_player_indicators { gap: 10px;
display: flex;
flex-direction: row;
align-items: center; margin-top: 10px;
justify-content: space-between;
gap: 10px; .livestream_player_header_user_spectators {
height: fit-content;
margin-top: 10px; .ant-tag {
display: flex;
flex-direction: row;
.livestream_player_header_user_spectators { align-items: center;
height: fit-content; gap: 5px;
.ant-tag { background-color: #eb0400;
background-color: #eb0400; border-color: #eb0400;
border-color: #eb0400; color: var(--background-color-contrast);
color: var(--background-color-contrast); font-size: 1rem;
font-size: 1rem; }
} }
}
.livestream_player_header_user_quality { .livestream_player_header_user_quality {
font-size: 1.8rem; font-size: 1.8rem;
height: fit-content; height: fit-content;
svg { svg {
color: var(--text-color); color: var(--text-color);
margin: 0; margin: 0;
} }
} }
} }
} }
.livestream_player_header_info { .livestream_player_header_info {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
width: 100%; min-width: 350px;
width: 100%;
.livestream_player_header_title { .livestream_player_header_title {
font-family: "Space Grotesk", sans-serif; font-family: "Space Grotesk", sans-serif;
font-size: 1rem; font-size: 0.9rem;
font-weight: 700; font-weight: 700;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
} }
.livestream_player_header_description { .livestream_player_header_description {
font-size: 0.8rem; font-size: 0.8rem;
font-weight: 300; font-weight: 300;
font-style: italic; font-style: italic;
h4 { h4 {
margin-left: 10px; margin-left: 10px;
} }
} }
} }
} }
} }
.livestream_panel { .livestream_panel {
display: flex; position: relative;
flex-direction: column; z-index: 100;
position: relative; display: flex;
height: 100vh; flex-direction: column;
width: @panel-width; height: 100%;
min-width: 300px;
width: 30%;
.chatbox { background-color: var(--background-color-accent);
position: relative; border-radius: 24px;
width: 100%; overflow: hidden;
height: 100%;
overflow: hidden; .chatbox {
position: relative;
padding: 20px; width: 100%;
height: 100%;
.chatbox_header { overflow: hidden;
position: absolute;
z-index: 100;
display: flex; padding: 10px;
flex-direction: column;
justify-content: center; .chatbox_header {
position: absolute;
z-index: 100;
z-index: 100; display: flex;
flex-direction: column;
top: 0; justify-content: center;
left: 0;
width: 100%; z-index: 100;
height: @chatbox-header-height;
padding: 20px; top: 0;
left: 0;
backdrop-filter: blur(20px); width: 100%;
} height: @chatbox-header-height;
.liveChat { padding: 20px;
.liveChat_timeline {
&::after {
position: absolute;
z-index: 90;
content: ""; backdrop-filter: blur(20px);
}
top: 0px; .liveChat {
left: 0; .liveChat_timeline {
&::after {
position: absolute;
z-index: 90;
width: 100%; content: "";
height: @chatbox-header-height;
filter: blur(7px); top: 0px;
background-color: rgba(var(--layoutBackgroundColor), 0.7); left: 0;
}
padding-top: @chatbox-header-height; width: 100%;
} height: @chatbox-header-height;
}
}
}
.plyr { filter: blur(7px);
border-radius: 0 4px 4px 0; background-color: rgba(
width: 80vw; var(--layoutBackgroundColor),
height: 100vh; 0.7
} );
} }
padding-top: @chatbox-header-height;
}
.liveChat_textInput {
.ant-input-affix-wrapper {
background-color: var(--background-color-primary);
}
}
}
}
}
.plyr {
width: 100%;
height: 100%;
}
}