no longer store stream key in DOM on dashboard

This commit is contained in:
Evert Prants 2021-02-14 09:54:09 +02:00
parent 1ab2c3df17
commit b0ed4f0e7a
Signed by: evert
GPG Key ID: 1688DA83D222D0B5
10 changed files with 93 additions and 71 deletions

12
app.js
View File

@ -75,7 +75,7 @@ config = Object.assign({
}, config) }, config)
// Constants // Constants
const port = parseInt(config.Streaming.port) const port = parseInt(config.Streaming.port, 10)
const streamServer = config.Streaming.streamServer const streamServer = config.Streaming.streamServer
const streamServerHost = config.Streaming.serverHost const streamServerHost = config.Streaming.serverHost
const streamAppName = streamServer.match(/\/([\w-_]+)\/$/)[1] const streamAppName = streamServer.match(/\/([\w-_]+)\/$/)[1]
@ -426,7 +426,7 @@ app.get('/', (req, res) => {
// Dashboard // Dashboard
app.get('/dashboard', authed, (req, res) => { app.get('/dashboard', authed, (req, res) => {
const stream = cache.streamers[req.user.uuid] const stream = cache.streamers[req.user.uuid]
res.render('dashboard.html', { stream: stream.key, server: 'rtmp://' + streamServerHost + '/live/' }) res.render('dashboard.html', { server: 'rtmp://' + streamServerHost + '/live/' })
}) })
// Stats // Stats
@ -464,8 +464,8 @@ app.get('/dashboard/data', authed, async (req, res) => {
key: stream.key, key: stream.key,
uuid: req.user.uuid, uuid: req.user.uuid,
live: data.live_at != null, live: data.live_at != null,
live_at: new Date(parseInt(data.live_at)), live_at: new Date(parseInt(data.live_at, 10)),
last_stream: new Date(parseInt(data.last_stream)) last_stream: new Date(parseInt(data.last_stream, 10))
}) })
}) })
@ -552,8 +552,8 @@ app.get('/api/channel/:name', async (req, res) => {
delete data.user_uuid delete data.user_uuid
data.live = data.live_at != null data.live = data.live_at != null
data.live_at = new Date(parseInt(data.live_at)) data.live_at = new Date(parseInt(data.live_at, 10))
data.last_stream = new Date(parseInt(data.last_stream)) data.last_stream = new Date(parseInt(data.last_stream, 10))
data.links = links || [] data.links = links || []
data.viewers = Object.keys(cache.viewers[name] || {}).length data.viewers = Object.keys(cache.viewers[name] || {}).length
data.source = streamServer + name + '.m3u8' data.source = streamServer + name + '.m3u8'

View File

@ -6,7 +6,7 @@
"private": true, "private": true,
"scripts": { "scripts": {
"test": "echo \"Error: no test specified\" && exit 1", "test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack -w --mode=development --log-level=debug", "watch": "webpack -w --mode=development",
"build": "webpack --mode=production", "build": "webpack --mode=production",
"start": "node app.js", "start": "node app.js",
"serve": "NODE_ENV=\"development\" node app.js" "serve": "NODE_ENV=\"development\" node app.js"

View File

@ -66,6 +66,10 @@ body {
width: 40px; width: 40px;
cursor: pointer; cursor: pointer;
padding: 4px; padding: 4px;
text-align: center;
}
.controls .button:hover {
background-color: #005193;
} }
.flex-divider { .flex-divider {
flex-grow: 1; flex-grow: 1;

View File

@ -51,13 +51,18 @@ function updateLinkList (k) {
}) })
} }
function dashboard (k) { function dashboard () {
let key;
let shown = false;
$.get('/dashboard/data', function (res) { $.get('/dashboard/data', function (res) {
if (res.error) { if (res.error) {
window.location.href = '/' window.location.href = '/'
return return
} }
// Set key from request
key = res.key
const fullURL = window.location.origin + '/watch/' + res.name const fullURL = window.location.origin + '/watch/' + res.name
const sourceURL = window.location.origin + '/live/' + res.name + '.m3u8' const sourceURL = window.location.origin + '/live/' + res.name + '.m3u8'
$('#myStream').attr('src', fullURL) $('#myStream').attr('src', fullURL)
@ -66,12 +71,33 @@ function dashboard (k) {
$('#stream_live').text(res.live ? 'Yes' : 'No') $('#stream_live').text(res.live ? 'Yes' : 'No')
}) })
$('#show_key').click(function (e) { $('#keybox').val('A'.repeat(36))
e.preventDefault() $('#show_key').on('click', function (e) {
$('#show_key').html(k) if (shown) {
$('#keybox').val('A'.repeat(36))
$('#keybox').attr('type', 'password')
$(this).text('Reveal Key')
} else {
$('#keybox').val(key)
$('#keybox').attr('type', 'text')
$(this).text('Hide Key')
}
shown = !shown
}) })
$('.go-page').click(function (e) { $('#copy_key').on('click', function (e) {
const i = $('<input>').attr('value', key)
$(this).append(i)
$(this).attr('title', 'Click to copy to clipboard')
i[0].select()
i[0].setSelectionRange(0, key.length)
document.execCommand('copy')
$(i).remove()
$(this).text('Copied!')
setTimeout(() => $(this).text('Copy'), 1000)
})
$('.go-page').on('click', function (e) {
const el = $(this) const el = $(this)
$('.go-page').removeClass('active') $('.go-page').removeClass('active')
el.addClass('active') el.addClass('active')
@ -80,7 +106,7 @@ function dashboard (k) {
}) })
}) })
$('#add-link').submit(function (e) { $('#add-link').on('submit', function (e) {
e.preventDefault() e.preventDefault()
const name = $('input[name="name"]').val() const name = $('input[name="name"]').val()
const url = $('input[name="url"]').val() const url = $('input[name="url"]').val()

View File

@ -1,5 +1,6 @@
/* global STREAM_KEY */
import 'bootstrap' import 'bootstrap'
import dashboard from './dashboard.js' import dashboard from './dashboard.js'
if (window.STREAM_KEY) dashboard(window.STREAM_KEY) if (window.location.pathname.startsWith('/dashboard')) dashboard()

View File

@ -32,26 +32,6 @@ let errored = false
let live = false let live = false
let ws let ws
function GET (url, istext) {
return new Promise((resolve, reject) => {
var xmlHttp = new XMLHttpRequest()
xmlHttp.onreadystatechange = function () {
if (xmlHttp.readyState === 4 && xmlHttp.status === 200) {
resolve(xmlHttp.responseText)
} else if (xmlHttp.readyState === 4 && xmlHttp.status >= 400) {
const err = new Error(xmlHttp.status)
err.request = xmlHttp
reject(err)
}
}
xmlHttp.open('GET', url, true)
istext && (xmlHttp.responseType = 'text')
xmlHttp.send(null)
})
}
function clampAddition (val) { function clampAddition (val) {
let volume = vid.volume let volume = vid.volume
@ -391,6 +371,7 @@ function updateLinks (srcs) {
if (!links) { if (!links) {
links = document.createElement('div') links = document.createElement('div')
links.className = 'right button' links.className = 'right button'
links.setAttribute('title', 'Links')
links.id = 'links' links.id = 'links'
links.innerHTML = '<i class="fa fa-link" aria-hidden="true"></i>' links.innerHTML = '<i class="fa fa-link" aria-hidden="true"></i>'
overlay.getElementsByClassName('controls')[0].insertBefore(links, fullscreenbtn) overlay.getElementsByClassName('controls')[0].insertBefore(links, fullscreenbtn)
@ -431,8 +412,9 @@ function updateLinks (srcs) {
} }
function getStreamStatus () { function getStreamStatus () {
GET('/api/channel/' + STREAM_NAME).then((data) => { fetch('/api/channel/' + STREAM_NAME)
const jd = JSON.parse(data) .then(data => data.json())
.then((jd) => {
if (jd.error) { if (jd.error) {
errored = true errored = true
return alert(jd.error) return alert(jd.error)

View File

@ -1,9 +1,6 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<script type="text/javascript">
window.STREAM_KEY = "{{ stream }}"
</script>
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css"> <link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<link rel="stylesheet" type="text/css" href="/dist/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="/dist/css/bootstrap.min.css">
<link rel="stylesheet" type="text/css" href="/dist/css/dashboard.css"> <link rel="stylesheet" type="text/css" href="/dist/css/dashboard.css">
@ -47,6 +44,7 @@
</div> </div>
<iframe allowfullscreen src="" id="myStream" width="1542" height="651" style="display: block; width: 1542px; height: 651px;"></iframe> <iframe allowfullscreen src="" id="myStream" width="1542" height="651" style="display: block; width: 1542px; height: 651px;"></iframe>
<br>
<h1 class="h2">Information</h1> <h1 class="h2">Information</h1>
<p class="lead"> <p class="lead">
<div class="row"> <div class="row">
@ -67,15 +65,6 @@
</div> </div>
</div> </div>
<div class="row">
<div class="col-2">
<label>Stream Key</label>
</div>
<div class="col">
<a href="#" id="show_key">Show Stream Key</a>
</div>
</div>
<div class="row"> <div class="row">
<div class="col-2"> <div class="col-2">
<label>Stream URL</label> <label>Stream URL</label>
@ -93,6 +82,17 @@
<a href="" id="source_url"></a> <a href="" id="source_url"></a>
</div> </div>
</div> </div>
<div class="row">
<div class="col-2">
<label>Stream Key</label>
</div>
<div class="col">
<input type="password" id="keybox">
<button href="#" id="show_key" class="btn btn-primary">Reveal Key</button>
<button href="#" id="copy_key" class="btn btn-success">Copy</button>
</div>
</div>
</p> </p>
<h1 class="h2">Metrics</h1> <h1 class="h2">Metrics</h1>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="/dist/css/bootstrap.min.css"> <link rel="stylesheet" type="text/css" href="/dist/css/bootstrap.min.css">

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html lang="en">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>IcyTV - {{ name }}</title> <title>IcyTV - {{ name }}</title>
@ -20,19 +20,27 @@
<div class="overlay"> <div class="overlay">
<div class="badge live offline">offline</div> <div class="badge live offline">offline</div>
<div class="badge viewers" style="display: none;">0</div> <div class="badge viewers" style="display: none;">0</div>
<div class="bigplaybtn hidden"><i class="fa fa-play fa-fw"></i></div> <div class="bigplaybtn hidden" title="Play">
<i class="fa fa-play fa-fw" aria-hidden="true"></i>
</div>
<div class="controls"> <div class="controls">
<div id="playbtn" class="button"><i class="fa fa-play fa-fw"></i></div> <div id="playbtn" class="button"><i class="fa fa-play fa-fw"></i></div>
<span class="seekview" id="volume_seek"> <span class="seekview" id="volume_seek">
<div id="mutebtn" class="button"><i class="fa fa-volume-up fa-fw"></i></div> <div id="mutebtn" class="button" title="Mute">
<div class="seeker"> <i class="fa fa-volume-up fa-fw" aria-hidden="true"></i>
</div>
<div class="seeker" aria-hidden="true">
<div class="seekbar" style="width: 100%"></div> <div class="seekbar" style="width: 100%"></div>
</div> </div>
</span> </span>
<div id="duration">0:00</div> <div id="duration">0:00</div>
<div class="flex-divider"></div> <div class="flex-divider"></div>
<div id="subbtn" class="right button" title="Subscribe"><i class="fa fa-envelope-o fa-fw"></i></div> <div id="subbtn" class="right button" title="Subscribe">
<div id="fullscrbtn" class="right button" title="Fullscreen"><i class="fa fa-expand fa-fw"></i></div> <i class="fa fa-envelope-o fa-fw" aria-hidden="true"></i>
</div>
<div id="fullscrbtn" class="right button" title="Fullscreen">
<i class="fa fa-expand fa-fw" aria-hidden="true"></i>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -16,8 +16,9 @@ module.exports = {
plugins: [ plugins: [
new CopyPlugin({ new CopyPlugin({
patterns: [{ patterns: [{
from: 'src/css/*.css', from: '*',
to: 'css' to: 'css',
context: 'src/css/'
}, },
{ {
from: 'node_modules/bootstrap/dist/css/bootstrap.min.css', from: 'node_modules/bootstrap/dist/css/bootstrap.min.css',