develop -> master #24
|
@ -38,17 +38,16 @@ transcode:
|
||||||
# satyr will generate one source quality variant, and the remaining
|
# satyr will generate one source quality variant, and the remaining
|
||||||
# variants will be of incrementally lower quality and bitrate
|
# variants will be of incrementally lower quality and bitrate
|
||||||
|
|
||||||
|
# having more than 4-5 variants will start giving diminishing returns on stream quality for cpu load
|
||||||
|
# if you can't afford to generate at least 3 variants, it's recommended to leave adaptive streaming off
|
||||||
|
|
||||||
inputflags: ""
|
inputflags: ""
|
||||||
# additional flags to apply to the input during transcoding
|
# additional flags to apply to the input during transcoding
|
||||||
outputflags: ""
|
outputflags: ""
|
||||||
# additional flags to apply to the output during transcoding
|
# additional flags to apply to the output during transcoding
|
||||||
|
|
||||||
# hardware acceleration is a bit difficult to configure programmatically
|
hwaccel:
|
||||||
# this is a good place to do so for your system
|
# See HWACCEL.md for information on configuring hardware acceleration.
|
||||||
# https://trac.ffmpeg.org/wiki/HWAccelIntro is a good place to start
|
|
||||||
|
|
||||||
# having more than 4-5 variants will start giving diminishing returns on stream quality for cpu load
|
|
||||||
# if you can't afford to generate at least 3 variants, it's recommended to leave adaptive streaming off
|
|
||||||
|
|
||||||
crypto:
|
crypto:
|
||||||
saltRounds: 12
|
saltRounds: 12
|
||||||
|
|
|
@ -0,0 +1,53 @@
|
||||||
|
## Configuration Hardware Acceleration
|
||||||
|
Satyr supports the NVENC and VA-API hardware acceleration APIs. If you've configured your system correctly (the hard part) it should be enough to set the type and use the default device setting if you only have one hardware acceleration device.
|
||||||
|
|
||||||
|
### System
|
||||||
|
Configuring the system for any hardware acceleration API involves three main steps: selecting the right drivers, installing the API libraries, and configuring ffmpeg.
|
||||||
|
|
||||||
|
#### NVENC
|
||||||
|
NVENC in ffmpeg can work with either open-source drivers (nouvea) or nvidia's proprietary drivers. The documentation for your distribution should have instructions for installing these.
|
||||||
|
|
||||||
|
The only system library you should need is the CUDA toolkit, general named cudatoolkit, nvidia-cuda-toolkit, or some variation in your system repositories.
|
||||||
|
You can also try installing manually from [here](https://developer.nvidia.com/cuda-downloads).
|
||||||
|
|
||||||
|
Most binary distributions provide a version of ffmpeg with NVENC already enabled. If not you can try compiling ffmpeg from source with the `--enable-nvenc` flag. If you use a source based distribution you should be familiar with enabling optional compile flags.
|
||||||
|
|
||||||
|
You can verify that ffmpeg has been set up correctly by checking the output of `ffmpeg -hide_banner -hwaccels | grep cuvid` and `ffmpeg -hide_banner -encoders | grep nvenc`. If you don't see anything, something is wrong.
|
||||||
|
|
||||||
|
#### VA-API
|
||||||
|
VA-API is an extremely generic API. Although the package names might be different in your distribution, the arch wiki page for hardware acceleration has good information on [driver selection](https://wiki.archlinux.org/index.php/Hardware_video_acceleration#Installation) and [verifying](https://wiki.archlinux.org/index.php/Hardware_video_acceleration#Verifying_VA-API) a VA-API install for a wide range of devices.
|
||||||
|
|
||||||
|
Regardless of driver selection, you will also need libva or the equivalent from your distrubtion, and libva-utils can be helpful as well.
|
||||||
|
|
||||||
|
Most binary distributions provide a version of ffmpeg with VA-API already enabled. If not you can try compiling ffmpeg from source with the `--enable-vaapi` flag. If you use a source based distribution you should be familiar with enabling optional compile flags.
|
||||||
|
|
||||||
|
You can verify that ffmpeg has been set up correctly by checking the output of `ffmpeg -hide_banner -hwaccels | grep vaapi` and `ffmpeg -hide_banner -encoders | grep vaapi`. If you don't see anything, something is wrong.
|
||||||
|
|
||||||
|
### Satyr
|
||||||
|
```
|
||||||
|
# Decoding
|
||||||
|
hwaccel:
|
||||||
|
# Enable hardware acceleration for decoding as well as encoding.
|
||||||
|
# Probably not worth it, hardware decoding won't be any faster compared to software on a vaguely modern CPU
|
||||||
|
# Hardware decoding also may not support the input format, in which case transcoding will fail
|
||||||
|
decode: true
|
||||||
|
|
||||||
|
# Only supported for VA-API
|
||||||
|
# Fall back to software decoding if hardware decoding fails
|
||||||
|
hwaccel:
|
||||||
|
decode: 'fallback'
|
||||||
|
|
||||||
|
|
||||||
|
# NVENC
|
||||||
|
hwaccel:
|
||||||
|
type: 'nvenc'
|
||||||
|
# device is optional for nvenc
|
||||||
|
device: 0
|
||||||
|
# nvenc wants a device number instead of a path, set to null to use the default
|
||||||
|
|
||||||
|
# VA-API
|
||||||
|
hwaccel:
|
||||||
|
type: 'vaapi'
|
||||||
|
# device is mandatory for va-api
|
||||||
|
device: '/dev/dri/renderD128'
|
||||||
|
```
|
|
@ -28,10 +28,15 @@ database:
|
||||||
transcode:
|
transcode:
|
||||||
#may result in higher latency if your cpu can't keep up
|
#may result in higher latency if your cpu can't keep up
|
||||||
adaptive: false
|
adaptive: false
|
||||||
|
#more than 3 might cause problems when using hwacceleration
|
||||||
variants: 3
|
variants: 3
|
||||||
#unused right now, will always transcode to dash
|
#unused right now, will always transcode to dash
|
||||||
format: dash
|
format: dash
|
||||||
|
|
||||||
|
hwaccel:
|
||||||
|
# see docs/HWACCEL.md for instructions on configuring hardware acceleration
|
||||||
|
type: null
|
||||||
|
|
||||||
chat:
|
chat:
|
||||||
|
|
||||||
irc:
|
irc:
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "satyr",
|
"name": "satyr",
|
||||||
"version": "0.10.1",
|
"version": "0.10.2",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1110,9 +1110,9 @@
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
},
|
},
|
||||||
"ini": {
|
"ini": {
|
||||||
"version": "1.3.5",
|
"version": "1.3.8",
|
||||||
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
|
||||||
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew=="
|
||||||
},
|
},
|
||||||
"ipaddr.js": {
|
"ipaddr.js": {
|
||||||
"version": "1.9.0",
|
"version": "1.9.0",
|
||||||
|
|
|
@ -10,11 +10,12 @@
|
||||||
"setup": "sh install/setup.sh",
|
"setup": "sh install/setup.sh",
|
||||||
"migrate": "ts-node src/migrate.ts",
|
"migrate": "ts-node src/migrate.ts",
|
||||||
"invite": "ts-node src/cli.ts --invite",
|
"invite": "ts-node src/cli.ts --invite",
|
||||||
|
"v3-manual": "ts-node src/v3manual.ts",
|
||||||
"make-templates": "nunjucks-precompile -i [\"\\.html$\",\"\\.njk$\"] templates > site/templates.js"
|
"make-templates": "nunjucks-precompile -i [\"\\.html$\",\"\\.njk$\"] templates > site/templates.js"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://gitlab.com/knotteye/satyr.git"
|
"url": "https://git.waldn.net/git/knotteye/satyr.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bcrypt": "^5.0.0",
|
"bcrypt": "^5.0.0",
|
||||||
|
|
|
@ -102,12 +102,15 @@ async function render(path, s){
|
||||||
//root
|
//root
|
||||||
case "/":
|
case "/":
|
||||||
render('/users/live');
|
render('/users/live');
|
||||||
|
modifyLinks();
|
||||||
break;
|
break;
|
||||||
case "":
|
case "":
|
||||||
render('/users/live');
|
render('/users/live');
|
||||||
|
modifyLinks();
|
||||||
break;
|
break;
|
||||||
case "/index.html":
|
case "/index.html":
|
||||||
render('/users/live');
|
render('/users/live');
|
||||||
|
modifyLinks();
|
||||||
break;
|
break;
|
||||||
//404
|
//404
|
||||||
default:
|
default:
|
||||||
|
@ -215,7 +218,8 @@ async function initPlayer(usr) {
|
||||||
onError(e);
|
onError(e);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
setTimeout(initPlayer, 5000, usr);
|
if(document.getElementById('video') !== null)
|
||||||
|
setTimeout(initPlayer, 5000, usr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,11 @@ const config: Object = {
|
||||||
connectionTimeout: '1000',
|
connectionTimeout: '1000',
|
||||||
insecureAuth: false,
|
insecureAuth: false,
|
||||||
debug: false }, localconfig['database']),
|
debug: false }, localconfig['database']),
|
||||||
|
hwaccel: Object.assign({
|
||||||
|
type: null,
|
||||||
|
device: null,
|
||||||
|
decode: false
|
||||||
|
}, localconfig['hwaccel']),
|
||||||
rtmp: Object.assign({
|
rtmp: Object.assign({
|
||||||
cluster: false,
|
cluster: false,
|
||||||
port: 1935,
|
port: 1935,
|
||||||
|
|
|
@ -27,7 +27,7 @@ async function addUser(name: string, password: string){
|
||||||
let dupe = await query('select * from users where username='+raw.escape(name));
|
let dupe = await query('select * from users where username='+raw.escape(name));
|
||||||
if(dupe[0]) return false;
|
if(dupe[0]) return false;
|
||||||
await query('INSERT INTO users (username, password_hash, stream_key, record_flag) VALUES ('+raw.escape(name)+', '+raw.escape(hash)+', '+raw.escape(key)+', 0)');
|
await query('INSERT INTO users (username, password_hash, stream_key, record_flag) VALUES ('+raw.escape(name)+', '+raw.escape(hash)+', '+raw.escape(key)+', 0)');
|
||||||
await query('INSERT INTO user_meta (username, title, about, live) VALUES ('+raw.escape(name)+',\'\',\'\',false)');
|
await query('INSERT INTO user_meta (username, title, about, live) VALUES ('+raw.escape(name)+',\' \',\' \',false)');
|
||||||
await query('INSERT INTO chat_integration (username, irc, xmpp, twitch, discord) VALUES ('+raw.escape(name)+',\'\',\'\',\'\',\'\')');
|
await query('INSERT INTO chat_integration (username, irc, xmpp, twitch, discord) VALUES ('+raw.escape(name)+',\'\',\'\',\'\',\'\')');
|
||||||
await query('INSERT INTO twitch_mirror (username) VALUES ('+raw.escape(name)+')');
|
await query('INSERT INTO twitch_mirror (username) VALUES ('+raw.escape(name)+')');
|
||||||
return true;
|
return true;
|
||||||
|
@ -40,6 +40,7 @@ async function rmUser(name: string){
|
||||||
await query('delete from user_meta where username='+raw.escape(name)+' limit 1');
|
await query('delete from user_meta where username='+raw.escape(name)+' limit 1');
|
||||||
await query('delete from chat_integration where username='+raw.escape(name)+' limit 1');
|
await query('delete from chat_integration where username='+raw.escape(name)+' limit 1');
|
||||||
await query('delete from twitch_mirror where username='+raw.escape(name)+' limit 1');
|
await query('delete from twitch_mirror where username='+raw.escape(name)+' limit 1');
|
||||||
|
await query('delete from ch_bans where channel='+raw.escape(name));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,21 @@
|
||||||
|
import * as db from "../database";
|
||||||
|
import * as dirty from "dirty";
|
||||||
|
|
||||||
|
async function run () {
|
||||||
|
await db.query('CREATE TABLE IF NOT EXISTS ch_bans(channel VARCHAR(25), target VARCHAR(45), time BIGINT, length INT DEFAULT 30)');
|
||||||
|
console.log('!!! This migration has a race condition when run from the `npm run migrate` command. If thats how this was called, please re-run this migration manually.\n!!! Run `npm run v3-manual` to do so');
|
||||||
|
var bansdb = new dirty('./config/bans.db')
|
||||||
|
bansdb.on('load', async () => {
|
||||||
|
bansdb.forEach(async (key, val) => {
|
||||||
|
let ips = Object.keys(val);
|
||||||
|
for(var i=0;i<ips.length;i++){
|
||||||
|
await db.query('INSERT INTO ch_bans (channel, target, time, length) VALUES ('+db.raw.escape(key)+', '+db.raw.escape(ips[i])+', '+val[ips[i]].time+', '+val[ips[i]].length+')');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
await db.query('INSERT INTO db_meta (version) VALUES (3)');
|
||||||
|
console.log('Done migrating bans.db');
|
||||||
|
console.log('If this was a manual migration, you can kill the process now.');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export { run }
|
43
src/http.ts
43
src/http.ts
|
@ -17,7 +17,6 @@ const app = express();
|
||||||
const server = http.createServer(app);
|
const server = http.createServer(app);
|
||||||
const io = socketio(server);
|
const io = socketio(server);
|
||||||
const store = dirty();
|
const store = dirty();
|
||||||
var banlist;
|
|
||||||
var jwkey;
|
var jwkey;
|
||||||
try{
|
try{
|
||||||
jwkey = JWK.asKey(readFileSync('./config/jwt.pem'));
|
jwkey = JWK.asKey(readFileSync('./config/jwt.pem'));
|
||||||
|
@ -77,7 +76,7 @@ async function init(){
|
||||||
else res.status(404).render('404.njk', njkconf);
|
else res.status(404).render('404.njk', njkconf);
|
||||||
//res.status(404).render('404.njk', njkconf);
|
//res.status(404).render('404.njk', njkconf);
|
||||||
});
|
});
|
||||||
banlist = new dirty('./config/bans.db').on('load', () => {initChat()});
|
await initChat();
|
||||||
server.listen(config['http']['port']);
|
server.listen(config['http']['port']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,6 +253,7 @@ async function initAPI() {
|
||||||
api.register(req.body.username, req.body.password, req.body.confirm, true).then((result) => {
|
api.register(req.body.username, req.body.password, req.body.confirm, true).then((result) => {
|
||||||
if(result[0]) return genToken(req.body.username).then((t) => {
|
if(result[0]) return genToken(req.body.username).then((t) => {
|
||||||
res.cookie('Authorization', t, {maxAge: 604800000, httpOnly: true, sameSite: 'Lax'});
|
res.cookie('Authorization', t, {maxAge: 604800000, httpOnly: true, sameSite: 'Lax'});
|
||||||
|
res.cookie('X-Auth-As', req.body.username, {maxAge: 604800000, httpOnly: false, sameSite: 'Lax'})
|
||||||
res.json(result);
|
res.json(result);
|
||||||
api.useInvite(req.body.invite);
|
api.useInvite(req.body.invite);
|
||||||
return;
|
return;
|
||||||
|
@ -268,6 +268,7 @@ async function initAPI() {
|
||||||
api.register(req.body.username, req.body.password, req.body.confirm).then( (result) => {
|
api.register(req.body.username, req.body.password, req.body.confirm).then( (result) => {
|
||||||
if(result[0]) return genToken(req.body.username).then((t) => {
|
if(result[0]) return genToken(req.body.username).then((t) => {
|
||||||
res.cookie('Authorization', t, {maxAge: 604800000, httpOnly: true, sameSite: 'Lax'});
|
res.cookie('Authorization', t, {maxAge: 604800000, httpOnly: true, sameSite: 'Lax'});
|
||||||
|
res.cookie('X-Auth-As', req.body.username, {maxAge: 604800000, httpOnly: false, sameSite: 'Lax'})
|
||||||
res.json(result);
|
res.json(result);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
|
@ -589,9 +590,10 @@ async function initChat() {
|
||||||
socket.on('JOINROOM', async (data) => {
|
socket.on('JOINROOM', async (data) => {
|
||||||
let t: any = await db.query('select username from users where username='+db.raw.escape(data));
|
let t: any = await db.query('select username from users where username='+db.raw.escape(data));
|
||||||
if(t[0]){
|
if(t[0]){
|
||||||
if(banlist.get(data) && banlist.get(data)[socket['handshake']['address']]){
|
let b = await db.query('select * from ch_bans where target='+db.raw.escape(socket['handshake']['address'])+' and channel='+db.raw.escape(data));
|
||||||
if(Math.floor(banlist.get(data)[socket['handshake']['address']]['time'] + (banlist.get(data)[socket['handshake']['address']]['length'] * 60)) < Math.floor(Date.now() / 1000)){
|
if(b[0]){
|
||||||
banlist.set(data, Object.assign({}, banlist.get(data), {[socket['handshake']['address']]: null}));
|
if(Math.floor(b[0].time + (b[0].length * 60)) < Math.floor(Date.now() / 1000)){
|
||||||
|
await db.query('delete from ch_bans where target='+db.raw.escape(b[0].target)+'and channel='+db.raw.escape(b[0].channel)+' and time='+db.raw.escape(b[0].time)+' and length='+db.raw.escape(b[0].length));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
socket.emit('ALERT', 'You are banned from that room');
|
socket.emit('ALERT', 'You are banned from that room');
|
||||||
|
@ -680,23 +682,27 @@ async function initChat() {
|
||||||
}
|
}
|
||||||
else socket.emit('ALERT', 'Not authorized to do that.');
|
else socket.emit('ALERT', 'Not authorized to do that.');
|
||||||
});
|
});
|
||||||
socket.on('BAN', (data: Object) => {
|
socket.on('BAN', async (data: Object) => {
|
||||||
if(socket.nick === data['room']){
|
if(socket.nick === data['room']){
|
||||||
let id: string = store.get(data['nick']);
|
let id: string = store.get(data['nick']);
|
||||||
if(id){
|
if(id){
|
||||||
if(Array.isArray(id)) {
|
if(Array.isArray(id)) {
|
||||||
for(let i=0;i<id.length;i++){
|
for(let i=0;i<id.length;i++){
|
||||||
let target = io.sockets.connected[id[i]];
|
let target = io.sockets.connected[id[i]];
|
||||||
if(typeof(data['time']) === 'number' && (data['time'] !== 0 && data['time'] !== NaN)) banlist.set(data['room'], Object.assign({}, banlist.get(data['room']), {[target.ip]: {time: Math.floor(Date.now() / 1000), length: data['time']}}));
|
if(typeof(data['time']) === 'number' && (data['time'] !== 0 && data['time'] !== NaN))
|
||||||
else banlist.set(data['room'], Object.assign({}, banlist.get(data['room']), {[target.ip]: {time: Math.floor(Date.now() / 1000), length: 30}}));
|
await db.query('insert into ch_bans (channel, target, time, length) VALUES ('+db.raw.escape(data['room'])+', '+db.raw.escape(target.ip)+', '+db.raw.escape(Math.floor(Date.now() / 1000))+', '+db.raw.escape(data['time'])+')');
|
||||||
|
else
|
||||||
|
await db.query('insert into ch_bans (channel, target, time, length) VALUES ('+db.raw.escape(data['room'])+', '+db.raw.escape(target.ip)+', '+db.raw.escape(Math.floor(Date.now() / 1000))+', '+db.raw.escape(30)+')');
|
||||||
target.leave(data['room']);
|
target.leave(data['room']);
|
||||||
}
|
}
|
||||||
io.to(data['room']).emit('ALERT', data['nick']+' was banned.');
|
io.to(data['room']).emit('ALERT', data['nick']+' was banned.');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let target = io.sockets.connected[id];
|
let target = io.sockets.connected[id];
|
||||||
if(typeof(data['time']) === 'number' && (data['time'] !== 0 && data['time'] !== NaN)) banlist.set(data['room'], Object.assign({}, banlist.get(data['room']), {[target.ip]: {time: Math.floor(Date.now() / 1000), length: data['time']}}));
|
if(typeof(data['time']) === 'number' && (data['time'] !== 0 && data['time'] !== NaN))
|
||||||
else banlist.set(data['room'], Object.assign({}, banlist.get(data['room']), {[target.ip]: {time: Math.floor(Date.now() / 1000), length: 30}}));
|
await db.query('insert into ch_bans (channel, target, time, length) VALUES ('+db.raw.escape(data['room'])+', '+db.raw.escape(target.ip)+', '+db.raw.escape(Math.floor(Date.now() / 1000))+', '+db.raw.escape(data['time'])+')');
|
||||||
|
else
|
||||||
|
await db.query('insert into ch_bans (channel, target, time, length) VALUES ('+db.raw.escape(data['room'])+', '+db.raw.escape(target.ip)+', '+db.raw.escape(Math.floor(Date.now() / 1000))+', '+db.raw.escape(30)+')');
|
||||||
target.leave(data['room']);
|
target.leave(data['room']);
|
||||||
io.to(data['room']).emit('ALERT', target.nick+' was banned.');
|
io.to(data['room']).emit('ALERT', target.nick+' was banned.');
|
||||||
}
|
}
|
||||||
|
@ -704,10 +710,11 @@ async function initChat() {
|
||||||
}
|
}
|
||||||
else socket.emit('ALERT', 'Not authorized to do that.');
|
else socket.emit('ALERT', 'Not authorized to do that.');
|
||||||
});
|
});
|
||||||
socket.on('UNBAN', (data: Object) => {
|
socket.on('UNBAN', async (data: Object) => {
|
||||||
if(socket.nick === data['room']){
|
if(socket.nick === data['room']){
|
||||||
if(banlist.get(data['room']) && banlist.get(data['room'])[data['ip']]){
|
let b = await db.query('select * from ch_bans where channel='+db.raw.escape(data['room'])+' and target='+db.raw.escape(data['ip']));
|
||||||
banlist.set(data['room'], Object.assign({}, banlist.get(data['room']), {[data['ip']]: null}));
|
if(b[0]){
|
||||||
|
await db.query('delete from ch_bans where channel='+db.raw.escape(data['room'])+' and target='+db.raw.escape(data['ip']));
|
||||||
socket.emit('ALERT', data['ip']+' was unbanned.');
|
socket.emit('ALERT', data['ip']+' was unbanned.');
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -715,13 +722,13 @@ async function initChat() {
|
||||||
}
|
}
|
||||||
else socket.emit('ALERT', 'Not authorized to do that.');
|
else socket.emit('ALERT', 'Not authorized to do that.');
|
||||||
});
|
});
|
||||||
socket.on('LISTBAN', (data: Object) => {
|
socket.on('LISTBAN', async (data: Object) => {
|
||||||
if(socket.nick === data['room']){
|
if(socket.nick === data['room']){
|
||||||
if(banlist.get(data['room'])) {
|
let b = await db.query('select target from ch_bans where channel='+db.raw.escape(data['room']));
|
||||||
let bans = Object.keys(banlist.get(data['room']));
|
if(b[0]) {
|
||||||
let str = '';
|
let str = '';
|
||||||
for(let i=0;i<bans.length;i++){
|
for(let i=0;i<b.length;i++){
|
||||||
str += bans[i]+', ';
|
str += b[i].target+', ';
|
||||||
}
|
}
|
||||||
socket.emit('ALERT', 'Banned IP adresses: '+str.substring(0, str.length - 2));
|
socket.emit('ALERT', 'Banned IP adresses: '+str.substring(0, str.length - 2));
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -42,9 +42,10 @@ function init () {
|
||||||
if(session.audioCodec !== 0 && session.videoCodec !== 0){
|
if(session.audioCodec !== 0 && session.videoCodec !== 0){
|
||||||
transCommand(results[0].username, key).then((r) => {
|
transCommand(results[0].username, key).then((r) => {
|
||||||
execFile(config['media']['ffmpeg'], r, {maxBuffer: Infinity}, (err, stdout, stderr) => {
|
execFile(config['media']['ffmpeg'], r, {maxBuffer: Infinity}, (err, stdout, stderr) => {
|
||||||
/*console.log(err);
|
//console.log(r);
|
||||||
console.log(stdout);
|
//console.log(err);
|
||||||
console.log(stderr);*/
|
//console.log(stdout);
|
||||||
|
//console.log(stderr);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
@ -126,29 +127,51 @@ function init () {
|
||||||
|
|
||||||
async function transCommand(user: string, key: string): Promise<string[]>{
|
async function transCommand(user: string, key: string): Promise<string[]>{
|
||||||
let args: string[] = ['-loglevel', 'fatal', '-y'];
|
let args: string[] = ['-loglevel', 'fatal', '-y'];
|
||||||
|
let vcodec: string = 'libx264';
|
||||||
|
if(config['hwaccel']['type'] === 'nvenc'){
|
||||||
|
vcodec = 'h264_nvenc';
|
||||||
|
if(config['hwaccel']['decode']){
|
||||||
|
args = args.concat(['-hwaccel', 'cuda']);
|
||||||
|
if(config['hwaccel']['device'])
|
||||||
|
args = args.concat(['-hwaccel_device', config['hwaccel']['device']]);
|
||||||
|
args = args.concat(['-hwaccel_output_format', 'cuda']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (config['hwaccel']['type'] === 'vaapi') {
|
||||||
|
vcodec = 'h264_vaapi';
|
||||||
|
if(config['hwaccel']['decode'] === 'fallback'){
|
||||||
|
args = args.concat('init_hw_device', 'vaapi=foo:'+config['hwaccel']['device'], '-hwaccel vaapi', '-hwaccel_output_format', 'vaapi', '-hwaccel_device', 'foo');
|
||||||
|
} else if (config['hwaccel']['decode']) {
|
||||||
|
args = args.concat(['-hwaccel', 'vaapi', '-hwaccel_output_format', 'vaapi', '-vaapi_device', config['hwaccel']['device']]);
|
||||||
|
}
|
||||||
|
}
|
||||||
if(config['transcode']['inputflags'] !== null && config['transcode']['inputflags'] !== "") args = args.concat(config['transcode']['inputflags'].split(" "));
|
if(config['transcode']['inputflags'] !== null && config['transcode']['inputflags'] !== "") args = args.concat(config['transcode']['inputflags'].split(" "));
|
||||||
args = args.concat(['-i', 'rtmp://127.0.0.1:'+config['rtmp']['port']+'/'+config['media']['privateEndpoint']+'/'+key, '-movflags', '+faststart']);
|
args = args.concat(['-i', 'rtmp://127.0.0.1:'+config['rtmp']['port']+'/'+config['media']['privateEndpoint']+'/'+key, '-movflags', '+faststart']);
|
||||||
if(config['transcode']['adaptive']===true && config['transcode']['variants'] > 1) {
|
if(config['transcode']['adaptive']===true && config['transcode']['variants'] > 1) {
|
||||||
for(let i=0;i<config['transcode']['variants'];i++){
|
for(let i=0;i<config['transcode']['variants'];i++){
|
||||||
args = args.concat(['-map', '0:2']);
|
args = args.concat(['-map', '0:v']);
|
||||||
}
|
}
|
||||||
args = args.concat(['-map', '0:1', '-c:a', 'aac', '-c:v:0', 'libx264']);
|
args = args.concat(['-map', '0:a', '-c:a', 'aac', '-c:v:0', vcodec]);
|
||||||
for(let i=1;i<config['transcode']['variants'];i++){
|
for(let i=1;i<config['transcode']['variants'];i++){
|
||||||
args = args.concat(['-c:v:'+i, 'libx264',]);
|
args = args.concat(['-c:v:'+i, vcodec,]);
|
||||||
|
}
|
||||||
|
if(!config['hwaccel']['type']){
|
||||||
|
for(let i=1;i<config['transcode']['variants'];i++){
|
||||||
|
let crf: number = Math.floor(18 + (i * 8)) > 51 ? 51 : Math.floor(18 + (i * 7));
|
||||||
|
args = args.concat(['-crf:'+i, ''+crf]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for(let i=1;i<config['transcode']['variants'];i++){
|
for(let i=1;i<config['transcode']['variants'];i++){
|
||||||
let crf: number = Math.floor(18 + (i * 8)) > 51 ? 51 : Math.floor(18 + (i * 7));
|
let bv: number = Math.floor((10000 / config['transcode']['variants']) * (config['transcode']['variants'] - i));
|
||||||
args = args.concat(['-crf:'+i, ''+crf]);
|
|
||||||
}
|
|
||||||
for(let i=1;i<config['transcode']['variants'];i++){
|
|
||||||
let bv: number = Math.floor((5000 / config['transcode']['variants']) * (config['transcode']['variants'] - i));
|
|
||||||
args = args.concat(['-b:v:'+i, ''+bv]);
|
args = args.concat(['-b:v:'+i, ''+bv]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
args = args.concat(['-c:a', 'aac', '-c:v', 'libx264']);
|
args = args.concat(['-c:a', 'aac', '-c:v', vcodec]);
|
||||||
}
|
}
|
||||||
args = args.concat(['-preset', 'veryfast', '-tune', 'zerolatency']);
|
if(!config['hwaccel']['type'])
|
||||||
|
args = args.concat(['-preset', 'veryfast']);
|
||||||
|
args = args.concat(['-tune', 'zerolatency']);
|
||||||
//if(config['transcode']['format'] === 'dash')
|
//if(config['transcode']['format'] === 'dash')
|
||||||
args = args.concat(['-remove_at_exit', '1', '-seg_duration', '1', '-window_size', '30']);
|
args = args.concat(['-remove_at_exit', '1', '-seg_duration', '1', '-window_size', '30']);
|
||||||
if(config['transcode']['outputflags'] !== null && config['transcode']['outputflags'] !== "") args = args.concat(config['transcode']['outputflags'].split(" "));
|
if(config['transcode']['outputflags'] !== null && config['transcode']['outputflags'] !== "") args = args.concat(config['transcode']['outputflags'].split(" "));
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
import * as db from "./database";
|
||||||
|
async function main() {
|
||||||
|
await db.init();
|
||||||
|
await require('./db/3.ts').run();
|
||||||
|
}
|
||||||
|
main();
|
Reference in New Issue