develop->master See merge request knotteye/satyr!1merge-requests/2/merge v0.3.2
commit
15eb76a30a
@ -0,0 +1,2 @@ |
|||||||
|
knotteye <knotteye@airmail.cc> |
||||||
|
crushv <nik@telekem.net> |
@ -0,0 +1,49 @@ |
|||||||
|
# Dash.js Authors List |
||||||
|
#####Please add entries to the bottom of the list in the following format |
||||||
|
* @GitHub UserName (Required) [Name and/or Organization] (Optional) |
||||||
|
|
||||||
|
#Authors |
||||||
|
* @nweber [Digital Primates] |
||||||
|
* @jefftapper [Jeff Tapper, Digital Primates] |
||||||
|
* @KozhinM [Mikail Kozhin, Microsoft Open Technologies] |
||||||
|
* @kirkshoop [Kirk Shoop, Microsoft Open Technologies] |
||||||
|
* @wilaw [Will Law, Akamai Technologies] |
||||||
|
* @AkamaiDASH [Dan Sparacio, Akamai Technologies] |
||||||
|
* @dsilhavy [Daniel Silhavy, Fraunhofer Fokus] |
||||||
|
* @greg80303 [Greg Rutz, CableLabs] |
||||||
|
* @heff [Steve Hefferman, Brightcove] |
||||||
|
* @Tomjohnson916 [Tom Johnson, Brightcove] |
||||||
|
* @jeroenwiljering [Jeroen Wijering, JWPlayer] |
||||||
|
* @bbcrddave [David Evans, BBC R&D] |
||||||
|
* @bbert [Bertrand Berthelot, Orange] |
||||||
|
* @vigneshvg [Vignesh Venkatasubramanian, Google] |
||||||
|
* @nicosang [Nicolas Angot, Orange] |
||||||
|
* @PriyadarshiniV |
||||||
|
* @senthil-codr [Senthil] |
||||||
|
* @dweremeichik [Dylan Weremeichik] |
||||||
|
* @aleal-envivio |
||||||
|
* @mconlin |
||||||
|
* @umavinoth |
||||||
|
* @lbonn |
||||||
|
* @mdale [Michael Dale, Kaltura] |
||||||
|
* @sgrebnov [Sergey Grebnov, Microsoft Open Technologies] |
||||||
|
* @wesleytodd [Wes Todd, Vubeology] |
||||||
|
* @colde [Loke Dupont, Xstream] |
||||||
|
* @rgardler [Ross Gardler, Microsoft Open Technologies] |
||||||
|
* @squapp |
||||||
|
* @xiaomings |
||||||
|
* @rcollins112 [Rich Collins, Wowza] |
||||||
|
* @timothy003 [Timothy Liang] |
||||||
|
* @JaapHaitsma |
||||||
|
* @72lions [Thodoris Tsiridis, 72lions] |
||||||
|
* @TobbeMobiTV [Torbjörn Einarsson, MobiTV] |
||||||
|
* @TobbeEdgeware [Torbjörn Einarsson, Edgeware] |
||||||
|
* @mstorsjo [Martin Storsjö] |
||||||
|
* @Hyddan [Daniel Hedenius] |
||||||
|
* @qjia7 |
||||||
|
* @waqarz |
||||||
|
* @WMSPanel [WMSPanel Team] |
||||||
|
* @matt-hammond-bbc [Matt Hammond, BBC R&D] |
||||||
|
* @siropeich [Siro Blanco, Epic Labs] |
||||||
|
* @epiclabsDASH [Jesus Oliva, Epic Labs] |
||||||
|
* @adripanico [Adrian Caballero, Epic Labs] |
@ -0,0 +1,14 @@ |
|||||||
|
# dash.js BSD License Agreement |
||||||
|
|
||||||
|
The copyright in this software is being made available under the BSD License, included below. This software may be subject to other third party and contributor rights, including patent rights, and no such rights are granted under this license. |
||||||
|
|
||||||
|
**Copyright (c) 2015, Dash Industry Forum. |
||||||
|
**All rights reserved.** |
||||||
|
|
||||||
|
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: |
||||||
|
* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. |
||||||
|
* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. |
||||||
|
* Neither the name of the Dash Industry Forum nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. |
||||||
|
|
||||||
|
**THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.** |
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -0,0 +1,23 @@ |
|||||||
|
import * as db from "./database"; |
||||||
|
import * as read from "recursive-readdir"; |
||||||
|
import * as fs from "fs"; |
||||||
|
|
||||||
|
async function init(siteDir: string) { |
||||||
|
//If satyr is restarted in the middle of a stream
|
||||||
|
//it causes problems
|
||||||
|
//Live flags in the database stay live
|
||||||
|
await db.query('update user_meta set live=false'); |
||||||
|
//and stray m3u8 files will play the last
|
||||||
|
//few seconds of a stream back
|
||||||
|
try { |
||||||
|
var files = await read(siteDir+'/live', ['!*.m3u8']); |
||||||
|
} |
||||||
|
catch (error) {} |
||||||
|
if(files === undefined || files.length == 0) return; |
||||||
|
for(let i=0;i<files.length;i++){ |
||||||
|
fs.unlinkSync(files[i]); |
||||||
|
} |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
export { init }; |
@ -0,0 +1,212 @@ |
|||||||
|
// written by crushv <nik@telekem.net>
|
||||||
|
// thanks nikki
|
||||||
|
|
||||||
|
const net = require('net') |
||||||
|
const EventEmitter = require('events') |
||||||
|
|
||||||
|
const socket = new net.Socket() |
||||||
|
const emitter = new EventEmitter() |
||||||
|
|
||||||
|
socket.setEncoding('utf8') |
||||||
|
|
||||||
|
socket.on('error', console.error) |
||||||
|
|
||||||
|
function m (text) { |
||||||
|
console.log('> ' + text) |
||||||
|
socket.write(text + '\r\n') |
||||||
|
} |
||||||
|
|
||||||
|
var config |
||||||
|
|
||||||
|
socket.once('connect', async () => { |
||||||
|
console.log('Connected') |
||||||
|
m(`PASS ${config.pass} TS 6 :${config.sid}`) |
||||||
|
m('CAPAB QS ENCAP EX IE SAVE EUID') |
||||||
|
m(`SERVER ${config.server} 1 satyr`) |
||||||
|
}) |
||||||
|
|
||||||
|
function parseLine (l) { |
||||||
|
const colIndex = l.lastIndexOf(':') |
||||||
|
if (colIndex > -1) { |
||||||
|
return { |
||||||
|
params: l.substring(0, colIndex - 1).split(' '), |
||||||
|
query: l.substring(colIndex + 1) |
||||||
|
} |
||||||
|
} else return { params: l.split(' ') } |
||||||
|
} |
||||||
|
|
||||||
|
const servers = [] |
||||||
|
const users = {} |
||||||
|
const channels = {} |
||||||
|
|
||||||
|
const globalCommands = { |
||||||
|
// PING :42X
|
||||||
|
// params: SID
|
||||||
|
PING: l => { |
||||||
|
const { query } = parseLine(l) |
||||||
|
m(`PONG :${query}`) |
||||||
|
emitter.emit('ping') |
||||||
|
}, |
||||||
|
// PASS hunter2 TS 6 :42X
|
||||||
|
// params: password, 'TS', TS version, SID
|
||||||
|
PASS: l => { |
||||||
|
const { query } = parseLine(l) |
||||||
|
// adds a server
|
||||||
|
servers.push(query) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const serverCommands = { |
||||||
|
// EUID nik 1 1569146316 +i ~nik localhost6.attlocal.net 0::1 42XAAAAAB * * :nik
|
||||||
|
// params: nickname, hopcount, nickTS, umodes, username, visible hostname, IP address, UID, real hostname, account name, gecos
|
||||||
|
EUID: l => { |
||||||
|
const { params } = parseLine(l) |
||||||
|
const user = { |
||||||
|
nick: params[0], |
||||||
|
nickTS: params[2], |
||||||
|
modes: params[3], |
||||||
|
username: params[4], |
||||||
|
vhost: params[5], |
||||||
|
ip: params[6], |
||||||
|
uid: params[7] |
||||||
|
} |
||||||
|
users[user.uid] = user |
||||||
|
}, |
||||||
|
// SJOIN 1569142987 #test +nt :42XAAAAAB
|
||||||
|
// params: channelTS, channel, simple modes, opt. mode parameters..., nicklist
|
||||||
|
SJOIN: l => { |
||||||
|
const { params, query } = parseLine(l) |
||||||
|
const channel = { |
||||||
|
timestamp: params[0], |
||||||
|
name: params[1], |
||||||
|
modes: params.slice(2).join(' '), |
||||||
|
nicklist: query.split(' ').map(uid => { |
||||||
|
if (/[^0-9a-zA-Z]/.test(uid[0])) return { uid: uid.slice(1), mode: uid[0] } |
||||||
|
else return { uid: uid, mode: '' } |
||||||
|
}) |
||||||
|
} |
||||||
|
channels[channel.name] = channel |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
const userCommands = { |
||||||
|
// :42XAAAAAC PRIVMSG #test :asd
|
||||||
|
// params: target, msg
|
||||||
|
PRIVMSG: (l, source) => { |
||||||
|
const { params, query } = parseLine(l) |
||||||
|
emitter.emit('message', users[source].nick, params[0], query) |
||||||
|
}, |
||||||
|
// :42XAAAAAC JOIN 1569149395 #test +
|
||||||
|
JOIN: (l, source) => { |
||||||
|
const { params } = parseLine(l) |
||||||
|
channels[params[1]].nicklist.push({ |
||||||
|
uid: source |
||||||
|
}) |
||||||
|
}, |
||||||
|
// :42XAAAAAC PART #test :WeeChat 2.6
|
||||||
|
PART: (l, source) => { |
||||||
|
const { params } = parseLine(l) |
||||||
|
for (let i = 0; i < channels[params[0]].nicklist.length; i++) { |
||||||
|
if (channels[params[0]].nicklist[i].uid === source) { |
||||||
|
channels[params[0]].nicklist.splice(i, 1) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
}, |
||||||
|
QUIT: (_l, source) => { |
||||||
|
delete users[source] |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function parser (l) { |
||||||
|
const split = l.split(' ') |
||||||
|
const cmd = split[0] |
||||||
|
const args = split.slice(1).join(' ') |
||||||
|
if (globalCommands[cmd]) return globalCommands[cmd](args) |
||||||
|
if (cmd[0] === ':') { |
||||||
|
const source = cmd.slice(1) |
||||||
|
const subcmd = split[1] |
||||||
|
const subargs = split.slice(2).join(' ') |
||||||
|
if (servers.indexOf(source) > -1 && serverCommands[subcmd]) serverCommands[subcmd](subargs) |
||||||
|
if (users[source] && userCommands[subcmd]) userCommands[subcmd](subargs, source) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
socket.on('data', data => { |
||||||
|
data.split('\r\n') |
||||||
|
.filter(l => l !== '') |
||||||
|
.forEach(l => { |
||||||
|
console.log('< ' + l) |
||||||
|
parser(l) |
||||||
|
}) |
||||||
|
}) |
||||||
|
|
||||||
|
module.exports.connect = conf => new Promise((resolve, reject) => { |
||||||
|
emitter.once('ping', resolve) |
||||||
|
config = conf |
||||||
|
socket.connect(config.port) |
||||||
|
process.on('SIGINT', () => { |
||||||
|
socket.write('QUIT\r\n') |
||||||
|
process.exit() |
||||||
|
}) |
||||||
|
}) |
||||||
|
module.exports.events = emitter |
||||||
|
|
||||||
|
const genTS = () => Math.trunc((new Date()).getTime() / 1000) |
||||||
|
const genUID = () => { |
||||||
|
const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' |
||||||
|
var uid = '' |
||||||
|
for (let i = 0; i < 6; i++) uid += chars.charAt(Math.floor(Math.random() * chars.length)) |
||||||
|
if (users[uid]) return genUID() |
||||||
|
return config.sid + uid |
||||||
|
} |
||||||
|
const getUID = nick => { |
||||||
|
for (const key in users) if (users[key].nick === nick) return key |
||||||
|
} |
||||||
|
|
||||||
|
module.exports.registerUser = nick => { |
||||||
|
const user = { |
||||||
|
nick: nick, |
||||||
|
nickTS: genTS(), |
||||||
|
modes: '+i', |
||||||
|
username: '~' + nick, |
||||||
|
vhost: config.vhost, |
||||||
|
ip: '0::1', |
||||||
|
uid: genUID() |
||||||
|
} |
||||||
|
users[user.uid] = user |
||||||
|
m(`EUID ${user.nick} 1 ${user.nickTS} ${user.modes} ~${user.nick} ${user.vhost} 0::1 ${user.uid} * * :${user.nick}`) |
||||||
|
} |
||||||
|
module.exports.unregisterUser = nick => { |
||||||
|
const uid = getUID(nick) |
||||||
|
m(`:${uid} QUIT :Quit: satyr`) |
||||||
|
delete users[uid] |
||||||
|
} |
||||||
|
module.exports.join = (nick, channelName) => { |
||||||
|
const uid = getUID(nick) |
||||||
|
if (!channels[channelName]) { |
||||||
|
const channel = { |
||||||
|
timestamp: genTS(), |
||||||
|
name: channelName, |
||||||
|
modes: '+nt', |
||||||
|
nicklist: [{ uid: uid, mode: '' }] |
||||||
|
} |
||||||
|
channels[channel.name] = channel |
||||||
|
} |
||||||
|
m(`:${uid} JOIN ${channels[channelName].timestamp} ${channelName} +`) |
||||||
|
} |
||||||
|
module.exports.part = (nick, channelName) => { |
||||||
|
const uid = getUID(nick) |
||||||
|
m(`:${uid} PART ${channelName} :satyr`) |
||||||
|
for (let i = 0; i < channels[channelName].nicklist.length; i++) { |
||||||
|
if (channels[channelName].nicklist[i].uid === uid) { |
||||||
|
channels[channelName].nicklist.splice(i, 1) |
||||||
|
return |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
module.exports.send = (nick, channelName, message) => { |
||||||
|
const uid = getUID(nick) |
||||||
|
m(`:${uid} PRIVMSG ${channelName} :${message}`) |
||||||
|
emitter.emit('message', nick, channelName, message) |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
{% extends "base.njk" %} |
||||||
|
{% block content %} |
||||||
|
<p></p> |
||||||
|
<h4>Chatting</h4> |
||||||
|
The webclient for chat can be accessed on the streamer's page, or at <a href="https://{{ domain }}/chat">https://{{ domain }}/chat</a></br></br> |
||||||
|
The following commands are available:</br> |
||||||
|
`/nick kawen (password)` Password is only required if kawen is a registered user.</br> |
||||||
|
`/join kawen` Join the chatroom for kawen's stream and leave the previous room.</br> |
||||||
|
`/kick cvcvcv` Available only in your own room if you are a streamer. Forcefully disconnect the user.</br> |
||||||
|
|
||||||
|
<h4>Streaming</h4> |
||||||
|
Users should stream to <a>rtmp://{{ domain }}/stream/Stream-Key</a></br></br> |
||||||
|
The stream will be available at <a>rtmp://{{ domain }}/live/username</a> </br>or at your page on <a>https://{{ domain }}/users/username</a></br> |
||||||
|
</br> |
||||||
|
Most software, such as OBS, will have a separate field for the URL and stream key, in which case you can enter rtmp://{{ domain }}/stream/ and the stream key in the appropriate field. |
||||||
|
{% endblock %} |
Reference in new issue