diff --git a/README.md b/README.md
index 84e1e48..0a21975 100644
--- a/README.md
+++ b/README.md
@@ -17,9 +17,10 @@ The base for creating a self-hosted pad.
2. Download the [latest stable version](https://github.com/musiqpad/mqp-server/releases/latest)
3. Unzip it in the location you want to install
4. Open a terminal and `npm install --production` it
-5. Copy the `serverconfig.example.js` to create the file `serverconfig.js`
-6. Start the server by running `npm start`
-7. If everything went well, there should be no error messages.
+5. Start the server by running `npm start`
+6. If everything went well, there should be no error messages!
+
+To change the settings, edit the config.hjson file!
If you want to start musiqpad using an application manager like forever, start the app.js file. To see server logs, run `npm run log` You can also download the latest pre-release [here](https://github.com/musiqpad/mqp-server/releases) (rc = release candidate, exp = experimental)
@@ -57,7 +58,8 @@ Params:
debug: false,
stream: false
}
- }
+ },
+ config: fs.readFileSync('config.hjson'), // example config: config.example.hjson
}
```
diff --git a/config.example.hjson b/config.example.hjson
index d35b084..52fac31 100644
--- a/config.example.hjson
+++ b/config.example.hjson
@@ -60,6 +60,18 @@
Pad Description
Here you can put anything you want in HTML!
'''
+ tags: { // Tags for Google & co
+ keywords: "musiqpad"
+ description: ""
+ image: "https://cdn.musiqpad.com/img/icon-256.png" // Image on twitter/facebook/slack/...
+ twitter: "@musiqpad"
+ description: // A one to two sentence description for search engines & co
+ '''
+
+ '''
+ themeColor: "" // a hex color for the theme on chrome for android
+ favicon: "/pads/lib/img/icon.png"
+ }
}
apis: {
YT: {
@@ -154,7 +166,6 @@
"bot"
]
-
/*
@@ -175,14 +186,14 @@
*/
// Defines roles and permissions
-
- owner: { // REQUIRED ROLE
- title: "Owner"
- showtitle: true
- style: {
- color: "#F46B40"
- }
- permissions: [
+ roles: {
+ owner: { // REQUIRED ROLE
+ title: "Owner"
+ showtitle: true
+ style: {
+ color: "#F46B40"
+ }
+ permissions: [
"djqueue.join"
"djqueue.joinlocked"
"djqueue.leave"
@@ -214,23 +225,23 @@
"room.whois"
"room.whois.iphistory"
"server.checkForUpdates"
- ]
- canGrantRoles: [
+ ]
+ canGrantRoles: [
"dev"
"coowner"
"supervisor"
"bot"
"regular"
"default"
- ]
- }
- dev: { // OPTIONAL ROLE FOR MUSIQPAD DEVS
- title: "Dev"
- showtitle: true
- style: {
- color: "#A77DC2"
+ ]
}
- permissions: [
+ dev: { // OPTIONAL ROLE FOR MUSIQPAD DEVS
+ title: "Dev"
+ showtitle: true
+ style: {
+ color: "#A77DC2"
+ }
+ permissions: [
"djqueue.join"
"djqueue.joinlocked"
"djqueue.leave"
@@ -260,24 +271,24 @@
"room.restrict.mute_silent"
"room.ratelimit.bypass"
"room.whois"
- ]
- canGrantRoles: [
+ ]
+ canGrantRoles: [
"dev"
"coowner"
"supervisor"
"bot"
"regular"
"default"
- ]
- mention: "devs"
- }
- coowner: {
- title: "Co-owner"
- showtitle: true
- style: {
- color: "#89BE6C"
+ ]
+ mention: "devs"
}
- permissions: [
+ coowner: {
+ title: "Co-owner"
+ showtitle: true
+ style: {
+ color: "#89BE6C"
+ }
+ permissions: [
"djqueue.join"
"djqueue.joinlocked"
"djqueue.leave"
@@ -308,21 +319,21 @@
"room.ratelimit.bypass"
"room.whois"
"room.whois.iphistory"
- ]
- canGrantRoles: [
+ ]
+ canGrantRoles: [
"supervisor"
"bot"
"regular"
"default"
- ]
- }
- supervisor: {
- title: "Supervisor"
- showtitle: true
- style: {
- color: "#009CDD"
+ ]
}
- permissions: [
+ supervisor: {
+ title: "Supervisor"
+ showtitle: true
+ style: {
+ color: "#009CDD"
+ }
+ permissions: [
"djqueue.join"
"djqueue.joinlocked"
"djqueue.leave"
@@ -350,20 +361,20 @@
"room.restrict.mute_silent"
"room.ratelimit.bypass"
"room.whois"
- ]
- canGrantRoles: [
+ ]
+ canGrantRoles: [
"regular"
"default"
- ]
- }
- bot: {
- title: "Bot"
- showtitle: true
- badge: "android"
- style: {
- color: "#964B74"
+ ]
}
- permissions: [
+ bot: {
+ title: "Bot"
+ showtitle: true
+ badge: "android"
+ style: {
+ color: "#964B74"
+ }
+ permissions: [
"djqueue.skip.other"
"djqueue.lock"
"djqueue.cycle"
@@ -375,17 +386,17 @@
"room.restrict.mute"
"room.restrict.mute_silent"
"room.ratelimit.bypass"
- ]
- canGrantRoles: [
- ]
- }
- regular: {
- title: "Regular"
- showtitle: false
- style: {
- color: "#925AFF"
+ ]
+ canGrantRoles: [
+ ]
}
- permissions: [
+ regular: {
+ title: "Regular"
+ showtitle: false
+ style: {
+ color: "#925AFF"
+ }
+ permissions: [
"djqueue.join"
"djqueue.joinlocked"
"djqueue.leave"
@@ -396,17 +407,17 @@
"playlist.delete"
"playlist.rename"
"playlist.import"
- ]
- canGrantRoles: [
- ]
- }
- default: { // REQUIRED ROLE
- title: "Default"
- showtitle: false
- style: {
- color: "#ffffff"
+ ]
+ canGrantRoles: [
+ ]
}
- permissions: [
+ default: { // REQUIRED ROLE
+ title: "Default"
+ showtitle: false
+ style: {
+ color: "#ffffff"
+ }
+ permissions: [
"djqueue.join"
"djqueue.leave"
"chat.send"
@@ -416,8 +427,9 @@
"playlist.delete"
"playlist.rename"
"playlist.import"
- ]
- canGrantRoles: [
- ]
+ ]
+ canGrantRoles: [
+ ]
+ }
}
}
\ No newline at end of file
diff --git a/package.json b/package.json
index f6197d6..20b30e3 100644
--- a/package.json
+++ b/package.json
@@ -31,6 +31,7 @@
"deasync": "^0.1.4",
"download-git-repo": "^0.1.2",
"durationjs": "^1.1.1",
+ "ejs": "^2.4.2",
"express": "^4.13.3",
"extend": "^3.0.0",
"file-tail": "^0.3.0",
diff --git a/server-package.js b/server-package.js
index 5fb5553..bb5937f 100644
--- a/server-package.js
+++ b/server-package.js
@@ -5,6 +5,7 @@ var log = new(require('basic-logger'))({
showTimestamp: true,
prefix: "ServerContainer"
});
+var fs = require('fs');
var extend = require('extend');
@@ -23,8 +24,11 @@ var server = function (params) {
}
}
extend(true, this.settings, params);
-
+
this.start = function() {
+ if(this.settings.config) {
+ fs.writeFileSync('./config.hjson', this.settings.config, 'utf8');
+ }
if (this.settings.forever.enabled) {
forever.load(this.settings.forever.options);
that.pid = forever.start('./start.js');
@@ -35,11 +39,11 @@ var server = function (params) {
});
}
};
-
+
this.stop = function() {
stopServer();
};
-
+
function stopServer() {
if (that.settings.forever.enabled) {
forever.stop();
diff --git a/serverconfig.example.js b/serverconfig.example.js
deleted file mode 100644
index df0d5e5..0000000
--- a/serverconfig.example.js
+++ /dev/null
@@ -1,418 +0,0 @@
-var fs = require('fs');
-var config = {};
-
-// IMPORTANT: In order to be able to launch the musiqpad server, set this to true
-config.setup = false;
-
-/*
- Set this flag to false to disable web server hosting or true to enable web server hosting.
- This is useful if you want to host static files in another web server such as nginx.
-
- If you are only hosting the socket and want musiqpad to host the frontend set this to false.
-*/
-config.hostWebserver = false;
-
-config.socketServer = {
- host: '', // Host name or IP that the socket server is located at. Leave blank to bind to process IP address
- port: '8082', // Leave blank to bind to process PORT
-};
-
-config.webServer = {
- address: '', // Leave blank to bind to process IP address
- port: '8080', // Leave blank to bind to process PORT
-
- redirectHTTP: false, // Set to true if you want HTTP redirect to HTTPS.
- redirectPort: '80' // Required if setting above is true. Set to the port you want to redirect HTTP to HTTPS from (Default: 80).
-};
-
-config.useSSL = true;
-
-config.certificate = {
-// key: fs.readFileSync('../cert.key'),
-// cert: fs.readFileSync('../cert.crt')
-};
-
-config.room = {
- name: 'Pad Name', // This is your pad name. It is shown as a user friendly description on the lounge and tab name.
- slug: 'this-is-your-slug', // Slugs are used to identify your pad when connecting to musiqpad! This slug must be unique and all in lowecase.
- greet: 'Welcome to musiqpad!',
- //bg: null, // Background image file path. Accepts external images. If this is undefined the default background will be used.
- maxCon: 0,
- ownerEmail: 'pad.owner@self-hosted.com', // This needs to be set, then the server restarted to take effect.
- guestCanSeeChat: true,
- bannedCanSeeChat: false,
- lastmsglimit: 6, // How many messages a user can see after joining.
- signupcd: 0, // How many miliseconds the user cannot do certain things after they sign up.
- allowemojis: true,
- allowrecovery: false,
- recaptcha: false,
- queue: {
- cycle: true,
- lock: false,
- limit: 50,
- },
- history: {
- limit_save: 0,
- limit_send: 50,
- },
- email: {
- confirmation: false, // Whether to force user to confirm his email address before he is able to do anything
- sender: 'your@email.tld',
- /*
- description: Email server setup, please refer to https://github.com/nodemailer/nodemailer documention on what the options are, supports xOAuth 2.0
- default: {}
- */
- options: {},
- },
- description: '\
-
Pad Description
\
- Here you can put anything you want in HTML!\
- ',
-};
-
-config.apis = {
- YT: {
- key: '', // Required api key in order for YouTube search to work.
- restrictSearchToMusic: false,
- },
- SC: {
- key: '',
- },
- reCaptcha: {
- key: '',
- secret: '',
- },
- musiqpad: {
- key: '', // This is required in order for your socket to update the musiqpad lounge. Request an API Key here: https://musiqpad.com/lounge
- sendLobbyStats: true,
- },
-};
-
-// The amount of time users stay logged in for before having to login again in days.
-// 0 = login every time;
-config.loginExpire = 7;
-
-// Database config
-config.db = {
- dbType: 'level', // Values "level" for LevelDB, "mysql" for MySQL and "mongo" for MongoDB
- dbDir: './socketserver/db', // Only used for LevelDB. Directory to save databases. Default is ./socketserver/db
- mysqlUser: '', // Only used for MySQL. Database username
- mysqlPassword: '', // Only used for MySQL. Database password
- mysqlHost: '', // Only used for MySQL. Host address
- mysqlDatabase: '', // Only used for MySQL. Database being used
- mongoUser: '', // Only used for MongoDB. Database username
- mongoPassword: '', // Only used for MongoDB. Database password
- mongoHost: '', // Only used for MongoDB. Host address
- mongoDatabase: '' // Only used for MongoDB. Database being used
-};
-
-/*
- 'djqueue.join': Ability to join queue
- 'djqueue.joinlocked': Ability to join locked queue
- 'djqueue.leave': Ability to leave queue
- 'djqueue.skip.self': Ability to skip self
- 'djqueue.skip.other': Ability to skip others
- 'djqueue.lock': Ability to lock/unlock queue
- 'djqueue.limit': Ability to change waitlist limit
- 'djqueue.cycle': Ability to enable/disable queue cycle
- 'djqueue.move': Ability to move, swap, add and remove people in the queue
- 'djqueue.playLiveVideos': Ability to play live videos with undefined duration
- 'djqueue.lock.bypass': Bypass locked queue
- 'djqueue.limit.bypass': Bypass queue limit
- 'chat.send': Abilty to send chat messages
- 'chat.delete': Ability to delete others' chat messages
- 'chat.specialMention': Ability to use @everyone, @guest and @djs as mention
- 'chat.broadcast': Ability to send a highlighted broadcast message
- 'chat.private': Ability to send PMs
- 'chat.staff': Ability to send and receive special staff chat
- 'playlist.create': Ability to create playlists
- 'playlist.delete': Ability to delete playlists
- 'playlist.rename': Ability to rename playlists
- 'playlist.import': Ability to import playlists
- 'playlist.shuffle': Ability to shuffle playlists
- 'room.grantroles': Ability to change user roles (requires canGrantPerms property)
- 'room.restrict.ban': Ability to ban and unban users
- 'room.restrict.mute': Ability to mute and unmute users
- 'room.restrict.mute_silent': Ability to shadow mute and unmute users
- 'room.ratelimit.bypass': Will bypass ratelimit
- 'room.whois': Possibility to request additional information about a user
- 'room.whois.iphistory': Possibility to request all IP addresses that the user logged from since account creation
-
- NOTE: Changing the PROPERTY NAME will break role assignments. Title can be changed
- without breaking things, but property name must stay the same.
-*/
-
-// Defines the order that roles will appear on the user list
-// PROPERTY names. NOT title. (case-sensitive)
-config.roleOrder = ['dev', 'owner', 'coowner', 'supervisor', 'bot', 'regular', 'default'];
-
-
-// Defines which roles are 'staff' members
-// PROPERTY names. NOT title. (case-sensitive)
-config.staffRoles = ['dev', 'owner', 'coowner', 'supervisor', 'bot'];
-
-
-/*
-
-Role Options:
-
-rolename:{
- title: '', // This is the title that gets displayed on the frontend.
- showtitle: true/false, // This is whether or not to display the title on the frontend.
- badge: '', // This can be any icon from the mdi package. A list of the icons is available here: https://materialdesignicons.com
- style: {}, // This can be used to set specific styles to the Username of a user with this role.
- permissions: [], // A list of permissions a user with this role is allowed to use.
- canGrantRoles: [], // A list of the roles that a user with this role can grant. I.e. an owner should be able to grant manager.
- mention: '' // A custom mention. I.e. 'owner' would mention this group when someone typed @owner.
-}
-
-Below are a list of roles we suggest using.
-
-*/
-
-// Defines roles and permissions
-config.roles = {
- owner: { // REQUIRED ROLE
- title: 'Owner',
- showtitle: true,
- style: {
- 'color': '#F46B40'
- },
- permissions: [
- 'djqueue.join',
- 'djqueue.joinlocked',
- 'djqueue.leave',
- 'djqueue.skip.self',
- 'djqueue.skip.other',
- 'djqueue.lock',
- 'djqueue.cycle',
- 'djqueue.limit',
- 'djqueue.move',
- 'djqueue.playLiveVideos',
- 'djqueue.limit.bypass',
- 'djqueue.lock.bypass',
- 'chat.send',
- 'chat.private',
- 'chat.broadcast',
- 'chat.delete',
- 'chat.specialMention',
- 'chat.staff',
- 'playlist.create',
- 'playlist.delete',
- 'playlist.rename',
- 'playlist.import',
- 'playlist.shuffle',
- 'room.grantroles',
- 'room.restrict.ban',
- 'room.restrict.mute',
- 'room.restrict.mute_silent',
- 'room.ratelimit.bypass',
- 'room.whois',
- 'room.whois.iphistory',
- 'server.checkForUpdates',
- ],
- canGrantRoles: [
- 'dev',
- 'coowner',
- 'supervisor',
- 'bot',
- 'regular',
- 'default',
- ],
- },
- dev: { // OPTIONAL ROLE - FOR MUSIQPAD DEVELOPERS
- title: 'Dev',
- showtitle: true,
- style: {
- 'color': '#A77DC2'
- },
- permissions: [
- 'djqueue.join',
- 'djqueue.joinlocked',
- 'djqueue.leave',
- 'djqueue.skip.self',
- 'djqueue.skip.other',
- 'djqueue.lock',
- 'djqueue.cycle',
- 'djqueue.limit',
- 'djqueue.move',
- 'djqueue.playLiveVideos',
- 'djqueue.limit.bypass',
- 'djqueue.lock.bypass',
- 'chat.send',
- 'chat.private',
- 'chat.broadcast',
- 'chat.delete',
- 'chat.specialMention',
- 'chat.staff',
- 'playlist.create',
- 'playlist.delete',
- 'playlist.rename',
- 'playlist.import',
- 'playlist.shuffle',
- 'room.grantroles',
- 'room.restrict.ban',
- 'room.restrict.mute',
- 'room.restrict.mute_silent',
- 'room.ratelimit.bypass',
- 'room.whois',
- ],
- canGrantRoles: [
- 'dev',
- 'coowner',
- 'supervisor',
- 'bot',
- 'regular',
- 'default'
- ],
- mention: 'devs',
- },
- coowner: {
- title: 'Co-owner',
- showtitle: true,
- style: {
- 'color': '#89BE6C'
- },
- permissions: [
- 'djqueue.join',
- 'djqueue.joinlocked',
- 'djqueue.leave',
- 'djqueue.skip.self',
- 'djqueue.skip.other',
- 'djqueue.lock',
- 'djqueue.cycle',
- 'djqueue.limit',
- 'djqueue.move',
- 'djqueue.playLiveVideos',
- 'djqueue.limit.bypass',
- 'djqueue.lock.bypass',
- 'chat.send',
- 'chat.private',
- 'chat.delete',
- 'chat.specialMention',
- 'chat.broadcast',
- 'chat.staff',
- 'playlist.create',
- 'playlist.delete',
- 'playlist.rename',
- 'playlist.import',
- 'playlist.shuffle',
- 'room.grantroles',
- 'room.restrict.ban',
- 'room.restrict.mute',
- 'room.restrict.mute_silent',
- 'room.ratelimit.bypass',
- 'room.whois',
- 'room.whois.iphistory',
- ],
- canGrantRoles: [
- 'supervisor',
- 'bot',
- 'regular',
- 'default',
- ],
- },
- supervisor: {
- title: 'Supervisor',
- showtitle: true,
- style: {
- 'color': '#009CDD'
- },
- permissions: [
- 'djqueue.join',
- 'djqueue.joinlocked',
- 'djqueue.leave',
- 'djqueue.skip.self',
- 'djqueue.skip.other',
- 'djqueue.lock',
- 'djqueue.cycle',
- 'djqueue.move',
- 'djqueue.playLiveVideos',
- 'djqueue.limit.bypass',
- 'djqueue.lock.bypass',
- 'chat.send',
- 'chat.private',
- 'chat.delete',
- 'chat.specialMention',
- 'chat.staff',
- 'playlist.create',
- 'playlist.delete',
- 'playlist.rename',
- 'playlist.import',
- 'playlist.shuffle',
- 'room.grantroles',
- 'room.restrict.ban',
- 'room.restrict.mute',
- 'room.restrict.mute_silent',
- 'room.ratelimit.bypass',
- 'room.whois',
- ],
- canGrantRoles: [
- 'regular',
- 'default'
- ],
- },
- bot: {
- title: 'Bot',
- showtitle: true,
- badge: 'android',
- style: {
- 'color': '#964B74'
- },
- permissions: [
- 'djqueue.skip.other',
- 'djqueue.lock',
- 'djqueue.cycle',
- 'djqueue.move',
- 'chat.send',
- 'chat.delete',
- 'chat.specialMention',
- 'room.restrict.ban',
- 'room.restrict.mute',
- 'room.restrict.mute_silent',
- 'room.ratelimit.bypass',
- ],
- canGrantRoles: [],
- },
- regular: {
- title: 'Regular',
- showtitle: false,
- style: {
- 'color': '#925AFF'
- },
- permissions: [
- 'djqueue.join',
- 'djqueue.joinlocked',
- 'djqueue.leave',
- 'chat.send',
- 'chat.private',
- 'djqueue.skip.self',
- 'playlist.create',
- 'playlist.delete',
- 'playlist.rename',
- 'playlist.import',
- ],
- canGrantRoles: [],
- },
- default: { // REQUIRED ROLE
- title: 'Default',
- showtitle: false,
- style: {
- 'color': '#ffffff'
- },
- permissions: [
- 'djqueue.join',
- 'djqueue.leave',
- 'chat.send',
- 'chat.private',
- 'djqueue.skip.self',
- 'playlist.create',
- 'playlist.delete',
- 'playlist.rename',
- 'playlist.import'
- ],
- canGrantRoles: [],
- }
-};
-
-module.exports = config;
diff --git a/webserver/app.js b/webserver/app.js
index 9cf49fd..0cbe913 100644
--- a/webserver/app.js
+++ b/webserver/app.js
@@ -1,21 +1,27 @@
-var express = require('express');
-var compression = require('compression');
-var path = require('path');
-var http = require('http');
-var https = require('https');
-var fs = require('fs');
+// eslint-disable-next-line
+'use strict';
+const express = require('express');
+const compression = require('compression');
+const path = require('path');
+const http = require('http');
+const https = require('https');
+const fs = require('fs');
const nconf = require('nconf');
+const ejs = require('ejs');
-var app = express();
-var server = null;
-var server2 = null;
-var socketServer = null;
+const app = express();
+let server2 = null;
+let server = null;
+let socketServer = null;
+
+/* SSL */
if (nconf.get('useSSL') && nconf.get('certificate') && nconf.get('certificate:key') && nconf.get('certificate:cert')) {
const certificate = {
key: fs.readFileSync(nconf.get('certificate:key')),
cert: fs.readFileSync(nconf.get('certificate:cert')),
};
+
server = https.createServer(certificate, app);
if (nconf.get('webServer:redirectHTTP') && nconf.get('webServer:redirectPort') !== '') {
server2 = http.createServer(app);
@@ -25,48 +31,64 @@ else {
server = http.createServer(app);
}
+app.set('view engine', 'html');
+app.engine('html', ejs.renderFile);
+app.set('views', __dirname + '/public');
app.use(compression());
-if(nconf.get('webServer:redirectHTTP'))
- app.use(function(req, res, next) {
- if(!req.secure) {
- return res.redirect(['https://', req.hostname, ":", nconf.get('webServer:port') || process.env.PORT, req.url].join(''));
+if (nconf.get('webServer:redirectHTTP')) {
+ app.use((req, res, next) => {
+ if (!req.secure) {
+ return res.redirect(['https://', req.hostname, ':', nconf.get('webServer:port') || process.env.PORT, req.url].join(''));
}
next();
});
+}
+app.get(['/', '/index.html'], (req, res) => {
+ res.render('index', {
+ tags: nconf.get('room:tags'),
+ room: nconf.get('room'),
+ });
+});
app.use(express.static(path.resolve(__dirname, 'public')));
app.use('/pads', express.static(path.resolve(__dirname, 'public')));
-app.get('/config', function(req, res) {
- res.setHeader("Content-Type", "application/javascript");
+app.get('/config', (req, res) => {
+ res.setHeader('Content-Type', 'application/javascript');
res.send(fs.readFileSync(__dirname + '/public/lib/js/webconfig.js'));
});
-app.get('/api/room', function(req, res) {
- var roomInfo = {
- "slug": nconf.get('room:slug'),
- "name": nconf.get('room:name'),
- "people": null,
- "queue": null,
- "media": null,
+
+app.get('/api/room', (req, res) => {
+ const roomInfo = {
+ slug: nconf.get('room:slug'),
+ name: nconf.get('room:name'),
+ people: null,
+ queue: null,
+ media: null,
};
res.send(roomInfo);
});
server.listen(nconf.get('webServer:port') || process.env.PORT, nconf.get('webServer:address') || process.env.IP, function(){
- var addr = server.address();
- console.log("Webserver listening at", addr.address + ":" + addr.port);
+ const addr = server.address();
+ console.log('Webserver listening at', addr.address + ':' + addr.port);
});
-if(server2 != null){
+if (server2 != null) {
server2.listen(nconf.get('webServer:redirectPort') || 80, nconf.get('webServer:address') || process.env.IP, function(){
- var addr2 = server2.address();
- console.log("HTTP Webserver listening at", addr2.address + ":" + addr2.port);
+ const addr2 = server2.address();
+ console.log('HTTP Webserver listening at', addr2.address + ':' + addr2.port);
});
}
-var setSocketServer = function(ss){
+const setSocketServer = function (ss) {
socketServer = ss;
};
-module.exports = {app: app, server: server, server2: server2, setSocketServer: setSocketServer};
+module.exports = {
+ app,
+ server,
+ server2,
+ setSocketServer,
+};
diff --git a/webserver/public/index.html b/webserver/public/index.html
index ef92eef..ce04284 100644
--- a/webserver/public/index.html
+++ b/webserver/public/index.html
@@ -2,9 +2,21 @@
-
-
- musiqpad - join us!
+
+
+ <% if (tags) { %>
+
+
+
+
+
+
+
+
+ <% } else { %>
+ <% } %>
+
+ <%- room.name -%>