Change API to set content-type headers.
Rework some responses to make all responses in JSON. Increment version because of major API changes.merge-requests/18/head
parent
0b7b040ade
commit
654b65640f
|
@ -68,9 +68,11 @@ sort is the optional way to sort results. current options are "alphabet" and "al
|
||||||
|
|
||||||
page is the page number (i.e. skip the first num * page results)
|
page is the page number (i.e. skip the first num * page results)
|
||||||
|
|
||||||
**Response**: Returns an array of objects containing the username and title of each stream. Returns an empty array if no one is streaming. Returns `{"error":"error code"}` in the event of an error. Will attempt to correct malformed requests to default values.
|
**Response**: Returns an array of JSON objects containing the username and title of each stream. Returns an empty array if no one is streaming. Returns `{"error":"error code"}` in the event of an error. Will attempt to correct malformed requests to default values.
|
||||||
|
|
||||||
**Example**: `[{username:"foo", title:"bar"}]`
|
The array will be wrapped in a JSON object under the key 'users'.
|
||||||
|
|
||||||
|
**Example**: `{users: [{username:"foo", title:"bar"}] }`
|
||||||
|
|
||||||
|
|
||||||
## /api/users/all
|
## /api/users/all
|
||||||
|
@ -194,7 +196,7 @@ Get a list of the named users VODs
|
||||||
|
|
||||||
**Parameters**: user
|
**Parameters**: user
|
||||||
|
|
||||||
**Response**: Returns an array of VODs with the format `[{"name":"yote.mp4"},{"name":"yeet.mp4"}]`
|
**Response**: Returns an array of VODs inside a JSON object with the format `{"vods": [{"name":"yote.mp4"},{"name":"yeet.mp4"}] }`
|
||||||
|
|
||||||
**Notes**: VODs are always available at http://domain.com/publicEndpoint/username/filename.mp4
|
**Notes**: VODs are always available at http://domain.com/publicEndpoint/username/filename.mp4
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "satyr",
|
"name": "satyr",
|
||||||
"version": "0.8.0",
|
"version": "0.9.0",
|
||||||
"description": "A livestreaming server.",
|
"description": "A livestreaming server.",
|
||||||
"license": "AGPL-3.0",
|
"license": "AGPL-3.0",
|
||||||
"author": "knotteye",
|
"author": "knotteye",
|
||||||
|
|
12
src/api.ts
12
src/api.ts
|
@ -14,7 +14,7 @@ async function register(name: string, password: string, confirm: string): Promis
|
||||||
let k = await db.query('select stream_key from users where username='+db.raw.escape(name));
|
let k = await db.query('select stream_key from users where username='+db.raw.escape(name));
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
return {"error":""};
|
return {error:""};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function update(fields: object): Promise<object>{
|
async function update(fields: object): Promise<object>{
|
||||||
|
@ -32,12 +32,12 @@ async function update(fields: object): Promise<object>{
|
||||||
qs += ' users.record_flag='+db.raw.escape(fields['rec']);
|
qs += ' users.record_flag='+db.raw.escape(fields['rec']);
|
||||||
}
|
}
|
||||||
await db.query('UPDATE users,user_meta SET'+qs+' WHERE users.username='+db.raw.escape(fields['name'])+' AND user_meta.username='+db.raw.escape(fields['name']));
|
await db.query('UPDATE users,user_meta SET'+qs+' WHERE users.username='+db.raw.escape(fields['name'])+' AND user_meta.username='+db.raw.escape(fields['name']));
|
||||||
return {"success":""};
|
return {success:""};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function updateChat(fields: object): Promise<object>{
|
async function updateChat(fields: object): Promise<object>{
|
||||||
await db.query('UPDATE chat_integration SET xmpp='+db.raw.escape(fields['xmpp'])+', discord='+db.raw.escape(fields['discord'])+', irc='+db.raw.escape(fields['irc'])+', twitch='+db.raw.escape(fields['twitch'])+' WHERE username='+db.raw.escape(fields['name']));
|
await db.query('UPDATE chat_integration SET xmpp='+db.raw.escape(fields['xmpp'])+', discord='+db.raw.escape(fields['discord'])+', irc='+db.raw.escape(fields['irc'])+', twitch='+db.raw.escape(fields['twitch'])+' WHERE username='+db.raw.escape(fields['name']));
|
||||||
return {"success":""};
|
return {success:""};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changepwd(name: string, password: string, newpwd: string): Promise<object>{
|
async function changepwd(name: string, password: string, newpwd: string): Promise<object>{
|
||||||
|
@ -46,13 +46,13 @@ async function changepwd(name: string, password: string, newpwd: string): Promis
|
||||||
if(!auth) return {"error":"Username or Password Incorrect"};
|
if(!auth) return {"error":"Username or Password Incorrect"};
|
||||||
let newhash: string = await db.hash(newpwd);
|
let newhash: string = await db.hash(newpwd);
|
||||||
await db.query('UPDATE users set password_hash='+db.raw.escape(newhash)+'where username='+db.raw.escape(name)+' limit 1');
|
await db.query('UPDATE users set password_hash='+db.raw.escape(newhash)+'where username='+db.raw.escape(name)+' limit 1');
|
||||||
return {"success":""};
|
return {success:""};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function changesk(name: string): Promise<object>{
|
async function changesk(name: string): Promise<object>{
|
||||||
let key: string = await db.genKey();
|
let key: string = await db.genKey();
|
||||||
await db.query('UPDATE users set stream_key='+db.raw.escape(key)+'where username='+db.raw.escape(name)+' limit 1');
|
await db.query('UPDATE users set stream_key='+db.raw.escape(key)+'where username='+db.raw.escape(name)+' limit 1');
|
||||||
return {"success":key};
|
return {success: key};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function login(name: string, password: string){
|
async function login(name: string, password: string){
|
||||||
|
@ -66,7 +66,7 @@ async function deleteVODs(vodlist: Array<string>, username: string): Promise<obj
|
||||||
for(var i=0;i<vodlist.length;i++){
|
for(var i=0;i<vodlist.length;i++){
|
||||||
unlink('./site/live/'+username+'/'+vodlist[i], ()=>{});
|
unlink('./site/live/'+username+'/'+vodlist[i], ()=>{});
|
||||||
}
|
}
|
||||||
return {"success":""};
|
return {success: ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getConfig(username: string, all?: boolean): Promise<object>{
|
async function getConfig(username: string, all?: boolean): Promise<object>{
|
||||||
|
|
102
src/http.ts
102
src/http.ts
|
@ -141,31 +141,27 @@ async function parseCookie(c){
|
||||||
|
|
||||||
async function initAPI() {
|
async function initAPI() {
|
||||||
app.get('/api/instance/info', (req, res) => {
|
app.get('/api/instance/info', (req, res) => {
|
||||||
res.send(
|
res.json({
|
||||||
JSON.stringify({
|
name: config['satyr']['name'],
|
||||||
name: config['satyr']['name'],
|
domain: config['satyr']['domain'],
|
||||||
domain: config['satyr']['domain'],
|
registration: config['satyr']['registration'],
|
||||||
registration: config['satyr']['registration'],
|
version: config['satyr']['version'],
|
||||||
version: config['satyr']['version'],
|
email: config['satyr']['email']
|
||||||
email: config['satyr']['email']
|
});
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
app.get('/api/instance/config', (req, res) => {
|
app.get('/api/instance/config', (req, res) => {
|
||||||
res.send(
|
res.json({
|
||||||
JSON.stringify({
|
rtmp: {
|
||||||
rtmp: {
|
port: config['rtmp']['port'],
|
||||||
port: config['rtmp']['port'],
|
ping_timeout: config['rtmp']['ping_timeout']
|
||||||
ping_timeout: config['rtmp']['ping_timeout']
|
},
|
||||||
},
|
media: {
|
||||||
media: {
|
vods: config['config']['media']['record'],
|
||||||
vods: config['config']['media']['record'],
|
publicEndpoint: config['media']['publicEndpoint'],
|
||||||
publicEndpoint: config['media']['publicEndpoint'],
|
privateEndpoint: config['media']['privateEndpoint'],
|
||||||
privateEndpoint: config['media']['privateEndpoint'],
|
adaptive: config['transcode']['adaptive']
|
||||||
adaptive: config['transcode']['adaptive']
|
}
|
||||||
}
|
});
|
||||||
})
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
app.post('/api/users/live', (req, res) => {
|
app.post('/api/users/live', (req, res) => {
|
||||||
let qs = 'SELECT username,title FROM user_meta WHERE live=1';
|
let qs = 'SELECT username,title FROM user_meta WHERE live=1';
|
||||||
|
@ -193,8 +189,8 @@ async function initAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
db.query(qs+';').then((result) => {
|
db.query(qs+';').then((result) => {
|
||||||
if(result) res.send(result);
|
if(result) res.json({users: result});
|
||||||
else res.send('{"error":""}');
|
else res.json({error:""});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.post('/api/users/all', (req, res) => {
|
app.post('/api/users/all', (req, res) => {
|
||||||
|
@ -223,18 +219,18 @@ async function initAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
db.query(qs+';').then((result) => {
|
db.query(qs+';').then((result) => {
|
||||||
if(result) res.send(result);
|
if(result) res.json({users: result});
|
||||||
else res.send('{"error":""}');
|
else res.json({error:""});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.post('/api/register', (req, res) => {
|
app.post('/api/register', (req, res) => {
|
||||||
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.send(result);
|
res.json(result);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
res.send(result);
|
res.json(result);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.post('/api/user/update', (req, res) => {
|
app.post('/api/user/update', (req, res) => {
|
||||||
|
@ -247,12 +243,12 @@ async function initAPI() {
|
||||||
bio: "bio" in req.body ? req.body.bio : false,
|
bio: "bio" in req.body ? req.body.bio : false,
|
||||||
rec: "record" in req.body ? req.body.record : "NA"
|
rec: "record" in req.body ? req.body.record : "NA"
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
res.send(r);
|
res.json(r);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -269,12 +265,12 @@ async function initAPI() {
|
||||||
twitch: "twitch" in req.body ? req.body.twitch : false,
|
twitch: "twitch" in req.body ? req.body.twitch : false,
|
||||||
irc: "irc" in req.body ? req.body.irc : false,
|
irc: "irc" in req.body ? req.body.irc : false,
|
||||||
}).then((r) => {
|
}).then((r) => {
|
||||||
res.send(r);
|
res.json(r);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -284,19 +280,19 @@ async function initAPI() {
|
||||||
});
|
});
|
||||||
app.post('/api/user/vods/delete', (req, res) => {
|
app.post('/api/user/vods/delete', (req, res) => {
|
||||||
if(req.body.vlist === undefined || req.body.vlist === null || req.body.vlist === []){
|
if(req.body.vlist === undefined || req.body.vlist === null || req.body.vlist === []){
|
||||||
res.send('{"error":"no vods specified"}');
|
res.json({error:"no vods specified"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
validToken(req.cookies.Authorization).then((t) => {
|
validToken(req.cookies.Authorization).then((t) => {
|
||||||
if(t) {
|
if(t) {
|
||||||
//token is valid, process deletion request
|
//token is valid, process deletion request
|
||||||
return api.deleteVODs(req.body.vlist, t['username']).then((r)=> {
|
return api.deleteVODs(req.body.vlist, t['username']).then((r)=> {
|
||||||
res.send(r)
|
res.json(r)
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -305,12 +301,12 @@ async function initAPI() {
|
||||||
validToken(req.cookies.Authorization).then((t) => {
|
validToken(req.cookies.Authorization).then((t) => {
|
||||||
if(t) {
|
if(t) {
|
||||||
return api.changepwd(t['username'], req.body.password, req.body.newpassword).then((r) => {
|
return api.changepwd(t['username'], req.body.password, req.body.newpassword).then((r) => {
|
||||||
res.send(r);
|
res.json(r);
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -319,12 +315,12 @@ async function initAPI() {
|
||||||
validToken(req.cookies.Authorization).then((t) => {
|
validToken(req.cookies.Authorization).then((t) => {
|
||||||
if(t) {
|
if(t) {
|
||||||
db.query('SELECT stream_key FROM users WHERE username='+db.raw.escape(t['username'])).then(o => {
|
db.query('SELECT stream_key FROM users WHERE username='+db.raw.escape(t['username'])).then(o => {
|
||||||
if(o[0]) res.send(o[0]);
|
if(o[0]) res.json(o[0]);
|
||||||
else res.send('{"error":""}');
|
else res.json({error:""});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -332,11 +328,11 @@ async function initAPI() {
|
||||||
validToken(req.cookies.Authorization).then((t) => {
|
validToken(req.cookies.Authorization).then((t) => {
|
||||||
if(t) {
|
if(t) {
|
||||||
api.changesk(t['username']).then((r) => {
|
api.changesk(t['username']).then((r) => {
|
||||||
res.send(r);
|
res.json(r);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -346,17 +342,17 @@ async function initAPI() {
|
||||||
if(t['exp'] - 86400 < Math.floor(Date.now() / 1000)){
|
if(t['exp'] - 86400 < Math.floor(Date.now() / 1000)){
|
||||||
return genToken(t['username']).then((t) => {
|
return genToken(t['username']).then((t) => {
|
||||||
res.cookie('Authorization', t, {maxAge: 604800000, httpOnly: true, sameSite: 'Lax'});
|
res.cookie('Authorization', t, {maxAge: 604800000, httpOnly: true, sameSite: 'Lax'});
|
||||||
res.send('{"success":""}');
|
res.json({success:""});
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"success":"already verified"}');
|
res.json({success:"already verified"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send('{"error":"invalid token"}');
|
res.json({error:"invalid token"});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -365,11 +361,11 @@ async function initAPI() {
|
||||||
if(!result){
|
if(!result){
|
||||||
genToken(req.body.username).then((t) => {
|
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.send('{"success":""}');
|
res.json({success:""});
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
res.send(result);
|
res.json(result);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -377,28 +373,28 @@ async function initAPI() {
|
||||||
app.get('/api/:user/vods', (req, res) => {
|
app.get('/api/:user/vods', (req, res) => {
|
||||||
readdir('./site/live/'+req.params.user, {withFileTypes: true} , (err, files) => {
|
readdir('./site/live/'+req.params.user, {withFileTypes: true} , (err, files) => {
|
||||||
if(err) {
|
if(err) {
|
||||||
res.send([]);
|
res.json({vods: []});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
var list = files.filter(fn => fn.name.endsWith('.mp4'));
|
var list = files.filter(fn => fn.name.endsWith('.mp4'));
|
||||||
res.send(list);
|
res.json({vods: list});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
app.get('/api/:user/config', (req, res) => {
|
app.get('/api/:user/config', (req, res) => {
|
||||||
if(req.cookies.Authorization) validToken(req.cookies.Authorization).then(r => {
|
if(req.cookies.Authorization) validToken(req.cookies.Authorization).then(r => {
|
||||||
if(r && r['username'] === req.params.user) {
|
if(r && r['username'] === req.params.user) {
|
||||||
api.getConfig(req.params.user, true).then(re => {
|
api.getConfig(req.params.user, true).then(re => {
|
||||||
res.send(JSON.stringify(re));
|
res.json(re);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
else api.getConfig(req.params.user).then(re => {
|
else api.getConfig(req.params.user).then(re => {
|
||||||
res.send(JSON.stringify(re));
|
res.json(re);
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
else api.getConfig(req.params.user).then(r => {
|
else api.getConfig(req.params.user).then(r => {
|
||||||
res.send(JSON.stringify(r));
|
res.json(r);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
Reference in New Issue