Added some api functions, an express server for the API and nunjucks
Added nunjucks templates for frontend pages.merge-requests/1/merge
parent
085dd02148
commit
b0533f973b
File diff suppressed because it is too large
Load Diff
|
@ -16,11 +16,14 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^3.0.6",
|
"bcrypt": "^3.0.6",
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
"config": "^3.2.2",
|
"config": "^3.2.2",
|
||||||
|
"express": "^4.17.1",
|
||||||
"flags": "^0.1.3",
|
"flags": "^0.1.3",
|
||||||
"irc": "^0.5.2",
|
"irc": "^0.5.2",
|
||||||
"mysql": "^2.17.1",
|
"mysql": "^2.17.1",
|
||||||
"node-media-server": ">=2.1.3 <3.0.0",
|
"node-media-server": ">=2.1.3 <3.0.0",
|
||||||
|
"nunjucks": "^3.2.0",
|
||||||
"toml": "^3.0.0"
|
"toml": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import * as db from "./database"
|
||||||
|
|
||||||
|
var config: any;
|
||||||
|
function init(conf: object){
|
||||||
|
config = conf;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function register(name: string, password: string, streamer: boolean) {
|
||||||
|
if(!config.registration){
|
||||||
|
return {"error":"registration disabled"};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(name.includes(';') || name.includes(' ')) return {"error":"illegal characters"};
|
||||||
|
let s: boolean;
|
||||||
|
if(streamer && config.streamKeys) s = true;
|
||||||
|
else s = false;
|
||||||
|
let r: boolean = await db.addUser(name, password, s, false);
|
||||||
|
if(r) return {"success":""};
|
||||||
|
else return {"error":""};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function login(name: string, pass: string) {
|
||||||
|
return await db.validatePassword(name, pass);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function users(num: number) {
|
||||||
|
return await db.query('select username from users limit '+num);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function user(name: string) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async function instance() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export { init, register };
|
|
@ -1,6 +1,8 @@
|
||||||
import * as mediaserver from "./server";
|
import * as mediaserver from "./server";
|
||||||
import * as ircd from "./ircd";
|
import * as ircd from "./ircd";
|
||||||
import * as db from "./database";
|
import * as db from "./database";
|
||||||
|
import * as api from "./api";
|
||||||
|
import * as http from "./http";
|
||||||
import * as config from "config";
|
import * as config from "config";
|
||||||
|
|
||||||
function run(): void{
|
function run(): void{
|
||||||
|
@ -12,7 +14,10 @@ function run(): void{
|
||||||
streamKeys: config.media.streamKeys,
|
streamKeys: config.media.streamKeys,
|
||||||
registration: config.satyr.registration,
|
registration: config.satyr.registration,
|
||||||
webFormat: config.satyr.webFormat,
|
webFormat: config.satyr.webFormat,
|
||||||
restrictedNames: config.satyr.restrictedNames
|
restrictedNames: config.satyr.restrictedNames,
|
||||||
|
name: config.satyr.name,
|
||||||
|
domain: config.satyr.domain,
|
||||||
|
email: config.satyr.email
|
||||||
};
|
};
|
||||||
const nms: object = {
|
const nms: object = {
|
||||||
logType: config.server.logs,
|
logType: config.server.logs,
|
||||||
|
@ -47,6 +52,8 @@ function run(): void{
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
api.init(satyr);
|
||||||
|
http.init(satyr);
|
||||||
db.init(dbcfg, bcryptcfg);
|
db.init(dbcfg, bcryptcfg);
|
||||||
mediaserver.init(nms, satyr);
|
mediaserver.init(nms, satyr);
|
||||||
ircd.init();
|
ircd.init();
|
||||||
|
|
|
@ -12,6 +12,7 @@ function init (db: object, bcrypt: object){
|
||||||
|
|
||||||
async function addUser(name: string, password: string, streamer: boolean, admin: boolean){
|
async function addUser(name: string, password: string, streamer: boolean, admin: boolean){
|
||||||
//does not respect registration setting in config
|
//does not respect registration setting in config
|
||||||
|
//nor stream keys
|
||||||
if(password === '') return false;
|
if(password === '') return false;
|
||||||
let key: string = ' ';
|
let key: string = ' ';
|
||||||
if (streamer) key = await genKey();
|
if (streamer) key = await genKey();
|
||||||
|
@ -60,7 +61,8 @@ async function query(query: string){
|
||||||
}
|
}
|
||||||
|
|
||||||
async function validatePassword(username: string, password: string){
|
async function validatePassword(username: string, password: string){
|
||||||
;
|
let pass: any= await query('select password from users where username=\''+username+'\' limit 1');
|
||||||
|
return await bcrypt.compare(password, pass[0].password_hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
export { query, raw, init, addUser, rmUser, addStreamKey, rmStreamKey };
|
export { query, raw, init, addUser, rmUser, addStreamKey, rmStreamKey, validatePassword };
|
|
@ -0,0 +1,47 @@
|
||||||
|
import * as express from "express";
|
||||||
|
import * as njk from "nunjucks";
|
||||||
|
import * as bodyparser from "body-parser";
|
||||||
|
import * as api from "./api";
|
||||||
|
import * as db from "./database";
|
||||||
|
|
||||||
|
var app = express();
|
||||||
|
var njkconf;
|
||||||
|
|
||||||
|
function init(satyr: any){
|
||||||
|
app.listen(8000);
|
||||||
|
njk.configure('templates', {
|
||||||
|
autoescape: true,
|
||||||
|
express : app,
|
||||||
|
watch: true
|
||||||
|
});
|
||||||
|
njkconf ={
|
||||||
|
sitename: satyr.name,
|
||||||
|
domain: satyr.domain,
|
||||||
|
email: satyr.email,
|
||||||
|
user: '',
|
||||||
|
streamtitle: '',
|
||||||
|
};
|
||||||
|
app.use(bodyparser.json());
|
||||||
|
app.use(bodyparser.urlencoded({ extended: true }));
|
||||||
|
app.get('/', (req, res) => {
|
||||||
|
res.render('index.njk', njkconf);
|
||||||
|
});
|
||||||
|
app.get('/about', (req, res) => {
|
||||||
|
res.render('about.njk', njkconf);
|
||||||
|
});
|
||||||
|
app.get('/users/*', (req, res) => {
|
||||||
|
njkconf.user = req.url.split('/')[2].toLowerCase();
|
||||||
|
res.render('user.njk', njkconf);
|
||||||
|
});
|
||||||
|
app.get('/registration', (req, res) => {
|
||||||
|
res.render('registration.njk', njkconf);
|
||||||
|
});
|
||||||
|
app.post('/api/register', (req, res) => {
|
||||||
|
api.register(req.body.username, req.body.password, req.body.streamer).then( (result) => {
|
||||||
|
res.send({"error":""});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
app.use(express.static('site'));
|
||||||
|
}
|
||||||
|
|
||||||
|
export { init };
|
|
@ -32,8 +32,8 @@ function init (mediaconfig: any, satyrconfig: any) {
|
||||||
}
|
}
|
||||||
console.log("[NodeMediaServer] Public endpoint, checking record flag.");
|
console.log("[NodeMediaServer] Public endpoint, checking record flag.");
|
||||||
//if this stream is from the public endpoint, check if we should be recording
|
//if this stream is from the public endpoint, check if we should be recording
|
||||||
return db.query('select username from users where username=\''+key+'\' and record_flag=true limit 1').then((results) => {
|
return db.query('select username,record_flag from users where username=\''+key+'\' limit 1').then((results) => {
|
||||||
if(results[0].username && satyrconfig.record){
|
if(results[0].record_flag && satyrconfig.record){
|
||||||
console.log('[NodeMediaServer] Initiating recording for stream:',id);
|
console.log('[NodeMediaServer] Initiating recording for stream:',id);
|
||||||
mkdir(mediaconfig.http.mediaroot+'/'+mediaconfig.trans.tasks[0].app+'/'+results[0].username, { recursive : true }, (err) => {
|
mkdir(mediaconfig.http.mediaroot+'/'+mediaconfig.trans.tasks[0].app+'/'+results[0].username, { recursive : true }, (err) => {
|
||||||
if (err) throw err;
|
if (err) throw err;
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<p>Add a description of your instance here!</p>
|
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "base.njk" %}
|
||||||
|
{% block content %}
|
||||||
|
{% include "about.html" %}
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/styles.css">
|
||||||
|
<title>{{ sitename }}</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div id="header">
|
||||||
|
<span style="float:left;"><h4><a href="/">{{ sitename }}</a> | <a href="/users/live">Live</a> <a href="/users">Users</a> <a href="/about">About</a></h4></span><span style="float:right;"><h4>| <a href="/login">Login</a></h4></span>
|
||||||
|
</div>
|
||||||
|
<div id="content">
|
||||||
|
{% block content %}
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
<div id="footer">
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<b>Satyr</b></br>
|
||||||
|
<a href="https://gitlab.com/knotteye/satyr">About</a></br>
|
||||||
|
<a href="">v0.1.0</a>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<img src="/satyr.png" height="50" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>{{ sitename }}</b></br>
|
||||||
|
<a href="/about">About</a></br>
|
||||||
|
<a href="mailto:{{ email }}">Contact</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
|
@ -0,0 +1,4 @@
|
||||||
|
{% extends "base.njk" %}
|
||||||
|
{% block content %}
|
||||||
|
What to put on index?
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,16 @@
|
||||||
|
{% extends "base.njk" %}
|
||||||
|
{% block content %}
|
||||||
|
<div id="jscontainer" style="height: 100%;">
|
||||||
|
<div id="jschild" style="width: 50%;height: 100%;text-align: left;margin: 20px;">
|
||||||
|
<form action="/api/register" method="POST" target="_self">
|
||||||
|
Username: </br><input type="text" name="username" style="min-width: 300px" placeholder="e.g. lain"/></br>
|
||||||
|
Password: </br><input type="password" name="password" style="min-width: 300px"/></br>
|
||||||
|
Request Stream Key: <input type="checkbox" name="streamer" value="true" style="min-heigh: 50px;"> </br>
|
||||||
|
<input type="submit" value="Submit">
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div id="jschild" style="width: 50%;height: 100%;text-align: left;margin: 20px;">
|
||||||
|
{% include "tos.html" %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -0,0 +1,2 @@
|
||||||
|
This is example terms of service!</br>
|
||||||
|
You should change it by editing templates/tos.html
|
|
@ -0,0 +1,31 @@
|
||||||
|
{% extends "base.njk" %}
|
||||||
|
{% block content %}
|
||||||
|
<span style="float: left;font-size: large;"><b>{{ user | capitalize }}'s Stream</b></span><span style="float: right;font-size: large;">Direct Links: <a href="rtmp://{{ domain }}/live/{{ user }}">RTMP</a> <a href="/live/{{ user }}/index.m3u8">HLS</a></span>
|
||||||
|
<div id="jscontainer">
|
||||||
|
<div id="jschild" style="width: 70%;height: 100%;">
|
||||||
|
<video controls poster="/thumbnail.jpg" class="video-js vjs-default-skin" id="live-video" style="width:100%;height:100%;"></video>
|
||||||
|
</div>
|
||||||
|
<div id="jschild" style="width: 30%;height: 100%;">
|
||||||
|
<img src="/chat.jpg" style="width: 100%;height: 100%" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script>window.HELP_IMPROVE_VIDEOJS = false;</script>
|
||||||
|
<script src="/videojs/video.min.js"></script>
|
||||||
|
<link rel="stylesheet" type="text/css" href="/videojs/video-js.min.css">
|
||||||
|
<script>
|
||||||
|
var player = videojs('live-video', {
|
||||||
|
html: {
|
||||||
|
nativeCaptions: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
player.ready(function() {
|
||||||
|
player.on("error", () => {
|
||||||
|
document.querySelector(".vjs-modal-dialog-content").textContent = "The stream is currently offline.";
|
||||||
|
});
|
||||||
|
player.src({
|
||||||
|
src: '/live/{{ user }}/index.m3u8',
|
||||||
|
type: 'application/x-mpegURL'
|
||||||
|
});
|
||||||
|
})
|
||||||
|
</script></br>
|
||||||
|
{% endblock %}
|
Reference in New Issue