## Bug tracker
-Have a bug? Please create an [issue](https://github.com/lpinca/binb/issues)
-here on GitHub, with a description of the problem, how to reproduce it and in
-what browser it occurred.
+Have a bug? Please create an [issue](https://github.com/lpinca/binb/issues) here
+on GitHub, with a description of the problem, how to reproduce it and in what
+browser it occurred.
## Copyright and license
'use strict';
-/**
- * Module dependencies.
- */
-
-var banHandler = require('./lib/middleware/ban-handler')
- , errorHandler = require('./lib/middleware/error-handler')
- , express = require('express')
- , favicon = require('serve-favicon')
- , http = require('http')
- , port = require('./config').port
- , session = require('express-session')
- , RedisStore = require('connect-redis')(session)
- , secret = process.env.SITE_SECRET || 'shhhh, very secret'
- , cookieParser = require('cookie-parser')(secret)
- , site = require('./routes/site')
- , urlencoded = require('body-parser').urlencoded
- , user = require('./routes/user')
- , usersdb = require('./lib/redis-clients').users;
+const banHandler = require('./lib/middleware/ban-handler');
+const errorHandler = require('./lib/middleware/error-handler');
+const express = require('express');
+const favicon = require('serve-favicon');
+const http = require('http');
+const port = require('./config').port;
+const session = require('express-session');
+const RedisStore = require('connect-redis')(session);
+const secret = process.env.SITE_SECRET || 'shhhh, very secret';
+const cookieParser = require('cookie-parser')(secret);
+const site = require('./routes/site');
+const urlencoded = require('body-parser').urlencoded;
+const user = require('./routes/user');
+const usersdb = require('./lib/redis-clients').users;
/**
* Setting up Express.
*/
-var app = express()
- , production = process.env.NODE_ENV === 'production'
- , pub = __dirname + '/public' // Path to public directory
- , sessionstore = new RedisStore({client: usersdb})
- , server = http.createServer(app); // HTTP server object
+const app = express();
+const production = process.env.NODE_ENV === 'production';
+const pub = __dirname + '/public'; // Path to public directory
+const sessionstore = new RedisStore({ client: usersdb });
+const server = http.createServer(app); // HTTP server object
// Configuration
app.set('view engine', 'pug');
-app.use('/static', express.static(pub, {maxAge: 2419200000})); // 4 weeks = 2419200000 ms
-app.use(favicon(pub + '/img/favicon.ico', {maxAge: 2419200000}));
+app.use('/static', express.static(pub, { maxAge: 2419200000 })); // 4 weeks = 2419200000 ms
+app.use(favicon(pub + '/img/favicon.ico', { maxAge: 2419200000 }));
app.use(banHandler);
-app.use(urlencoded({extended: false}));
+app.use(urlencoded({ extended: false }));
app.use(cookieParser);
-app.use(session({
- cookie: {
- secure: production,
- maxAge: 14400000 // 4 h = 14400000 ms
- },
- proxy: production,
- resave: false,
- rolling: true,
- saveUninitialized: true,
- secret: secret,
- store: sessionstore
-}));
+app.use(
+ session({
+ cookie: {
+ secure: production,
+ maxAge: 14400000 // 4 h = 14400000 ms
+ },
+ proxy: production,
+ resave: false,
+ rolling: true,
+ saveUninitialized: true,
+ secret: secret,
+ store: sessionstore
+ })
+);
// Routes
app.get('/', site.home);
app.get('/artworks', site.artworks);
app.get('/changepasswd', site.validationErrors, site.changePasswd);
-app.post('/changepasswd', user.validateChangePasswd, user.checkOldPasswd, user.changePasswd);
+app.post(
+ '/changepasswd',
+ user.validateChangePasswd,
+ user.checkOldPasswd,
+ user.changePasswd
+);
app.get('/leaderboards', user.leaderboards);
app.get('/login', site.validationErrors, site.login);
app.post('/login', user.validateLogin, user.checkUser, user.authenticate);
app.post('/resetpasswd', user.resetPasswd);
app.get('/sliceleaderboard', user.sliceLeaderboard);
app.get('/signup', site.validationErrors, site.signup);
-app.post('/signup', user.validateSignUp, user.userExists, user.emailExists, user.createAccount);
+app.post(
+ '/signup',
+ user.validateSignUp,
+ user.userExists,
+ user.emailExists,
+ user.createAccount
+);
app.get('/:room', site.room);
app.get('/user/:username', user.profile);
{
"gameswithnorepeats": 3,
"port": 8138,
- "rooms": [
- "hits",
- "pop",
- "rock",
- "rap",
- "oldies",
- "mixed"
- ],
+ "rooms": ["hits", "pop", "rock", "rap", "oldies", "mixed"],
"songsinarun": 15
}
const { createCanvas } = require('canvas');
-const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+const characters =
+ 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
/**
* Captcha constructor.
'use strict';
-/**
- * Module dependencies.
- */
-
-var fs = require('fs')
- , pug = require('pug')
- , nodemailer = require('nodemailer')
- , texttemplate = fs.readFileSync(__dirname + '/template.txt', 'utf-8');
+const fs = require('fs');
+const pug = require('pug');
+const nodemailer = require('nodemailer');
+const texttemplate = fs.readFileSync(__dirname + '/template.txt', 'utf-8');
/**
* Generate the HTML version of the message.
*/
-var HTMLMessage = pug.compileFile(__dirname + '/template.pug');
+const HTMLMessage = pug.compileFile(__dirname + '/template.pug');
/**
* Generate the plaintext version of the message.
*/
-var plaintextMessage = function(token) {
+const plaintextMessage = function(token) {
return texttemplate.replace(/<token>/, token);
};
* Create a reusable transport method.
*/
-var transport = nodemailer.createTransport({
+const transport = nodemailer.createTransport({
service: 'SendGrid',
auth: {
user: process.env.SENDGRID_USER,
*/
exports.sendEmail = function(to, token, callback) {
- transport.sendMail({
- from: 'binb <no-reply@binb.co>',
- to: to,
- subject: 'binb password recovery',
- html: HTMLMessage({ token: token }),
- text: plaintextMessage(token)
- }, function(err, info) {
- if (err) {
- return callback(err);
+ transport.sendMail(
+ {
+ from: 'binb <no-reply@binb.co>',
+ to: to,
+ subject: 'binb password recovery',
+ html: HTMLMessage({ token: token }),
+ text: plaintextMessage(token)
+ },
+ function(err, info) {
+ if (err) {
+ return callback(err);
+ }
+
+ callback(null, info);
}
-
- callback(null, info);
- });
+ );
};
* Cambridge, UK: Cambridge University Press. pp 263-264. ISBN 0-521-58519-8.
*/
-var checkDistance = function(s1, s2) {
- var k = Math.log(s1.length);
+const checkDistance = function(s1, s2) {
+ let k = Math.log(s1.length);
k = Math.round(k);
if (k === 0) {
return false;
}
- var d = []
- , i, j, l, m;
+ const d = [];
+ let i;
+ let j;
+ let l;
+ let m;
for (i = 0; i <= s1.length; i++) {
d[i] = []; // Now d is a matrix with s1.length + 1 rows
}
for (i = 1; i <= s1.length; i++) {
- l = ((i - k) < 1) ? 1 : i - k;
- m = ((i + k) > s2.length) ? s2.length : i + k;
+ l = i - k < 1 ? 1 : i - k;
+ m = i + k > s2.length ? s2.length : i + k;
for (j = l; j <= m; j++) {
- if (s1.charAt(i-1) === s2.charAt(j-1)) {
- d[i][j] = d[i-1][j-1];
+ if (s1.charAt(i - 1) === s2.charAt(j - 1)) {
+ d[i][j] = d[i - 1][j - 1];
continue;
}
- if (j === l && d[i][j-1] === undefined) {
- d[i][j] = Math.min(d[i-1][j-1] + 1, d[i-1][j] + 1);
+ if (j === l && d[i][j - 1] === undefined) {
+ d[i][j] = Math.min(d[i - 1][j - 1] + 1, d[i - 1][j] + 1);
continue;
}
- if (j === m && d[i-1][j] === undefined) {
- d[i][j] = Math.min(d[i][j-1] + 1, d[i-1][j-1] + 1);
+ if (j === m && d[i - 1][j] === undefined) {
+ d[i][j] = Math.min(d[i][j - 1] + 1, d[i - 1][j - 1] + 1);
continue;
}
- d[i][j] = Math.min(d[i][j-1] + 1, d[i-1][j-1] + 1, d[i-1][j] + 1);
+ d[i][j] = Math.min(d[i][j - 1] + 1, d[i - 1][j - 1] + 1, d[i - 1][j] + 1);
}
}
* Supported artist name abbreviations.
*/
-var abbreviations = {
+const abbreviations = {
bfmv: 'bullet for my valentine',
brmc: 'black rebel motorcycle club',
ccr: 'creedence clearwater revival',
return true;
}
- var _pattern;
+ let _pattern;
if (~pattern.indexOf('.')) {
// Ignore dots
}
if (~pattern.indexOf('-')) {
// Ignore dashes
- _pattern = pattern.replace(/\-/g, '');
+ _pattern = pattern.replace(/-/g, '');
if (checkDistance(_pattern, guess)) {
return true;
}
if (enableartistrules) {
// Split artist name on " & " and ", " (it can be composed by more names)
- var splits = pattern.split(/ & |, /)
- , multipleartists = splits.length !== 1;
+ const splits = pattern.split(/ & |, /);
+ const multipleartists = splits.length !== 1;
- for (var i = 0; i < splits.length; i++) {
- var artist = splits[i];
+ for (let i = 0; i < splits.length; i++) {
+ const artist = splits[i];
if (multipleartists) {
if (checkDistance(artist, guess)) {
return true;
}
if (artist.indexOf('the ') === 0) {
// Ignore "the" at the beginning of artist name
- var nothe = artist.replace(/^the /, '');
+ const nothe = artist.replace(/^the /, '');
if (checkDistance(nothe, guess)) {
return true;
}
return true;
}
}
- }
- else {
+ } else {
if (~pattern.indexOf(',')) {
// Ignore commas
_pattern = pattern.replace(/,/g, '');
}
if (/\(.+\)\??(?: \[.+\])?/.test(pattern)) {
// Ignore additional info e.g. "(Love Theme from Titanic)"
- var normalized = pattern.replace(/\(.+\)\??(?: \[.+\])?/, '').trim();
+ const normalized = pattern.replace(/\(.+\)\??(?: \[.+\])?/, '').trim();
if (checkDistance(normalized, guess)) {
return true;
}
'use strict';
-/**
- * Module dependencies.
- */
-
-var db = require('../redis-clients').users
- , forwarded = require('forwarded-for')
- , utils = require('../utils');
+const db = require('../redis-clients').users;
+const forwarded = require('forwarded-for');
+const utils = require('../utils');
/**
* Expose a middleware to filter banned IPs.
module.exports = function(req, res, next) {
res.setHeader('Cache-Control', 'no-store, no-cache');
- var address = forwarded(req, req.headers);
+ const address = forwarded(req, req.headers);
db.ttl(['ban:' + address.ip], function(err, ttl) {
if (err) {
'use strict';
-/**
- * Module dependencies.
- */
-
-var http = require('http');
+const http = require('http');
/**
* Basic error handling middleware.
'use strict';
-/**
- * Module dependencies.
- */
+const crypto = require('crypto');
-var crypto = require('crypto')
- , rrange = 4294967296;
+const rrange = 4294967296;
/**
* Return an integer, pseudo-random number in the range [0, 2^32).
*/
-var nextInt = function() {
+const nextInt = function() {
return crypto.randomBytes(4).readUInt32BE(0);
};
* Return a floating-point, pseudo-random number in the range [0, 1).
*/
-var rand = function() {
+const rand = function() {
return nextInt() / rrange;
};
'use strict';
-/**
- * Module dependencies.
- */
-
-var redis = require('redis');
+const redis = require('redis');
/**
* Setting up redis clients.
*/
-var songsclient = redis.createClient({ auth_pass: process.env.DB_AUTH })
- , usersclient = redis.createClient({ auth_pass: process.env.DB_AUTH });
+const songsclient = redis.createClient({ auth_pass: process.env.DB_AUTH });
+const usersclient = redis.createClient({ auth_pass: process.env.DB_AUTH });
songsclient.on('error', function(err) {
console.error(err.message);
'use strict';
-/**
- * Module dependencies.
- */
-
-var amatch = require('./match')
- , clients = require('./redis-clients')
- , config = require('../config')
- , fifolength = config.songsinarun * config.gameswithnorepeats
- , primus
- , randInt = require('./prng').randInt
- , rooms = {} // The Object that contains all the room instances
- , songsdb = clients.songs
- , sparks
- , updateStats = require('./stats')
- , usersdb = clients.users
- , utils = require('./utils')
- , isString = utils.isString
- , isUsername = utils.isUsername;
+const amatch = require('./match');
+const clients = require('./redis-clients');
+const config = require('../config');
+const randInt = require('./prng').randInt;
+const updateStats = require('./stats');
+const utils = require('./utils');
+
+const fifolength = config.songsinarun * config.gameswithnorepeats;
+const rooms = {}; // The Object that contains all the room instances
+const songsdb = clients.songs;
+const usersdb = clients.users;
+const isString = utils.isString;
+const isUsername = utils.isUsername;
+let primus;
+let sparks;
/**
* Expose a function to set up the rooms.
*/
module.exports = function(options) {
- var refs = require('./sparks')(options);
+ const refs = require('./sparks')(options);
primus = refs.primus;
sparks = refs.sparks;
config.rooms.forEach(function(room) {
*/
function Room(roomname) {
- this.artist = null; // Artists in lowercase
- this.artistName = null; // Artists of the track
- this.artworkUrl = null; // The URL of the album cover
- this.feat = null; // Featured artists
- this.finishline = 1; // A counter to handle the 3 fastest answers
- this.playedtracks = []; // The list of already played songs
- this.previewUrl = null; // The URL for the preview of the track
+ this.artist = null; // Artists in lowercase
+ this.artistName = null; // Artists of the track
+ this.artworkUrl = null; // The URL of the album cover
+ this.feat = null; // Featured artists
+ this.finishline = 1; // A counter to handle the 3 fastest answers
+ this.playedtracks = []; // The list of already played songs
+ this.previewUrl = null; // The URL for the preview of the track
this.roomname = roomname;
- this.songcounter = 0; // A counter for the track of the current game
- this.songtimeleft = 0; // Remaining time for the current playing track
- this.status = 3; // The room status
- this.title = null; // Title in lowercase
- this.trackName = null; // Title of the track
+ this.songcounter = 0; // A counter for the track of the current game
+ this.songtimeleft = 0; // Remaining time for the current playing track
+ this.status = 3; // The room status
+ this.title = null; // Title in lowercase
+ this.trackName = null; // Title of the track
this.trackViewUrl = null; // The iTunes URL of the track
- this.trackscount = 0; // The number of available tracks in the room
- this.totusers = 0; // The number of players in the room
+ this.trackscount = 0; // The number of available tracks in the room
+ this.totusers = 0; // The number of players in the room
this.usersData = Object.create(null);
this.initialize();
* Room states.
*/
-Room.PLAYING = 0; // A track is playing
-Room.LOADING = 1; // A track is loading
-Room.ENDING = 2; // The game is over
-Room.STARTING = 3; // A new game is about to start
+Room.PLAYING = 0; // A track is playing
+Room.LOADING = 1; // A track is loading
+Room.ENDING = 2; // The game is over
+Room.STARTING = 3; // A new game is about to start
/**
* Add points and collect players' statistics.
*/
Room.prototype.addPointsAndStats = function(nickname, allinone) {
- var stats = {}
- , userData = this.usersData[nickname];
+ const stats = {};
+ const userData = this.usersData[nickname];
switch (this.finishline) {
case 1:
*/
Room.prototype.addUser = function(spark, loggedin) {
- var nickname = spark.nickname
- , usersData = this.usersData;
+ const nickname = spark.nickname;
+ const usersData = this.usersData;
sparks[nickname] = spark;
status: this.status
}
});
- primus.room(this.roomname).except(spark.id).send('newuser', nickname, usersData);
+ primus
+ .room(this.roomname)
+ .except(spark.id)
+ .send('newuser', nickname, usersData);
};
/**
*/
Room.prototype.gameOver = function() {
- var podium = []
- , usersData = this.usersData;
+ const podium = [];
+ const usersData = this.usersData;
// Build podium
- for (var key in usersData) {
+ for (const key in usersData) {
podium.push(usersData[key]);
}
podium.sort(function(a, b) {
*/
Room.prototype.initialize = function() {
- var room = this;
+ const room = this;
songsdb.zcard([this.roomname], function(err, card) {
if (err) {
*/
Room.prototype.onChatMessage = function(msg, spark, to) {
- var from = spark.nickname;
+ const from = spark.nickname;
if (isString(to)) {
// Check if the recipient is in the room
}
// Censor answers from chat
- var feat = this.feat
- , msglcase = msg.toLowerCase();
-
- if (this.status === Room.PLAYING && (amatch(this.artist, msglcase, true) ||
- (feat && amatch(feat, msglcase, true)) || amatch(this.title, msglcase))) {
- var notice = 'You are probably right, but you have to use the box above.';
+ const feat = this.feat;
+ const msglcase = msg.toLowerCase();
+
+ if (
+ this.status === Room.PLAYING &&
+ (amatch(this.artist, msglcase, true) ||
+ (feat && amatch(feat, msglcase, true)) ||
+ amatch(this.title, msglcase))
+ ) {
+ const notice = 'You are probably right, but you have to use the box above.';
spark.send('chatmsg', notice, 'binb', from);
return;
}
return;
}
- var artist = this.artist
- , feat = this.feat
- , title = this.title
- , userData = this.usersData[spark.nickname];
+ const artist = this.artist;
+ const feat = this.feat;
+ const title = this.title;
+ const userData = this.usersData[spark.nickname];
// The user hasn't guessed anything
if (!userData.matched) {
- if ((artist === title) && amatch(title, guess, true)) {
+ if (artist === title && amatch(title, guess, true)) {
return this.onPair(spark, true);
}
if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
*/
Room.prototype.onKick = function(who, why, executor, duration, callback) {
- var room = this;
+ const room = this;
if (typeof duration === 'function') {
callback = duration;
// Check if the target player is in the room
if (room.usersData[who]) {
- var notice = 'you have been kicked by ' + executor +
- (why && ' (' + why + ')') + '.';
- var target = sparks[who];
+ const notice =
+ 'you have been kicked by ' + executor + (why && ' (' + why + ')') + '.';
+ const target = sparks[who];
if (duration) {
usersdb.setex('ban:' + target.address.ip, duration, who);
*/
Room.prototype.onMatch = function(spark, what) {
- var nickname = spark.nickname
- , usersData = this.usersData
- , userData = usersData[nickname];
+ const nickname = spark.nickname;
+ const usersData = this.usersData;
+ const userData = usersData[nickname];
userData.matched = what;
userData.points++;
*/
Room.prototype.join = function(spark, nickname) {
- var feedback
- , room = this;
+ let feedback;
+ const room = this;
if (nickname === 'binb') {
feedback = 'That name is reserved.';
Room.prototype.onUnignore = function(who, executor) {
if (this.usersData[who]) {
- var notice = executor + ' has stopped ignoring you.';
+ const notice = executor + ' has stopped ignoring you.';
sparks[who].send('chatmsg', notice, 'binb', who);
}
};
*/
Room.prototype.removeUser = function(nickname) {
- var usersData = this.usersData;
+ const usersData = this.usersData;
// Delete the references
delete sparks[nickname];
*/
Room.prototype.resetPoints = function(roundonly) {
- var usersData = this.usersData
- , userData;
+ const usersData = this.usersData;
+ let userData;
- for (var key in usersData) {
+ for (const key in usersData) {
userData = usersData[key];
if (!roundonly) {
userData.points = 0;
Room.prototype.sendLoadTrack = function() {
this.status = Room.LOADING;
- var index = randInt(this.trackscount)
- , room = this;
+ const index = randInt(this.trackscount);
+ const room = this;
songsdb.zrange([this.roomname, index, index], function(err, res) {
if (err) {
throw err;
}
- var id = res[0];
+ const id = res[0];
// Check if extracted track is in the list of already played tracks
if (~room.playedtracks.indexOf(id)) {
return room.sendLoadTrack();
room.playedtracks.push(id);
- songsdb.hmget([
- 'song:' + id
- , 'artistName'
- , 'trackName'
- , 'previewUrl'
- , 'artworkUrl60'
- , 'trackViewUrl'
- ], function(err, replies) {
- if (err) {
- throw err;
+ songsdb.hmget(
+ [
+ 'song:' + id,
+ 'artistName',
+ 'trackName',
+ 'previewUrl',
+ 'artworkUrl60',
+ 'trackViewUrl'
+ ],
+ function(err, replies) {
+ if (err) {
+ throw err;
+ }
+
+ room.artistName = replies[0];
+ room.artist = room.artistName.toLowerCase();
+ room.trackName = replies[1];
+ room.title = room.trackName.toLowerCase();
+ room.feat = /feat\. (.+?)[)\]]/.test(room.title) ? RegExp.$1 : null;
+ room.previewUrl = replies[2];
+ room.artworkUrl = replies[3];
+ room.trackViewUrl = replies[4];
+ primus.room(room.roomname).send('loadtrack', room.previewUrl);
+
+ setTimeout(room.sendPlayTrack.bind(room), 5000);
}
-
- room.artistName = replies[0];
- room.artist = room.artistName.toLowerCase();
- room.trackName = replies[1];
- room.title = room.trackName.toLowerCase();
- room.feat = /feat\. (.+?)[)\]]/.test(room.title) ? RegExp.$1 : null;
- room.previewUrl = replies[2];
- room.artworkUrl = replies[3];
- room.trackViewUrl = replies[4];
- primus.room(room.roomname).send('loadtrack', room.previewUrl);
-
- setTimeout(room.sendPlayTrack.bind(room), 5000);
- });
+ );
});
};
*/
Room.prototype.startTimer = function(end, delay) {
- var interval
- , room = this;
+ const room = this;
room.songtimeleft = end - Date.now();
- interval = setInterval(function() {
+ const interval = setInterval(function() {
room.songtimeleft = end - Date.now();
if (room.songtimeleft < delay) {
clearInterval(interval);
'use strict';
-/**
- * Module dependencies.
- */
-
-var config = require('../config')
- , db = require('./redis-clients').users
- , fs = require('fs')
- , uglify = require('uglify-js')
- , Primus = require('primus')
- , primus
- , primusemitter = require('primus-emitter')
- , primusrooms = require('primus-rooms')
- , rooms = require('./rooms').rooms
- , sessionstore
- , sparks = Object.create(null) // Sparks of all rooms
- , utils = require('./utils')
- , banDuration = utils.banDuration
- , isFunction = utils.isFunction
- , isString = utils.isString;
+const config = require('../config');
+const db = require('./redis-clients').users;
+const fs = require('fs');
+const Primus = require('primus');
+const primusemitter = require('primus-emitter');
+const primusrooms = require('primus-rooms');
+const rooms = require('./rooms').rooms;
+const uglify = require('uglify-js');
+const utils = require('./utils');
+
+const banDuration = utils.banDuration;
+const isFunction = utils.isFunction;
+const isString = utils.isString;
+const sparks = Object.create(null); // Sparks of all rooms
+let primus;
+let sessionstore;
/**
* Expose a function to set up Primus.
emitter: primusemitter,
rooms: primusrooms
},
- rooms: {wildcard: false},
+ rooms: { wildcard: false },
transformer: 'websockets'
});
// Remove unneeded middleware
- [
- 'cors',
- 'no-cache',
- 'primus.js',
- 'spec',
- 'x-xss'
- ].forEach(function(middleware) {
+ ['cors', 'no-cache', 'primus.js', 'spec', 'x-xss'].forEach(function(
+ middleware
+ ) {
primus.remove(middleware);
});
primus.on('joinroom', joinRoom);
primus.on('log', function(type) {
if (type === 'error') {
- var err = arguments[1];
+ const err = arguments[1];
console.error(err.stack || err.message);
}
});
// Minify and store the client-side library in the public directory
- var library = uglify.minify(primus.library());
+ const library = uglify.minify(primus.library());
fs.writeFileSync(__dirname + '/../public/js/primus.min.js', library.code);
- return {primus: primus, sparks: sparks};
+ return { primus: primus, sparks: sparks };
};
/**
* Authorization handler.
*/
-var authorize = function(req, authorized) {
- var cookies = req.signedCookies;
+function authorize(req, authorized) {
+ const cookies = req.signedCookies;
if (!cookies['connect.sid']) {
- var err = new Error('connect.sid cookie not transmitted');
+ const err = new Error('connect.sid cookie not transmitted');
console.error(err.message);
return authorized(err);
}
authorized();
});
});
-};
+}
/**
* Handle `connection` event.
*/
-var connection = function(spark) {
- var nickname = spark.request.cookies.nickname
- , user = spark.request.user
- , room = spark.query.room;
+function connection(spark) {
+ const nickname = spark.request.cookies.nickname;
+ const user = spark.request.user;
+ const room = spark.query.room;
- spark.send('overview', config.rooms.reduce(function(data, room) {
- data[room] = rooms[room].totusers;
- return data;
- }, {}));
+ spark.send(
+ 'overview',
+ config.rooms.reduce(function(data, room) {
+ data[room] = rooms[room].totusers;
+ return data;
+ }, {})
+ );
if (!~config.rooms.indexOf(room)) return;
if (user) {
- if (sparks[user]) { // User already in a room
+ if (sparks[user]) {
+ // User already in a room
spark.send('alreadyinaroom');
} else {
spark.nickname = user;
}
});
}
-};
+}
/**
* Handle `joinroom` event.
*/
-var joinRoom = function(room, spark) {
+function joinRoom(room, spark) {
room = rooms[room];
spark.on('ban', function(who, why, duration, callback) {
if (
room.onUnignore(who, spark.nickname);
}
});
-};
+}
'use strict';
-/**
- * Module dependencies.
- */
-
-var db = require('./redis-clients').users;
+const db = require('./redis-clients').users;
/**
* Update user statistics.
*/
-var updateStats = function(key, multi, username, stats) {
+const updateStats = function(key, multi, username, stats) {
if (stats.points) {
// Update total points
multi.hincrby(key, 'totpoints', stats.points);
*/
module.exports = function(username, stats) {
- var key = 'user:' + username
- , multi = db.multi();
+ const key = 'user:' + username;
+ const multi = db.multi();
if (stats.guesstime) {
- var args = [
- key
- , 'bestscore'
- , 'bestguesstime'
- , 'worstguesstime'
- , 'totguesstime'
- , 'guessed'
+ const args = [
+ key,
+ 'bestscore',
+ 'bestguesstime',
+ 'worstguesstime',
+ 'totguesstime',
+ 'guessed'
];
db.hmget(args, function(err, replies) {
if (err) {
return console.error(err.message);
}
if (stats.guesstime < 1000) {
- stats.guesstime = replies[4] !== '0'
- ? Math.round(replies[3] / replies[4])
- : 15000;
+ stats.guesstime =
+ replies[4] !== '0' ? Math.round(replies[3] / replies[4]) : 15000;
}
if (stats.userscore > replies[0]) {
// Set personal best
'use strict';
-/**
- * Module dependencies.
- */
-
-var db = require('./redis-clients').users;
+const db = require('./redis-clients').users;
/**
* Convert the duration of a ban from minutes to seconds and return the value.
*/
exports.buildLeaderboards = function(pointsresults, timesresults) {
- var obj = {
+ const obj = {
pointsleaderboard: [],
timesleaderboard: []
};
- for (var i=0; i<pointsresults.length; i+=2) {
+ for (let i = 0; i < pointsresults.length; i += 2) {
obj.pointsleaderboard.push({
username: pointsresults[i],
- totpoints: pointsresults[i+1]
+ totpoints: pointsresults[i + 1]
});
obj.timesleaderboard.push({
username: timesresults[i],
- bestguesstime: (timesresults[i+1] / 1000).toFixed(2)
+ bestguesstime: (timesresults[i + 1] / 1000).toFixed(2)
});
}
return obj;
*/
exports.britishFormat = function(date) {
- var day = date.getDate()
- , month = date.getMonth() + 1
- , year = date.getFullYear();
+ let day = date.getDate();
+ let month = date.getMonth() + 1;
+ const year = date.getFullYear();
if (day < 10) {
- day = '0'+day;
+ day = '0' + day;
}
if (month < 10) {
- month = '0'+month;
+ month = '0' + month;
}
- return day+'/'+month+'/'+year;
+ return day + '/' + month + '/' + year;
};
/**
exports.isEmail = function(str) {
// Simple filter, but it covers most of the use cases.
- var filter = /^[+a-zA-Z0-9_.\-]+@([a-zA-Z0-9\-]+\.)+[a-zA-Z0-9]{2,6}$/;
+ const filter = /^[+a-zA-Z0-9_.-]+@([a-zA-Z0-9-]+\.)+[a-zA-Z0-9]{2,6}$/;
return filter.test(str);
};
*/
exports.isUsername = function(str) {
- var filter = /^[a-zA-Z0-9\-_]{1,15}$/;
+ const filter = /^[a-zA-Z0-9\-_]{1,15}$/;
return filter.test(str);
};
*/
exports.randomSlogan = function() {
- var slogans = [
- 'guess the song.'
- , 'name that tune.'
- , 'i know this track.'
- ];
+ const slogans = ['guess the song.', 'name that tune.', 'i know this track.'];
return slogans[Math.floor(Math.random() * slogans.length)];
};
*/
exports.sortParams = function(offset) {
- var params = [
- 'users'
- , 'by'
- , 'user:*->bestguesstime'
- , 'get'
- , '#'
- , 'get'
- , 'user:*->bestguesstime'
- , 'limit'
- , offset
- , '30'
+ const params = [
+ 'users',
+ 'by',
+ 'user:*->bestguesstime',
+ 'get',
+ '#',
+ 'get',
+ 'user:*->bestguesstime',
+ 'limit',
+ offset,
+ '30'
];
return params;
};
*/
exports.unban = function(ip, spark, callback) {
- var issuedby = spark.nickname;
+ const issuedby = spark.nickname;
db.hget(['user:' + issuedby, 'role'], function(err, role) {
if (err) {
}
replies.forEach(function(key) {
- var bannedip = key.slice(4);
+ const bannedip = key.slice(4);
db.get([key], function(err, reply) {
if (err) {
return console.error(err.message);
(function() {
'use strict';
- var $cassettewheels = $('#cassette .wheel')
- , $chat = $('#chat')
- , $chatwrapper = $('#chat-outer-wrapper')
- , $countdown = $('#countdown')
- , $feedback = $('#feedback')
- , $guessbox = $('#guess')
- , $messagebox = $('#message')
- , $modal = $('#modal')
- , $points = $('#summary .points')
- , $progress = $('#progress')
- , $rank = $('#summary .rank')
- , $recipient = $('#recipient')
- , $tapeleft = $('#tape-left')
- , $taperight = $('#tape-right')
- , $togglechat = $('#toggle-chat')
- , $touchplay
- , $track = $('#summary .track')
- , $tracks = $('#tracks')
- , $users = $('#users')
- , audio
- , elapsedtime = 0
- , historycursor = 0
- , historyvalues = []
- , ignoredplayers = {}
- , isplaying
- , nickname
- , primus
- , pvtmsgto
- , replyto
- , roomname = location.pathname.replace(/\//g, '')
- , roundpoints = 0
- , subscriber = false
- , timer
- , urlregex = /(https?:\/\/[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])/
- , users = []
- , userscounters = {};
+ var $cassettewheels = $('#cassette .wheel');
+ var $chat = $('#chat');
+ var $chatwrapper = $('#chat-outer-wrapper');
+ var $countdown = $('#countdown');
+ var $feedback = $('#feedback');
+ var $guessbox = $('#guess');
+ var $messagebox = $('#message');
+ var $modal = $('#modal');
+ var $points = $('#summary .points');
+ var $progress = $('#progress');
+ var $rank = $('#summary .rank');
+ var $recipient = $('#recipient');
+ var $tapeleft = $('#tape-left');
+ var $taperight = $('#tape-right');
+ var $togglechat = $('#toggle-chat');
+ var $touchplay;
+ var $track = $('#summary .track');
+ var $tracks = $('#tracks');
+ var $users = $('#users');
+ var audio;
+ var elapsedtime = 0;
+ var historycursor = 0;
+ var historyvalues = [];
+ var ignoredplayers = {};
+ var isplaying;
+ var nickname;
+ var primus;
+ var pvtmsgto;
+ var replyto;
+ var roomname = location.pathname.replace(/\//g, '');
+ var roundpoints = 0;
+ var subscriber = false;
+ var timer;
+ var urlregex = /(https?:\/\/[-A-Za-z0-9+&@#/%?=~_()|!:,.;]*[-A-Za-z0-9+&@#/%=~_()|])/;
+ var users = [];
+ var userscounters = {};
var amstrings = [
- 'Do you also know the title?'
- , 'Exactly, now tell me the title!'
- , 'Yes, that\'s the artist. What about the title?'
+ 'Do you also know the title?',
+ 'Exactly, now tell me the title!',
+ "Yes, that's the artist. What about the title?"
];
var bmstrings = [
- 'Congratulations'
- , 'Exactly'
- , 'Excellent'
- , 'Good job!'
- , 'Great!'
- , 'I\'m proud of you'
- , 'Keep it up!'
- , 'Perfect'
- , 'Super duper'
- , 'That\'s it!'
- , 'Very well done'
- , 'Woohoo!'
- , 'Yeah true, do you like this track?'
- , 'Yes, you\'re right'
- , 'You make it look easy'
- , 'You remembered'
- , 'You rock!'
+ 'Congratulations',
+ 'Exactly',
+ 'Excellent',
+ 'Good job!',
+ 'Great!',
+ "I'm proud of you",
+ 'Keep it up!',
+ 'Perfect',
+ 'Super duper',
+ "That's it!",
+ 'Very well done',
+ 'Woohoo!',
+ 'Yeah true, do you like this track?',
+ "Yes, you're right",
+ 'You make it look easy',
+ 'You remembered',
+ 'You rock!'
];
var nmstrings = [
- 'Are you kidding?'
- , 'Don\'t give up'
- , 'Fail'
- , 'Haha, what?!'
- , 'Incorrect answer'
- , 'It is not that hard'
- , 'Keep trying'
- , 'No way!'
- , 'No'
- , 'Nope'
- , 'Nope, sorry!'
- , 'Oh, come on!'
- , 'That\'s wrong'
- , 'Try again'
- , 'What?!'
- , 'Wrong'
+ 'Are you kidding?',
+ "Don't give up",
+ 'Fail',
+ 'Haha, what?!',
+ 'Incorrect answer',
+ 'It is not that hard',
+ 'Keep trying',
+ 'No way!',
+ 'No',
+ 'Nope',
+ 'Nope, sorry!',
+ 'Oh, come on!',
+ "That's wrong",
+ 'Try again',
+ 'What?!',
+ 'Wrong'
];
var states = [
- 'A song is already playing, please wait for the next one...'
- , 'Game is about to start...'
- , 'Game is over'
- , 'New game will start soon...'
+ 'A song is already playing, please wait for the next one...',
+ 'Game is about to start...',
+ 'Game is over',
+ 'New game will start soon...'
];
var tmstrings = [
- 'Correct, do you also know the artist?'
- , 'Now tell me the artist!'
- , 'Yes, you guessed the title. Who is the artist?'
+ 'Correct, do you also know the artist?',
+ 'Now tell me the artist!',
+ 'Yes, you guessed the title. Who is the artist?'
];
var addCassetteBackdrop = function() {
var html = [
- '<div id="touch-backdrop">'
- , '<button id="touch-play" class="btn btn-danger disabled">'
- , '<i class="icon-play icon-white"></i> Wait'
- , '</button>'
- , '</div>'
+ '<div id="touch-backdrop">',
+ '<button id="touch-play" class="btn btn-danger disabled">',
+ '<i class="icon-play icon-white"></i> Wait',
+ '</button>',
+ '</div>'
].join('');
var $touchbackdrop = $(html);
$recipient.text('To ' + usrname + ':');
var width = $recipient.outerWidth(true) + 1;
$recipient.hide();
- $messagebox.animate({ 'width': '-=' + width + 'px' }, 'fast', function() {
+ $messagebox.animate({ width: '-=' + width + 'px' }, 'fast', function() {
$recipient.show();
});
clearInterval(timer);
cassetteAnimation(Date.now() + 5000, false);
- var artistName = data.artistName.replace(/"/g, '"')
- , trackName = data.trackName.replace(/"/g, '"')
- , attrs = ''
- , rp = '';
+ var artistName = data.artistName.replace(/"/g, '"');
+ var trackName = data.trackName.replace(/"/g, '"');
+ var attrs = '';
+ var rp = '';
if (roundpoints > 0) {
rp = '+' + roundpoints;
}
var html = [
- '<li class="bordered">'
- , '<img class="artwork" src="' + data.artworkUrl + '"/>'
- , '<div class="info">'
- , '<div class="artist" title="' + artistName + '">' + artistName + '</div>'
- , '<div class="title" title="' + trackName + '">' + trackName + '</div>'
- , '</div>'
- , '<div ' + attrs + '></div>'
- , '<div class="round-points">' + rp + '</div>'
- , '<a class="icons" target="itunes_store" href="' + data.trackViewUrl + '"></a>'
- , '</li>'
+ '<li class="bordered">',
+ '<img class="artwork" src="' + data.artworkUrl + '"/>',
+ '<div class="info">',
+ '<div class="artist" title="' + artistName + '">' + artistName + '</div>',
+ '<div class="title" title="' + trackName + '">' + trackName + '</div>',
+ '</div>',
+ '<div ' + attrs + '></div>',
+ '<div class="round-points">' + rp + '</div>',
+ '<a class="icons" target="itunes_store" href="' +
+ data.trackViewUrl +
+ '"></a>',
+ '</li>'
].join('');
$tracks.prepend(html);
var addVolumeControl = function() {
var html = [
- '<div id="volume-button">'
- , '<a class="button">'
- , '<div id="icon" class="icons volume-high"></div>'
- , '</a>'
- , '<div id="volume-slider">' // Outer background
- , '<div id="volume-total"></div>' // Rail
- , '<div id="volume-current"></div>' // Current volume
- , '<div id="volume-handle"></div>' // Handle
- , '</div>'
- , '</div>'
+ '<div id="volume-button">',
+ '<a class="button">',
+ '<div id="icon" class="icons volume-high"></div>',
+ '</a>',
+ '<div id="volume-slider">', // Outer background
+ '<div id="volume-total"></div>', // Rail
+ '<div id="volume-current"></div>', // Current volume
+ '<div id="volume-handle"></div>', // Handle
+ '</div>',
+ '</div>'
].join('');
- var $volumebutton = $(html)
- , $icon = $volumebutton.find('#icon')
- , $volumecurrent = $volumebutton.find('#volume-current')
- , $volumehandle = $volumebutton.find('#volume-handle')
- , $volumeslider = $volumebutton.find('#volume-slider')
- , $volumetotal = $volumebutton.find('#volume-total')
- , clicked = false
- , mouseisdown = false
- , mouseisover = false
- , oldvalue = 1;
+ var $volumebutton = $(html);
+ var $icon = $volumebutton.find('#icon');
+ var $volumecurrent = $volumebutton.find('#volume-current');
+ var $volumehandle = $volumebutton.find('#volume-handle');
+ var $volumeslider = $volumebutton.find('#volume-slider');
+ var $volumetotal = $volumebutton.find('#volume-total');
+ var clicked = false;
+ var mouseisdown = false;
+ var mouseisover = false;
+ var oldvalue = 1;
$volumebutton.appendTo('#volume');
var handleIcon = function(volume) {
if (volume === 0) {
$icon.removeClass().addClass('icons volume-none');
- }
- else if (volume <= 0.33) {
+ } else if (volume <= 0.33) {
$icon.removeClass().addClass('icons volume-low');
- }
- else if (volume <= 0.66) {
+ } else if (volume <= 0.66) {
$icon.removeClass().addClass('icons volume-medium');
- }
- else {
+ } else {
$icon.removeClass().addClass('icons volume-high');
}
};
var handleVolumeMove = function(e) {
- var railheight = $volumetotal.height()
- , totaloffset = $volumetotal.offset()
- , totalTop = parseInt($volumetotal.css('top').replace(/px/, ''), 10)
- , newy = e.pageY - totaloffset.top
- , volume = (railheight - newy) / railheight;
+ var railheight = $volumetotal.height();
+ var totaloffset = $volumetotal.offset();
+ var totalTop = parseInt($volumetotal.css('top').replace(/px/, ''), 10);
+ var newy = e.pageY - totaloffset.top;
+ var volume = (railheight - newy) / railheight;
clicked = false;
if (newy < 0) {
newy = 0;
- }
- else if (newy > railheight) {
+ } else if (newy > railheight) {
newy = railheight;
}
$volumecurrent.height(railheight - newy);
$volumecurrent.css('top', newy + totalTop);
- $volumehandle.css('top', totalTop + newy - ($volumehandle.height() / 2));
+ $volumehandle.css('top', totalTop + newy - $volumehandle.height() / 2);
volume = Math.max(0, volume);
volume = Math.min(volume, 1);
return $volumeslider.hide();
}
- var totalheight = $volumetotal.height()
- , totalposition = $volumetotal.position()
- , newtop = totalheight - (totalheight * volume);
+ var totalheight = $volumetotal.height();
+ var totalposition = $volumetotal.position();
+ var newtop = totalheight - totalheight * volume;
- $volumecurrent.height(totalheight - newtop );
+ $volumecurrent.height(totalheight - newtop);
$volumecurrent.css('top', totalposition.top + newtop);
- $volumehandle.css('top', totalposition.top + newtop - ($volumehandle.height() / 2));
+ $volumehandle.css(
+ 'top',
+ totalposition.top + newtop - $volumehandle.height() / 2
+ );
};
var setCookie = function(volume) {
var d = new Date();
d.setTime(d.getTime() + 31536000000); // One year in milliseconds
- document.cookie = 'volume=' + volume + ';path=/;expires=' + d.toGMTString() + ';';
+ document.cookie =
+ 'volume=' + volume + ';path=/;expires=' + d.toGMTString() + ';';
};
var setVolume = function(volume) {
}
});
- $volumebutton.hover(function() {
- mouseisover = true;
- $volumeslider.show();
- }, function() {
- mouseisover = false;
- if (!mouseisdown) {
- $volumeslider.hide();
+ $volumebutton.hover(
+ function() {
+ mouseisover = true;
+ $volumeslider.show();
+ },
+ function() {
+ mouseisover = false;
+ if (!mouseisdown) {
+ $volumeslider.hide();
+ }
}
- });
-
- $volumeslider.on('mouseover', function() {
- mouseisover = true;
- }).on('mousedown', function(e) {
- handleVolumeMove(e);
- mouseisdown = true;
- return false;
- });
+ );
- $(document).on('mouseup', function() {
- mouseisdown = false;
- if (!mouseisover) {
- $volumeslider.hide();
- }
- }).on('mousemove', function(e) {
- if (mouseisdown) {
+ $volumeslider
+ .on('mouseover', function() {
+ mouseisover = true;
+ })
+ .on('mousedown', function(e) {
handleVolumeMove(e);
- }
- });
+ mouseisdown = true;
+ return false;
+ });
+
+ $(document)
+ .on('mouseup', function() {
+ mouseisdown = false;
+ if (!mouseisover) {
+ $volumeslider.hide();
+ }
+ })
+ .on('mousemove', function(e) {
+ if (mouseisdown) {
+ handleVolumeMove(e);
+ }
+ });
(function() {
- if (/volume\s*\=/.test(document.cookie)) {
- var value = document.cookie.replace(/.*volume\s*\=\s*([^;]*);?.*/, '$1');
+ if (/volume\s*=/.test(document.cookie)) {
+ var value = document.cookie.replace(/.*volume\s*=\s*([^;]*);?.*/, '$1');
value = parseFloat(value);
positionVolumeHandle(value);
return setVolume(value);
// Called when a registered user already in a room, tries to enter in another room
var alreadyInARoom = function() {
var html = [
- '<div class="modal-header">'
- , '<h3>Already in a room</h3>'
- , '</div>'
- , '<div class="modal-body">'
- , '<div class="alert alert-error alert-block">'
- , '<h4 class="alert-heading">Warning!</h4>'
- , 'You are already in a room.<br/>'
- , 'Leave the other room and refresh this page or close this one.'
- , '</div>'
- , '</div>'
+ '<div class="modal-header">',
+ '<h3>Already in a room</h3>',
+ '</div>',
+ '<div class="modal-body">',
+ '<div class="alert alert-error alert-block">',
+ '<h4 class="alert-heading">Warning!</h4>',
+ 'You are already in a room.<br/>',
+ 'Leave the other room and refresh this page or close this one.',
+ '</div>',
+ '</div>'
].join('');
$(html).appendTo($modal);
// Start cassette animation
var cassetteAnimation = function(endtime, forward) {
- var deg
- , factor
- , millisleft
- , offsetleft
- , offsetright
- , secleft
- , step
- , width;
+ var deg;
+ var factor;
+ var millisleft;
+ var offsetleft;
+ var offsetright;
+ var secleft;
+ var step;
+ var width;
(step = function() {
millisleft = endtime - Date.now();
deg = -360 + 360 * factor;
offsetleft = 20 + 24 * factor;
offsetright = 106 + 24 * factor;
- }
- else {
+ } else {
$countdown.text(Math.round(secleft));
factor = secleft / 5;
width = 148 * factor;
// Prompt for name and send it
var chooseNickname = function(msg) {
msg = msg
- ? '<span class="label label-important">' + msg + '</span><br/>Try with another one:'
- : 'What\'s your name?';
+ ? '<span class="label label-important">' +
+ msg +
+ '</span><br/>Try with another one:'
+ : "What's your name?";
if ($modal.hasClass('in')) {
$('.modal-body p').html(msg);
}
var html = [
- '<div class="modal-header">'
- , '<h3>You are joining the ' + roomname + ' room</h3>'
- , '</div>'
- , '<div class="modal-body">'
- , '<p>' + msg + '</p>'
- , '</div>'
- , '<div class="modal-footer relative">'
- , '<input id="login" maxlength="15" type="text" name="nickname" />'
- , '<button id="join" class="btn btn-success">'
- , '<i class="icon-user icon-white"></i> Join the game'
- , '</button>'
- , '<span class="divider">'
- , '<span>or</span>'
- , '</span>'
- , '<a class="btn btn-primary" href="/login?followup=/' + roomname + '">'
- , '<i class="icon-lock icon-white"></i> Login'
- , '</a>'
- , '</div>'
+ '<div class="modal-header">',
+ '<h3>You are joining the ' + roomname + ' room</h3>',
+ '</div>',
+ '<div class="modal-body">',
+ '<p>' + msg + '</p>',
+ '</div>',
+ '<div class="modal-footer relative">',
+ '<input id="login" maxlength="15" type="text" name="nickname" />',
+ '<button id="join" class="btn btn-success">',
+ '<i class="icon-user icon-white"></i> Join the game',
+ '</button>',
+ '<span class="divider">',
+ '<span>or</span>',
+ '</span>',
+ '<a class="btn btn-primary" href="/login?followup=/' + roomname + '">',
+ '<i class="icon-lock icon-white"></i> Login',
+ '</a>',
+ '</div>'
].join('');
$(html).appendTo($modal);
- var $button = $('#join')
- , $login = $('#login');
+ var $button = $('#join');
+ var $login = $('#login');
$button.on('click', function() {
var value = $login.val();
return primus.send('nickname', value);
}
- chooseNickname('Nickname can\'t be empty.');
+ chooseNickname("Nickname can't be empty.");
});
$login.on('keyup', function(event) {
var width = $recipient.outerWidth(true) + 1;
$recipient.css('margin-right', '0');
$recipient.text('');
- $messagebox.animate({ 'width': '+=' + width + 'px' }, 'fast');
+ $messagebox.animate({ width: '+=' + width + 'px' }, 'fast');
var $el = $('.name').filter(function() {
return $(this).text() === pvtmsgto;
// Game over countdown
var countDown = function(endtime) {
- var millisleft = endtime - Date.now()
- , secleft = millisleft / 1000;
+ var millisleft = endtime - Date.now();
+ var secleft = millisleft / 1000;
$('.modal-footer span').text(Math.round(secleft));
};
var encodeEntities = function(str) {
- return str.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
+ return str
+ .replace(/&/g, '&')
+ .replace(/</g, '<')
+ .replace(/>/g, '>');
};
var gameOver = function(podium) {
var html = [
- '<div class="modal-header">'
- , '<h3>Game Over</h3>'
- , '</div>'
- , '<div class="modal-body">'
- , '<table class="table table-striped scoreboard">'
- , '<thead>'
- , '<tr>'
- , '<th>#</th>'
- , '<th>Name</th>'
- , '<th>Points</th>'
- , '<th><div class="icons cups stand1"></div></th>'
- , '<th><div class="icons cups stand2"></div></th>'
- , '<th><div class="icons cups stand3"></div></th>'
- , '<th>Guessed</th>'
- , '<th>Mean time</th>'
- , '</tr>'
- , '</thead>'
- , '<tbody>'
+ '<div class="modal-header">',
+ '<h3>Game Over</h3>',
+ '</div>',
+ '<div class="modal-body">',
+ '<table class="table table-striped scoreboard">',
+ '<thead>',
+ '<tr>',
+ '<th>#</th>',
+ '<th>Name</th>',
+ '<th>Points</th>',
+ '<th><div class="icons cups stand1"></div></th>',
+ '<th><div class="icons cups stand2"></div></th>',
+ '<th><div class="icons cups stand3"></div></th>',
+ '<th>Guessed</th>',
+ '<th>Mean time</th>',
+ '</tr>',
+ '</thead>',
+ '<tbody>'
];
podium.forEach(function(player, i) {
html.push('<tr>');
- html.push('<td><div class="icons medals rank' + (i + 1) + '"></div></td>');
+ html.push(
+ '<td><div class="icons medals rank' + (i + 1) + '"></div></td>'
+ );
html.push('<td class="name">' + player.nickname + '</td>');
html.push('<td>' + player.points + '</td>');
html.push('<td>' + player.golds + '</td>');
return;
}
- var $message = $('<span class="message"></span>')
- , prefix = from;
+ var $message = $('<span class="message"></span>');
+ var prefix = from;
if (to) {
// Private Message
- if (nickname === from ) {
+ if (nickname === from) {
prefix = '(To ' + to + ')';
- }
- else {
+ } else {
prefix = '(From ' + from + ')';
replyto = from;
}
*/
var parseCommand = function(input) {
- var inquotes = false
- , token = ''
- , tokens = [];
+ var inquotes = false;
+ var token = '';
+ var tokens = [];
for (var i = 0; i < input.length; i++) {
if (input[i] === '\\') {
continue;
}
- token += '\\'+input[i];
+ token += '\\' + input[i];
continue;
}
if (input[i] === ' ') {
if (inquotes) {
token += ' ';
- }
- else if (token.length) {
+ } else if (token.length) {
tokens.push(token);
token = '';
}
if (punishment === 'kick') {
args.push(tokens[1] || '');
- }
- else if (!tokens[1]) {
+ } else if (!tokens[1]) {
args.push('', '');
- }
- else if (!tokens[2]) {
+ } else if (!tokens[2]) {
if (/^[1-9][0-9]*$/.test(tokens[1])) {
args.push('', tokens[1]);
- }
- else {
+ } else {
args.push(tokens[1], '');
}
- }
- else {
+ } else {
args.push(tokens[1], tokens[2]);
}
var card = set.length;
return function() {
- var index = Math.floor(Math.random() * card)
- , text = set[index];
+ var index = Math.floor(Math.random() * card);
+ var text = set[index];
addFeedback(text, style);
};
$modal.modal('hide').empty();
$('#total-tracks span').text(data.trackscount);
- var $entry = $('<span class="join">' + nickname + ' joined the game</span>');
+ var $entry = $(
+ '<span class="join">' + nickname + ' joined the game</span>'
+ );
addChatEntry($entry);
updateUsers(data.usersData);
}
});
- $guessbox.on('keydown', function(event) {
- switch (event.keyCode) {
- case 13: // return
- var guess = $guessbox.val().trim();
- $guessbox.val('');
-
- if (guess) {
- historyvalues.push(guess);
- if (historyvalues.length > 20) {
- historyvalues.splice(0, 1);
+ $guessbox
+ .on('keydown', function(event) {
+ switch (event.keyCode) {
+ case 13: // return
+ var guess = $guessbox.val().trim();
+ $guessbox.val('');
+
+ if (guess) {
+ historyvalues.push(guess);
+ if (historyvalues.length > 20) {
+ historyvalues.splice(0, 1);
+ }
+ historycursor = historyvalues.length;
+
+ if (isplaying) {
+ return primus.send('guess', guess.toLowerCase());
+ }
+
+ addFeedback('You have to wait the next song...');
}
- historycursor = historyvalues.length;
- if (isplaying) {
- return primus.send('guess', guess.toLowerCase());
+ break;
+ case 38: // up-arrow
+ if (historycursor > 0) {
+ $guessbox.val(historyvalues[--historycursor]);
}
- addFeedback('You have to wait the next song...');
- }
-
- break;
- case 38: // up-arrow
- if (historycursor > 0) {
- $guessbox.val(historyvalues[--historycursor]);
- }
-
- // Prevent default action to keep the cursor at the end of the word
- return false;
- case 40: // down-arrow
- if (historycursor < historyvalues.length - 1) {
- return $guessbox.val(historyvalues[++historycursor]);
- }
+ // Prevent default action to keep the cursor at the end of the word
+ return false;
+ case 40: // down-arrow
+ if (historycursor < historyvalues.length - 1) {
+ return $guessbox.val(historyvalues[++historycursor]);
+ }
- historycursor = historyvalues.length;
- $guessbox.val('');
- }
- }).on('paste', function(event) {
- event.preventDefault();
- }).focus();
+ historycursor = historyvalues.length;
+ $guessbox.val('');
+ }
+ })
+ .on('paste', function(event) {
+ event.preventDefault();
+ })
+ .focus();
primus.on('artistmatched', randomFeedback(amstrings, 'correct'));
primus.on('bothmatched', randomFeedback(bmstrings, 'correct'));
// Show the number of players inside each room
var roomsOverview = function(data) {
$('.users-counter').each(function() {
- var room = $(this).prevAll('.room-name').text();
+ var room = $(this)
+ .prevAll('.room-name')
+ .text();
userscounters[room] = $(this);
$(this).text(data[room]);
});
if (data.status === 0) {
isplaying = true;
cassetteAnimation(Date.now() + data.timeleft, true);
- }
- else if (data.status === 1) {
+ } else if (data.status === 1) {
loadTrack(data.previewUrl);
}
};
var slashCommandHandler = function(line) {
- var $outcome = $('<span class="message private">(From binb): </span>')
- , args;
+ var $outcome = $('<span class="message private">(From binb): </span>');
+ var args;
try {
args = parseCommand(line);
- }
- catch (err) {
+ } catch (err) {
$outcome.append(err.message);
return addChatEntry($outcome);
}
- var cmdname = args.shift()
- , command = slashcommands[cmdname.substr(1)];
+ var cmdname = args.shift();
+ var command = slashcommands[cmdname.substr(1)];
if (command) {
if (args.length < command.minargs) {
// Send a private message to a user
var privateMessage = function(args, $outcome) {
if (!~users.indexOf(args[0])) {
- $outcome.text('(From binb): There\'s no one here by that name.');
+ $outcome.text("(From binb): There's no one here by that name.");
return addChatEntry($outcome);
}
addPrivate(args[0]);
// Reply to the last player who sent you a private message
var replyToPrivate = function(args, $outcome) {
if (!replyto) {
- $outcome.text('(From binb): There\'s no one to reply to.');
+ $outcome.text("(From binb): There's no one to reply to.");
return addChatEntry($outcome);
}
if (!~users.indexOf(replyto)) {
- $outcome.text('(From binb): ' + replyto + ' isn\'t here anymore.');
+ $outcome.text('(From binb): ' + replyto + " isn't here anymore.");
return addChatEntry($outcome);
}
addPrivate(replyto);
users.forEach(function(user, index) {
user = usersData[user];
- var $guesstime = $('<span class="guess-time"></span>')
- , $li = $('<li></li>')
- , $pnts = $('<span class="points">(' + user.points + ')</span>')
- , $pvt = $('<span class="private label label-info">P</span>')
- , $roundpoints = $('<span class="round-points"></span>')
- , $roundrank = $('<span></span>')
- , $username = $('<span class="name">' + user.nickname + '</span>');
+ var $guesstime = $('<span class="guess-time"></span>');
+ var $li = $('<li></li>');
+ var $pnts = $('<span class="points">(' + user.points + ')</span>');
+ var $pvt = $('<span class="private label label-info">P</span>');
+ var $roundpoints = $('<span class="round-points"></span>');
+ var $roundrank = $('<span></span>');
+ var $username = $('<span class="name">' + user.nickname + '</span>');
$li.append($pvt, $username, $pnts, $roundrank, $roundpoints, $guesstime);
if (user.registered) {
var href = 'href="/user/' + user.nickname + '"';
- $pvt.after('<a class="icons registered" target="_blank" ' + href + '></a>');
+ $pvt.after(
+ '<a class="icons registered" target="_blank" ' + href + '></a>'
+ );
}
$users.append($li);
$pvt.show();
$username.on('click', clearPrivate);
found = true;
- }
- else {
+ } else {
$username.on('click', function() {
addPrivate($(this).text());
});
$username.addClass('correct');
if (user.roundpoints > 2) {
- $guesstime.text((user.guesstime / 1000).toFixed(1) +' s');
+ $guesstime.text((user.guesstime / 1000).toFixed(1) + ' s');
}
if (user.roundpoints > 3) {
- $roundrank.addClass('icons round-rank stand' + (7 - user.roundpoints));
+ $roundrank.addClass(
+ 'icons round-rank stand' + (7 - user.roundpoints)
+ );
}
}
});
var width = $recipient.outerWidth(true) + 1;
$recipient.css('margin-right', '0');
$recipient.text('');
- $messagebox.animate({ 'width': '+=' + width + 'px' }, 'fast');
+ $messagebox.animate({ width: '+=' + width + 'px' }, 'fast');
}
};
// Convert any URLs in text into clickable links
var urlize = function(text) {
if (urlregex.test(text)) {
- var html = ''
- , splits = text.split(urlregex);
+ var html = '';
+ var splits = text.split(urlregex);
for (var i = 0; i < splits.length; i++) {
var escapedsplit = encodeEntities(splits[i]);
if (urlregex.test(splits[i])) {
- html += '<a target="_blank" href="' + escapedsplit + '">' +
- escapedsplit + '</a>';
+ html +=
+ '<a target="_blank" href="' +
+ escapedsplit +
+ '">' +
+ escapedsplit +
+ '</a>';
continue;
}
// A new player has joined the game
var userJoin = function(username, usersData) {
- var $entry = $('<span class="join">' + username +' joined the game</span>');
+ var $entry = $(
+ '<span class="join">' + username + ' joined the game</span>'
+ );
addChatEntry($entry);
updateUsers(usersData);
};
// A player has left the game
var userLeft = function(username, usersData) {
- var $entry = $('<span class="left">' + username +' left the game</span>');
+ var $entry = $('<span class="left">' + username + ' left the game</span>');
addChatEntry($entry);
updateUsers(usersData);
};
/**
-* Bootstrap.js by @fat & @mdo
-* plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-alert.js
-* Copyright 2012 Twitter, Inc.
-* http://www.apache.org/licenses/LICENSE-2.0.txt
-*/
-!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(document.body),this.$backdrop.click(this.options.backdrop=="static"?a.proxy(this.$element[0].focus,this.$element[0]):a.proxy(this.hide,this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in");if(!b)return;e?this.$backdrop.one(a.support.transition.end,b):b()}else!this.isShown&&this.$backdrop?(this.$backdrop.removeClass("in"),a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one(a.support.transition.end,b):b()):b&&b()}};var c=a.fn.modal;a.fn.modal=function(c){return this.each(function(){var d=a(this),e=d.data("modal"),f=a.extend({},a.fn.modal.defaults,d.data(),typeof c=="object"&&c);e||d.data("modal",e=new b(this,f)),typeof c=="string"?e[c]():f.show&&e.show()})},a.fn.modal.defaults={backdrop:!0,keyboard:!0,show:!0},a.fn.modal.Constructor=b,a.fn.modal.noConflict=function(){return a.fn.modal=c,this},a(document).on("click.modal.data-api",'[data-toggle="modal"]',function(b){var c=a(this),d=c.attr("href"),e=a(c.attr("data-target")||d&&d.replace(/.*(?=#[^\s]+$)/,"")),f=e.data("modal")?"toggle":a.extend({remote:!/#/.test(d)&&d},e.data(),c.data());b.preventDefault(),e.modal(f).one("hide",function(){c.focus()})})}(window.jQuery),!function(a){function d(){a(b).each(function(){e(a(this)).removeClass("open")})}function e(b){var c=b.attr("data-target"),d;c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,"")),d=c&&a(c);if(!d||!d.length)d=b.parent();return d}var b="[data-toggle=dropdown]",c=function(b){var c=a(b).on("click.dropdown.data-api",this.toggle);a("html").on("click.dropdown.data-api",function(){c.parent().removeClass("open")})};c.prototype={constructor:c,toggle:function(b){var c=a(this),f,g;if(c.is(".disabled, :disabled"))return;return f=e(c),g=f.hasClass("open"),d(),g||f.toggleClass("open"),c.focus(),!1},keydown:function(c){var d,f,g,h,i,j;if(!/(38|40|27)/.test(c.keyCode))return;d=a(this),c.preventDefault(),c.stopPropagation();if(d.is(".disabled, :disabled"))return;h=e(d),i=h.hasClass("open");if(!i||i&&c.keyCode==27)return c.which==27&&h.find(b).focus(),d.click();f=a("[role=menu] li:not(.divider):visible a",h);if(!f.length)return;j=f.index(f.filter(":focus")),c.keyCode==38&&j>0&&j--,c.keyCode==40&&j<f.length-1&&j++,~j||(j=0),f.eq(j).focus()}};var f=a.fn.dropdown;a.fn.dropdown=function(b){return this.each(function(){var d=a(this),e=d.data("dropdown");e||d.data("dropdown",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.dropdown.Constructor=c,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=f,this},a(document).on("click.dropdown.data-api",d).on("click.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.dropdown-menu",function(a){a.stopPropagation()}).on("click.dropdown.data-api",b,c.prototype.toggle).on("keydown.dropdown.data-api",b+", [role=menu]",c.prototype.keydown)}(window.jQuery),!function(a){var b='[data-dismiss="alert"]',c=function(c){a(c).on("click",b,this.close)};c.prototype.close=function(b){function f(){e.trigger("closed").remove()}var c=a(this),d=c.attr("data-target"),e;d||(d=c.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),e=a(d),b&&b.preventDefault(),e.length||(e=c.hasClass("alert")?c:c.parent()),e.trigger(b=a.Event("close"));if(b.isDefaultPrevented())return;e.removeClass("in"),a.support.transition&&e.hasClass("fade")?e.on(a.support.transition.end,f):f()};var d=a.fn.alert;a.fn.alert=function(b){return this.each(function(){var d=a(this),e=d.data("alert");e||d.data("alert",e=new c(this)),typeof b=="string"&&e[b].call(d)})},a.fn.alert.Constructor=c,a.fn.alert.noConflict=function(){return a.fn.alert=d,this},a(document).on("click.alert.data-api",b,c.prototype.close)}(window.jQuery)
\ No newline at end of file
+ * Bootstrap.js by @fat & @mdo
+ * plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-alert.js
+ * Copyright 2012 Twitter, Inc.
+ * http://www.apache.org/licenses/LICENSE-2.0.txt
+ */
+!(function(a) {
+ a(function() {
+ a.support.transition = (function() {
+ var a = (function() {
+ var a = document.createElement('bootstrap');
+ var b = {
+ WebkitTransition: 'webkitTransitionEnd',
+ MozTransition: 'transitionend',
+ OTransition: 'oTransitionEnd otransitionend',
+ transition: 'transitionend'
+ };
+ var c;
+ for (c in b) if (a.style[c] !== undefined) return b[c];
+ })();
+ return a && { end: a };
+ })();
+ });
+})(window.jQuery),
+ !(function(a) {
+ var b = function(b, c) {
+ (this.options = c),
+ (this.$element = a(b).delegate(
+ '[data-dismiss="modal"]',
+ 'click.dismiss.modal',
+ a.proxy(this.hide, this)
+ )),
+ this.options.remote &&
+ this.$element.find('.modal-body').load(this.options.remote);
+ };
+ b.prototype = {
+ constructor: b,
+ toggle: function() {
+ return this[this.isShown ? 'hide' : 'show']();
+ },
+ show: function() {
+ var b = this;
+ var c = a.Event('show');
+ this.$element.trigger(c);
+ if (this.isShown || c.isDefaultPrevented()) return;
+ (this.isShown = !0),
+ this.escape(),
+ this.backdrop(function() {
+ var c = a.support.transition && b.$element.hasClass('fade');
+ b.$element.parent().length || b.$element.appendTo(document.body),
+ b.$element.show(),
+ c && b.$element[0].offsetWidth,
+ b.$element.addClass('in').attr('aria-hidden', !1),
+ b.enforceFocus(),
+ c
+ ? b.$element.one(a.support.transition.end, function() {
+ b.$element.focus().trigger('shown');
+ })
+ : b.$element.focus().trigger('shown');
+ });
+ },
+ hide: function(b) {
+ b && b.preventDefault();
+ var c = this;
+ (b = a.Event('hide')), this.$element.trigger(b);
+ if (!this.isShown || b.isDefaultPrevented()) return;
+ (this.isShown = !1),
+ this.escape(),
+ a(document).off('focusin.modal'),
+ this.$element.removeClass('in').attr('aria-hidden', !0),
+ a.support.transition && this.$element.hasClass('fade')
+ ? this.hideWithTransition()
+ : this.hideModal();
+ },
+ enforceFocus: function() {
+ var b = this;
+ a(document).on('focusin.modal', function(a) {
+ b.$element[0] !== a.target &&
+ !b.$element.has(a.target).length &&
+ b.$element.focus();
+ });
+ },
+ escape: function() {
+ var a = this;
+ this.isShown && this.options.keyboard
+ ? this.$element.on('keyup.dismiss.modal', function(b) {
+ b.which == 27 && a.hide();
+ })
+ : this.isShown || this.$element.off('keyup.dismiss.modal');
+ },
+ hideWithTransition: function() {
+ var b = this;
+ var c = setTimeout(function() {
+ b.$element.off(a.support.transition.end), b.hideModal();
+ }, 500);
+ this.$element.one(a.support.transition.end, function() {
+ clearTimeout(c), b.hideModal();
+ });
+ },
+ hideModal: function() {
+ var a = this;
+ this.$element.hide(),
+ this.backdrop(function() {
+ a.removeBackdrop(), a.$element.trigger('hidden');
+ });
+ },
+ removeBackdrop: function() {
+ this.$backdrop && this.$backdrop.remove(), (this.$backdrop = null);
+ },
+ backdrop: function(b) {
+ var c = this;
+ var d = this.$element.hasClass('fade') ? 'fade' : '';
+ if (this.isShown && this.options.backdrop) {
+ var e = a.support.transition && d;
+ (this.$backdrop = a(
+ '<div class="modal-backdrop ' + d + '" />'
+ ).appendTo(document.body)),
+ this.$backdrop.click(
+ this.options.backdrop == 'static'
+ ? a.proxy(this.$element[0].focus, this.$element[0])
+ : a.proxy(this.hide, this)
+ ),
+ e && this.$backdrop[0].offsetWidth,
+ this.$backdrop.addClass('in');
+ if (!b) return;
+ e ? this.$backdrop.one(a.support.transition.end, b) : b();
+ } else
+ !this.isShown && this.$backdrop
+ ? (this.$backdrop.removeClass('in'),
+ a.support.transition && this.$element.hasClass('fade')
+ ? this.$backdrop.one(a.support.transition.end, b)
+ : b())
+ : b && b();
+ }
+ };
+ var c = a.fn.modal;
+ (a.fn.modal = function(c) {
+ return this.each(function() {
+ var d = a(this);
+ var e = d.data('modal');
+ var f = a.extend(
+ {},
+ a.fn.modal.defaults,
+ d.data(),
+ typeof c == 'object' && c
+ );
+ e || d.data('modal', (e = new b(this, f))),
+ typeof c == 'string' ? e[c]() : f.show && e.show();
+ });
+ }),
+ (a.fn.modal.defaults = { backdrop: !0, keyboard: !0, show: !0 }),
+ (a.fn.modal.Constructor = b),
+ (a.fn.modal.noConflict = function() {
+ return (a.fn.modal = c), this;
+ }),
+ a(document).on('click.modal.data-api', '[data-toggle="modal"]', function(
+ b
+ ) {
+ var c = a(this);
+ var d = c.attr('href');
+ var e = a(
+ c.attr('data-target') || (d && d.replace(/.*(?=#[^\s]+$)/, ''))
+ );
+ var f = e.data('modal')
+ ? 'toggle'
+ : a.extend({ remote: !/#/.test(d) && d }, e.data(), c.data());
+ b.preventDefault(),
+ e.modal(f).one('hide', function() {
+ c.focus();
+ });
+ });
+ })(window.jQuery),
+ !(function(a) {
+ function d() {
+ a(b).each(function() {
+ e(a(this)).removeClass('open');
+ });
+ }
+ function e(b) {
+ var c = b.attr('data-target');
+ var d;
+ c ||
+ ((c = b.attr('href')),
+ (c = c && /#[A-Za-z]/.test(c) && c.replace(/.*(?=#[^\s]*$)/, ''))),
+ (d = c && a(c));
+ if (!d || !d.length) d = b.parent();
+ return d;
+ }
+ var b = '[data-toggle=dropdown]';
+ var c = function(b) {
+ var c = a(b).on('click.dropdown.data-api', this.toggle);
+ a('html').on('click.dropdown.data-api', function() {
+ c.parent().removeClass('open');
+ });
+ };
+ c.prototype = {
+ constructor: c,
+ toggle: function(b) {
+ var c = a(this);
+ var f;
+ var g;
+ if (c.is('.disabled, :disabled')) return;
+ return (
+ (f = e(c)),
+ (g = f.hasClass('open')),
+ d(),
+ g || f.toggleClass('open'),
+ c.focus(),
+ !1
+ );
+ },
+ keydown: function(c) {
+ var d;
+ var f;
+ var g;
+ var h;
+ var i;
+ var j;
+ if (!/(38|40|27)/.test(c.keyCode)) return;
+ (d = a(this)), c.preventDefault(), c.stopPropagation();
+ if (d.is('.disabled, :disabled')) return;
+ (h = e(d)), (i = h.hasClass('open'));
+ if (!i || (i && c.keyCode == 27))
+ return c.which == 27 && h.find(b).focus(), d.click();
+ f = a('[role=menu] li:not(.divider):visible a', h);
+ if (!f.length) return;
+ (j = f.index(f.filter(':focus'))),
+ c.keyCode == 38 && j > 0 && j--,
+ c.keyCode == 40 && j < f.length - 1 && j++,
+ ~j || (j = 0),
+ f.eq(j).focus();
+ }
+ };
+ var f = a.fn.dropdown;
+ (a.fn.dropdown = function(b) {
+ return this.each(function() {
+ var d = a(this);
+ var e = d.data('dropdown');
+ e || d.data('dropdown', (e = new c(this))),
+ typeof b == 'string' && e[b].call(d);
+ });
+ }),
+ (a.fn.dropdown.Constructor = c),
+ (a.fn.dropdown.noConflict = function() {
+ return (a.fn.dropdown = f), this;
+ }),
+ a(document)
+ .on('click.dropdown.data-api', d)
+ .on('click.dropdown.data-api', '.dropdown form', function(a) {
+ a.stopPropagation();
+ })
+ .on('click.dropdown-menu', function(a) {
+ a.stopPropagation();
+ })
+ .on('click.dropdown.data-api', b, c.prototype.toggle)
+ .on(
+ 'keydown.dropdown.data-api',
+ b + ', [role=menu]',
+ c.prototype.keydown
+ );
+ })(window.jQuery),
+ !(function(a) {
+ var b = '[data-dismiss="alert"]';
+ var c = function(c) {
+ a(c).on('click', b, this.close);
+ };
+ c.prototype.close = function(b) {
+ function f() {
+ e.trigger('closed').remove();
+ }
+ var c = a(this);
+ var d = c.attr('data-target');
+ var e;
+ d || ((d = c.attr('href')), (d = d && d.replace(/.*(?=#[^\s]*$)/, ''))),
+ (e = a(d)),
+ b && b.preventDefault(),
+ e.length || (e = c.hasClass('alert') ? c : c.parent()),
+ e.trigger((b = a.Event('close')));
+ if (b.isDefaultPrevented()) return;
+ e.removeClass('in'),
+ a.support.transition && e.hasClass('fade')
+ ? e.on(a.support.transition.end, f)
+ : f();
+ };
+ var d = a.fn.alert;
+ (a.fn.alert = function(b) {
+ return this.each(function() {
+ var d = a(this);
+ var e = d.data('alert');
+ e || d.data('alert', (e = new c(this))),
+ typeof b == 'string' && e[b].call(d);
+ });
+ }),
+ (a.fn.alert.Constructor = c),
+ (a.fn.alert.noConflict = function() {
+ return (a.fn.alert = d), this;
+ }),
+ a(document).on('click.alert.data-api', b, c.prototype.close);
+ })(window.jQuery);
var appendResults = function(data, $leaderboard, offset, type) {
for (var i = 0; i < data.length; i += 2) {
- var col1 = '<td>' + (++offset) + '</td>'
- , col2 = '<td><a href="/user/' + data[i] + '">' + data[i] +'</a></td>'
- , col3 = (type === 'points')
+ var col1 = '<td>' + ++offset + '</td>';
+ var col2 = '<td><a href="/user/' + data[i] + '">' + data[i] + '</a></td>';
+ var col3 =
+ type === 'points'
? '<td>' + data[i + 1] + '</td>'
: '<td><i class="icon-time"></i> ' +
- (data[i + 1] / 1000).toFixed(2) + ' sec</td>';
+ (data[i + 1] / 1000).toFixed(2) +
+ ' sec</td>';
$leaderboard.append('<tr>' + col1 + col2 + col3 + '</tr>');
}
};
$('.leaderboard-wrapper').each(function(index) {
- var $leaderboard = $(this).find('tbody')
- , $loading = $(this).find('.loading')
- , offset = 0
- , type = (index === 0) ? 'points' : 'times';
+ var $leaderboard = $(this).find('tbody');
+ var $loading = $(this).find('.loading');
+ var offset = 0;
+ var type = index === 0 ? 'points' : 'times';
$(this).scroll(function() {
var diff = $(this).prop('scrollHeight') - $(this).scrollTop();
'use strict';
-/**
- * Module dependencies.
- */
-
-var Captcha = require('../lib/captcha')
- , config = require('../config')
- , db = require('../lib/redis-clients').songs
- , http = require('http')
- , parallel = require('async/parallel')
- , randInt = require('../lib/prng').randInt
- , randomSlogan = require('../lib/utils').randomSlogan
- , rooms = require('../lib/rooms').rooms;
+const Captcha = require('../lib/captcha');
+const config = require('../config');
+const db = require('../lib/redis-clients').songs;
+const http = require('http');
+const parallel = require('async/parallel');
+const randInt = require('../lib/prng').randInt;
+const randomSlogan = require('../lib/utils').randomSlogan;
+const rooms = require('../lib/rooms').rooms;
/**
* Generate a sub-task.
*/
-var subTask = function(genre) {
+const subTask = function(genre) {
return function(callback) {
- var index = randInt(rooms[genre].trackscount);
+ const index = randInt(rooms[genre].trackscount);
db.zrange([genre, index, index], function(err, res) {
if (err) {
return callback(err);
*/
exports.artworks = function(req, res, next) {
- var tasks = {};
+ const tasks = {};
config.rooms.forEach(function(room) {
tasks[room] = function(callback) {
- var subtasks = [];
- for (var i = 0; i < 6; i++) {
+ const subtasks = [];
+ for (let i = 0; i < 6; i++) {
subtasks.push(subTask(room));
}
parallel(subtasks, callback);
};
exports.recoverPasswd = function(req, res) {
- var captcha = new Captcha();
+ const captcha = new Captcha();
req.session.captchacode = captcha.getCode();
res.render('recoverpasswd', {
captchaurl: captcha.toDataURL(),
};
exports.signup = function(req, res) {
- var captcha = new Captcha();
+ const captcha = new Captcha();
req.session.captchacode = captcha.getCode();
res.render('signup', {
captchaurl: captcha.toDataURL(),
'use strict';
-/**
- * Module dependencies.
- */
-
-var crypto = require('crypto')
- , db = require('../lib/redis-clients').users
- , http = require('http')
- , mailer = require('../lib/email/mailer')
- , rooms = require('../config').rooms
- , User = require('../lib/user')
- , utils = require('../lib/utils');
+const crypto = require('crypto');
+const db = require('../lib/redis-clients').users;
+const http = require('http');
+const mailer = require('../lib/email/mailer');
+const rooms = require('../config').rooms;
+const User = require('../lib/user');
+const utils = require('../lib/utils');
/**
* Populate the whitelist of follow-up URLs.
*/
-var safeurls = ['/', '/changepasswd'];
-for (var i=0; i<rooms.length; i++) {
- safeurls.push('/'+rooms[i]);
+const safeurls = ['/', '/changepasswd'];
+for (let i = 0; i < rooms.length; i++) {
+ safeurls.push('/' + rooms[i]);
}
/**
if (err) {
return next(err);
}
- var leaderboards = utils.buildLeaderboards(pointsresults, timesresults);
+ const leaderboards = utils.buildLeaderboards(pointsresults, timesresults);
res.locals.slogan = utils.randomSlogan();
res.render('leaderboards', leaderboards);
});
*/
exports.sliceLeaderboard = function(req, res, next) {
- var begin = parseInt(req.query.begin, 10)
- , by = req.query.by;
+ const begin = parseInt(req.query.begin, 10);
+ const by = req.query.by;
if (isNaN(begin) || begin > 180 || (by !== 'points' && by !== 'times')) {
return res.status(400).send(http.STATUS_CODES[400]);
}
- var end = begin + 29;
+ const end = begin + 29;
if (by === 'points') {
db.zrevrange(['users', begin, end, 'withscores'], function(err, results) {
if (err) {
*/
exports.validateChangePasswd = function(req, res, next) {
- if (!req.session.user || req.body.oldpassword === undefined ||
- req.body.newpassword === undefined) {
+ if (
+ !req.session.user ||
+ req.body.oldpassword === undefined ||
+ req.body.newpassword === undefined
+ ) {
return res.status(400).send(http.STATUS_CODES[400]);
}
- var errors = {};
+ const errors = {};
if (req.body.oldpassword.trim() === '') {
- errors.oldpassword = 'can\'t be empty';
+ errors.oldpassword = "can't be empty";
}
if (req.body.newpassword.trim() === '') {
- errors.newpassword = 'can\'t be empty';
- }
- else if (req.body.newpassword.length < 6) {
+ errors.newpassword = "can't be empty";
+ } else if (req.body.newpassword.length < 6) {
errors.newpassword = 'must be at least 6 characters long';
- }
- else if(req.body.newpassword === req.body.oldpassword) {
- errors.newpassword = 'can\'t be changed to the old one';
+ } else if (req.body.newpassword === req.body.oldpassword) {
+ errors.newpassword = "can't be changed to the old one";
}
if (errors.oldpassword || errors.newpassword) {
};
exports.checkOldPasswd = function(req, res, next) {
- var key = 'user:' + req.session.user;
+ const key = 'user:' + req.session.user;
db.hmget([key, 'salt', 'password'], function(err, data) {
if (err) {
return next(err);
}
- var digest
- , hash = crypto.createHash('sha256');
- hash.update(data[0] + req.body.oldpassword);
- digest = hash.digest('hex');
+
+ const digest = crypto
+ .createHash('sha256')
+ .update(data[0] + req.body.oldpassword)
+ .digest('hex');
+
if (digest !== data[1]) {
- req.session.errors = {oldpassword: 'is incorrect'};
+ req.session.errors = { oldpassword: 'is incorrect' };
return res.redirect(req.url);
}
next();
};
exports.changePasswd = function(req, res, next) {
- var digest
- , followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/'
- , user = req.session.user
- , key = 'user:' + user
- , hash = crypto.createHash('sha256')
- , salt = crypto.randomBytes(6).toString('base64');
- hash.update(salt + req.body.newpassword);
- digest = hash.digest('hex');
+ const followup = ~safeurls.indexOf(req.query.followup)
+ ? req.query.followup
+ : '/';
+ const user = req.session.user;
+ const key = 'user:' + user;
+ const salt = crypto.randomBytes(6).toString('base64');
+ const digest = crypto
+ .createHash('sha256')
+ .update(salt + req.body.newpassword)
+ .digest('hex');
+
db.hmset([key, 'salt', salt, 'password', digest], function(err) {
if (err) {
return next(err);
return res.status(400).send(http.STATUS_CODES[400]);
}
- var errors = {};
+ const errors = {};
if (req.body.username.trim() === '') {
- errors.username = 'can\'t be empty';
+ errors.username = "can't be empty";
}
if (req.body.password.trim() === '') {
- errors.password = 'can\'t be empty';
+ errors.password = "can't be empty";
}
- req.session.oldvalues = {username: req.body.username};
+ req.session.oldvalues = { username: req.body.username };
if (errors.username || errors.password) {
req.session.errors = errors;
return res.redirect(req.url);
};
exports.checkUser = function(req, res, next) {
- var key = 'user:' + req.body.username;
+ const key = 'user:' + req.body.username;
db.exists([key], function(err, exists) {
if (err) {
return next(err);
// User exists, proceed with authentication
return next();
}
- req.session.errors = {alert: 'The username you specified does not exists.'};
+ req.session.errors = {
+ alert: 'The username you specified does not exists.'
+ };
res.redirect(req.url);
});
};
exports.authenticate = function(req, res, next) {
- var key = 'user:' + req.body.username;
+ const key = 'user:' + req.body.username;
db.hmget([key, 'salt', 'password'], function(err, data) {
if (err) {
return next(err);
}
- var digest
- , hash = crypto.createHash('sha256');
- hash.update(data[0] + req.body.password);
- digest = hash.digest('hex');
+
+ const digest = crypto
+ .createHash('sha256')
+ .update(data[0] + req.body.password)
+ .digest('hex');
+
if (digest === data[1]) {
- var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/';
+ const followup = ~safeurls.indexOf(req.query.followup)
+ ? req.query.followup
+ : '/';
// Authentication succeeded, regenerate the session
req.session.regenerate(function() {
req.session.cookie.maxAge = 604800000; // One week
});
return;
}
- req.session.errors = {alert: 'The password you specified is not correct.'};
+ req.session.errors = {
+ alert: 'The password you specified is not correct.'
+ };
res.redirect(req.url);
});
};
*/
exports.validateSignUp = function(req, res, next) {
- if (req.body.username === undefined || req.body.email === undefined ||
- req.body.password === undefined || req.body.captcha === undefined) {
+ if (
+ req.body.username === undefined ||
+ req.body.email === undefined ||
+ req.body.password === undefined ||
+ req.body.captcha === undefined
+ ) {
return res.status(400).send(http.STATUS_CODES[400]);
}
- var errors = {};
+ const errors = {};
if (req.body.username === 'binb') {
errors.username = 'is reserved';
- }
- else if (!utils.isUsername(req.body.username)) {
+ } else if (!utils.isUsername(req.body.username)) {
errors.username = 'must contain only alphanumeric characters';
}
if (!utils.isEmail(req.body.email)) {
errors.email = 'is not an email address';
}
if (req.body.password.trim() === '') {
- errors.password = 'can\'t be empty';
- }
- else if (req.body.password.length < 6) {
+ errors.password = "can't be empty";
+ } else if (req.body.password.length < 6) {
errors.password = 'must be at least 6 characters long';
}
if (req.body.captcha !== req.session.captchacode) {
};
exports.userExists = function(req, res, next) {
- var key = 'user:' + req.body.username;
+ const key = 'user:' + req.body.username;
db.exists([key], function(err, exists) {
if (err) {
return next(err);
}
if (exists) {
// User already exists
- req.session.errors = {alert: 'A user with that name already exists.'};
+ req.session.errors = { alert: 'A user with that name already exists.' };
return res.redirect(req.url);
}
next();
};
exports.emailExists = function(req, res, next) {
- var key = 'email:' + req.body.email;
+ const key = 'email:' + req.body.email;
db.exists([key], function(err, exists) {
if (err) {
return next(err);
}
if (exists) {
// Email already exists
- req.session.errors = {alert: 'A user with that email already exists.'};
+ req.session.errors = { alert: 'A user with that email already exists.' };
return res.redirect(req.url);
}
next();
};
exports.createAccount = function(req, res, next) {
- var digest
- , hash = crypto.createHash('sha256')
- , mailkey = 'email:' + req.body.email
- , salt = crypto.randomBytes(6).toString('base64')
- , userkey = 'user:' + req.body.username;
- hash.update(salt + req.body.password);
- digest = hash.digest('hex');
- var date = new Date().toISOString()
- , user = new User(req.body.username, req.body.email, salt, digest, date);
+ const mailkey = 'email:' + req.body.email;
+ const salt = crypto.randomBytes(6).toString('base64');
+ const userkey = 'user:' + req.body.username;
+ const digest = crypto
+ .createHash('sha256')
+ .update(salt + req.body.password)
+ .digest('hex');
+ const date = new Date().toISOString();
+ const user = new User(req.body.username, req.body.email, salt, digest, date);
// Delete old fields values
delete req.session.oldvalues;
// Add new user in the db
- var multi = db.multi();
+ const multi = db.multi();
multi.hmset(userkey, user);
multi.set(mailkey, userkey);
multi.zadd('users', 0, req.body.username);
res.render('login', {
followup: req.query.followup || '/',
slogan: utils.randomSlogan(),
- success: 'You successfully created your account. You are now ready to login.'
+ success:
+ 'You successfully created your account. You are now ready to login.'
});
});
};
return res.status(400).send(http.STATUS_CODES[400]);
}
- var errors = {};
+ const errors = {};
if (!utils.isEmail(req.body.email)) {
errors.email = 'is not an email address';
errors.captcha = 'no match';
}
- req.session.oldvalues = {email: req.body.email};
+ req.session.oldvalues = { email: req.body.email };
if (errors.email || errors.captcha) {
req.session.errors = errors;
};
exports.sendEmail = function(req, res, next) {
- var key = 'email:' + req.body.email;
+ const key = 'email:' + req.body.email;
db.get([key], function(err, data) {
if (err) {
return next(err);
delete req.session.captchacode;
delete req.session.oldvalues;
// Email exists, generate a secure random token
- var token = crypto.randomBytes(48).toString('hex');
+ const token = crypto.randomBytes(48).toString('hex');
// Token expires after 4 hours
db.setex(['token:' + token, 14400, data], function(err) {
if (err) {
});
return;
}
- req.session.errors = {alert: 'The email address you specified could not be found'};
+ req.session.errors = {
+ alert: 'The email address you specified could not be found'
+ };
res.redirect(req.url);
});
};
return res.status(400).send(http.STATUS_CODES[400]);
}
- var errors = {};
+ const errors = {};
// Validate new password
if (req.body.password.trim() === '') {
- errors.password = 'can\'t be empty';
- }
- else if (req.body.password.length < 6) {
+ errors.password = "can't be empty";
+ } else if (req.body.password.length < 6) {
errors.password = 'must be at least 6 characters long';
}
// Check token availability
return res.redirect(req.url);
}
- var key = 'token:' + req.query.token;
+ const key = 'token:' + req.query.token;
db.get([key], function(err, user) {
if (err) {
return next(err);
}
if (user) {
db.del(key); // Delete the token
- var digest
- , hash = crypto.createHash('sha256')
- , salt = crypto.randomBytes(6).toString('base64');
- hash.update(salt + req.body.password);
- digest = hash.digest('hex');
+ const salt = crypto.randomBytes(6).toString('base64');
+ const digest = crypto
+ .createHash('sha256')
+ .update(salt + req.body.password)
+ .digest('hex');
+
db.hmset([user, 'salt', salt, 'password', digest], function(err) {
if (err) {
return next(err);
});
return;
}
- req.session.errors = {alert: 'Invalid or expired token.'};
+ req.session.errors = { alert: 'Invalid or expired token.' };
res.redirect(req.url);
});
};
*/
exports.profile = function(req, res, next) {
- var key = 'user:' + req.params.username;
+ const key = 'user:' + req.params.username;
db.exists([key], function(err, exists) {
if (err) {
return next(err);
if (err) {
return next(err);
}
- var joindate = new Date(user.joindate);
+ const joindate = new Date(user.joindate);
user.bestguesstime = (user.bestguesstime / 1000).toFixed(1);
user.joindate = utils.britishFormat(joindate);
if (user.guessed !== '0') {
module.exports = {
pop: [
- 262836961 // ADELE
- , 459885 // Avril Lavigne
- , 1419227 // Beyoncé
- , 217005 // Britney Spears
- , 64387566 // Katy Perry
- , 277293880 // Lady GaGa
- , 184932871 // MIKA
+ 262836961, // ADELE
+ 459885, // Avril Lavigne
+ 1419227, // Beyoncé
+ 217005, // Britney Spears
+ 64387566, // Katy Perry
+ 277293880, // Lady GaGa
+ 184932871 // MIKA
],
rap: [
- 1587965 // A Tribe Called Quest
- , 1971863 // Beastie Boys
- , 465802 // Cypress Hill
- , 384304 // EPMD
- , 289550 // OutKast
- , 13503763 // Swollen Members
- , 43680 // The Roots
+ 1587965, // A Tribe Called Quest
+ 1971863, // Beastie Boys
+ 465802, // Cypress Hill
+ 384304, // EPMD
+ 289550, // OutKast
+ 13503763, // Swollen Members
+ 43680 // The Roots
],
rock: [
- 5040714 // AC/DC
- , 462006 // Bob Dylan
- , 994656 // Led Zeppelin
- , 3296287 // Queen
- , 562555 // The Beach Boys
- , 136975 // The Beatles
- , 62819 // The Jimi Hendrix Experience
+ 5040714, // AC/DC
+ 462006, // Bob Dylan
+ 994656, // Led Zeppelin
+ 3296287, // Queen
+ 562555, // The Beach Boys
+ 136975, // The Beatles
+ 62819 // The Jimi Hendrix Experience
]
};
'use strict';
-/**
- * Module dependencies.
- */
-
-var artistIds = require('./artist-ids')
- , http = require('http')
- , JSONStream = require('JSONStream')
- , limit = 7 // The number of songs to retrieve for each artist
- , parser = JSONStream.parse(['results', true])
- , popIds = artistIds.pop
- , rapIds = artistIds.rap
- , rc = require('redis').createClient()
- , rockIds = artistIds.rock
- , rooms = require('../config').rooms
- , score
- , skip = 0 // Skip counter
- , songId = 0;
+const artistIds = require('./artist-ids');
+const http = require('http');
+const JSONStream = require('JSONStream');
+const limit = 7; // The number of songs to retrieve for each artist
+const parser = JSONStream.parse(['results', true]);
+const popIds = artistIds.pop;
+const rapIds = artistIds.rap;
+const rc = require('redis').createClient();
+const rockIds = artistIds.rock;
+let rooms = require('../config').rooms;
+let score;
+let skip = 0; // Skip counter
+let songId = 0;
-var options = {
- headers: {'content-type': 'application/json'},
+const options = {
+ headers: { 'content-type': 'application/json' },
host: 'itunes.apple.com',
// Look up multiple artists by their IDs and get `limit` songs for each one
- path: '/lookup?id='+popIds.concat(rapIds, rockIds).join()+'&entity=song&limit='+limit,
+ path:
+ '/lookup?id=' +
+ popIds.concat(rapIds, rockIds).join() +
+ '&entity=song&limit=' +
+ limit,
port: 80
};
* Set the rooms in which the songs of a given artist will be loaded.
*/
-var updateRooms = function(artistId) {
+const updateRooms = function(artistId) {
rooms = ['mixed'];
score = 0;
if (artistId === popIds[0]) {
rooms.push('hits', 'pop');
// Set the skip counter (there is no need to update the rooms for the next pop artists)
skip = popIds.length - 1;
- }
- else if (artistId === rapIds[0]) {
+ } else if (artistId === rapIds[0]) {
rooms.push('rap');
skip = rapIds.length - 1;
- }
- else {
+ } else {
rooms.push('oldies', 'rock');
skip = rockIds.length - 1;
}
return;
}
- rc.hmset('song:'+songId,
- 'artistName', track.artistName,
- 'trackName', track.trackName,
- 'trackViewUrl', track.trackViewUrl,
- 'previewUrl', track.previewUrl,
- 'artworkUrl60', track.artworkUrl60,
- 'artworkUrl100', track.artworkUrl100
+ rc.hmset(
+ 'song:' + songId,
+ 'artistName',
+ track.artistName,
+ 'trackName',
+ track.trackName,
+ 'trackViewUrl',
+ track.trackViewUrl,
+ 'previewUrl',
+ track.previewUrl,
+ 'artworkUrl60',
+ track.artworkUrl60,
+ 'artworkUrl100',
+ track.artworkUrl100
);
rooms.forEach(function(room) {
- var _score = (room === 'mixed') ? songId : score;
+ const _score = room === 'mixed' ? songId : score;
rc.zadd(room, _score, songId);
});