*/
var config = require('./config')
- , express = require('express')
- , http = require('http')
- , parseCookie = require('express/node_modules/cookie').parse
- , parseSignedCookies = require('express/node_modules/connect').utils.parseSignedCookies
- , redisstore = require('connect-redis')(express)
- , site = require('./routes/site')
- , user = require('./routes/user')
- , usersdb = require('./lib/redis-clients').users;
+ , express = require('express')
+ , http = require('http')
+ , parseCookie = require('express/node_modules/cookie').parse
+ , parseSignedCookies = require('express/node_modules/connect').utils.parseSignedCookies
+ , redisstore = require('connect-redis')(express)
+ , site = require('./routes/site')
+ , user = require('./routes/user')
+ , usersdb = require('./lib/redis-clients').users;
/**
* Setting up Express.
*/
var app = express()
- , pub = __dirname + '/public' // Path to public directory
- , sessionstore = new redisstore({client: usersdb});
+ , pub = __dirname + '/public' // Path to public directory
+ , sessionstore = new redisstore({client: usersdb});
// Configuration
app.set('view engine', 'jade');
*/
var io = require('socket.io').listen(server)
- , sockets = Object.create(null); // Sockets of all rooms
+ , sockets = Object.create(null); // Sockets of all rooms
// Configuration
io.enable('browser client minification');
io.enable('browser client gzip');
io.set('log level', 1);
io.set('transports', [
- 'websocket'
- , 'htmlfile'
- , 'xhr-polling'
- , 'jsonp-polling'
+ 'websocket'
+ , 'htmlfile'
+ , 'xhr-polling'
+ , 'jsonp-polling'
]);
// Authorization
io.set('authorization', function(data, accept) {
- if(!data.headers.cookie) {
- return accept('no cookie transmitted', false);
+ if(!data.headers.cookie) {
+ return accept('no cookie transmitted', false);
+ }
+ var signedcookie = parseCookie(data.headers.cookie);
+ var cookie = parseSignedCookies(signedcookie, process.env.SITE_SECRET);
+ sessionstore.get(cookie['connect.sid'], function(err, session) {
+ if (err) {
+ return accept(err.message, false);
}
- var signedcookie = parseCookie(data.headers.cookie);
- var cookie = parseSignedCookies(signedcookie, process.env.SITE_SECRET);
- sessionstore.get(cookie['connect.sid'], function(err, session) {
- if (err) {
- return accept(err.message, false);
- }
- else if (!session) {
- var debuginfos = {
- address: data.headers['x-forwarded-for'],
- ua: data.headers['user-agent'],
- cookie: data.headers.cookie
- };
- console.log(debuginfos);
- return accept('session not found', false);
- }
- data.session = session;
- accept(null, true);
- });
+ else if (!session) {
+ var debuginfos = {
+ address: data.headers['x-forwarded-for'],
+ ua: data.headers['user-agent'],
+ cookie: data.headers.cookie
+ };
+ console.log(debuginfos);
+ return accept('session not found', false);
+ }
+ data.session = session;
+ accept(null, true);
+ });
});
io.sockets.on('connection', function(socket) {
- var session = socket.handshake.session;
- socket.on('disconnect', function() {
- if (socket.roomname) {
- rooms[socket.roomname].removeUser(socket.nickname);
- }
- });
- socket.on('getoverview', function(callback) {
- if (typeof callback !== 'function') {
- return;
- }
- var data = Object.create(null);
- for (var prop in rooms) {
- data[prop] = rooms[prop].getPopulation();
- }
- callback(data);
- });
- socket.on('getstatus', function(callback) {
- if (socket.roomname && typeof callback === 'function') {
- rooms[socket.roomname].sendStatus(callback);
- }
- });
- socket.on('guess', function(guess) {
- if (socket.roomname && typeof guess === 'string') {
- rooms[socket.roomname].guess(socket, guess);
- }
- });
- socket.on('ignore', function(who, callback) {
- if (socket.roomname && typeof who === 'string' && typeof callback === 'function') {
- rooms[socket.roomname].ignore(who, socket.nickname, callback);
- }
- });
- socket.on('joinanonymously', function(nickname, roomname) {
- if (!socket.nickname && typeof nickname === 'string' && ~config.rooms.indexOf(roomname)) {
- rooms[roomname].setNickName(socket, nickname);
- }
- });
- socket.on('joinroom', function(room) {
- if (session.user && ~config.rooms.indexOf(room)) {
- if (sockets[session.user]) { // User already in a room
- socket.emit('alreadyinaroom');
- return;
- }
- socket.nickname = session.user;
- rooms[room].joinRoom(socket);
- }
- });
- socket.on('kick', function(who, why, callback) {
- if (socket.roomname && typeof who === 'string' && typeof why === 'string' &&
- typeof callback === 'function') {
- rooms[socket.roomname].kick(who, why, socket.nickname, callback);
- }
- });
- socket.on('loggedin', function(callback) {
- if (typeof callback !== 'function') {
- return;
- }
- return (session.user) ? callback(session.user) : callback(false);
- });
- socket.on('sendchatmsg', function(msg, to) {
- if (socket.roomname && typeof msg === 'string') {
- rooms[socket.roomname].sendChatMessage(msg, socket, to);
- }
- });
- socket.on('unignore', function(who) {
- if (socket.roomname && typeof who === 'string') {
- rooms[socket.roomname].unignore(who, socket.nickname);
- }
- });
+ var session = socket.handshake.session;
+ socket.on('disconnect', function() {
+ if (socket.roomname) {
+ rooms[socket.roomname].removeUser(socket.nickname);
+ }
+ });
+ socket.on('getoverview', function(callback) {
+ if (typeof callback !== 'function') {
+ return;
+ }
+ var data = Object.create(null);
+ for (var prop in rooms) {
+ data[prop] = rooms[prop].getPopulation();
+ }
+ callback(data);
+ });
+ socket.on('getstatus', function(callback) {
+ if (socket.roomname && typeof callback === 'function') {
+ rooms[socket.roomname].sendStatus(callback);
+ }
+ });
+ socket.on('guess', function(guess) {
+ if (socket.roomname && typeof guess === 'string') {
+ rooms[socket.roomname].guess(socket, guess);
+ }
+ });
+ socket.on('ignore', function(who, callback) {
+ if (socket.roomname && typeof who === 'string' && typeof callback === 'function') {
+ rooms[socket.roomname].ignore(who, socket.nickname, callback);
+ }
+ });
+ socket.on('joinanonymously', function(nickname, roomname) {
+ if (!socket.nickname && typeof nickname === 'string' && ~config.rooms.indexOf(roomname)) {
+ rooms[roomname].setNickName(socket, nickname);
+ }
+ });
+ socket.on('joinroom', function(room) {
+ if (session.user && ~config.rooms.indexOf(room)) {
+ if (sockets[session.user]) { // User already in a room
+ socket.emit('alreadyinaroom');
+ return;
+ }
+ socket.nickname = session.user;
+ rooms[room].joinRoom(socket);
+ }
+ });
+ socket.on('kick', function(who, why, callback) {
+ if (socket.roomname && typeof who === 'string' && typeof why === 'string' &&
+ typeof callback === 'function') {
+ rooms[socket.roomname].kick(who, why, socket.nickname, callback);
+ }
+ });
+ socket.on('loggedin', function(callback) {
+ if (typeof callback !== 'function') {
+ return;
+ }
+ return (session.user) ? callback(session.user) : callback(false);
+ });
+ socket.on('sendchatmsg', function(msg, to) {
+ if (socket.roomname && typeof msg === 'string') {
+ rooms[socket.roomname].sendChatMessage(msg, socket, to);
+ }
+ });
+ socket.on('unignore', function(who) {
+ if (socket.roomname && typeof who === 'string') {
+ rooms[socket.roomname].unignore(who, socket.nickname);
+ }
+ });
});
/**
*/
var Room = require('./lib/room')({io: io, sockets: sockets})
- , rooms = Object.create(null); // The Object that contains all the room instances
+ , rooms = Object.create(null); // The Object that contains all the room instances
for (var i=0; i<config.rooms.length; i++) {
- rooms[config.rooms[i]] = new Room(config.rooms[i]);
- rooms[config.rooms[i]].start();
+ rooms[config.rooms[i]] = new Room(config.rooms[i]);
+ rooms[config.rooms[i]].start();
}
// Begin accepting connections
server.listen(config.port, function() {
- console.log('binb server listening on port ' + config.port);
+ console.log('binb server listening on port ' + config.port);
});
*/
var canvas = require('canvas')
- , characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+ , characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
/**
* Expose the constructor.
*/
module.exports = function() {
- var code = ''
- , _canvas = new canvas(64, 26)
- , ctx = _canvas.getContext('2d');
+ var code = ''
+ , _canvas = new canvas(64, 26)
+ , ctx = _canvas.getContext('2d');
- while (code.length < 4) {
- code += characters[Math.floor(Math.random() * characters.length)];
- }
+ while (code.length < 4) {
+ code += characters[Math.floor(Math.random() * characters.length)];
+ }
- ctx.fillStyle = '#DDDDDD';
- ctx.fillRect(0, 0, 64, 26);
- ctx.font = 'bold 20px Helvetica';
- ctx.lineWidth = 1;
- ctx.textAlign = "center";
- ctx.strokeStyle = '#080';
- ctx.strokeText(code, 31, 20);
- ctx.save();
+ ctx.fillStyle = '#DDDDDD';
+ ctx.fillRect(0, 0, 64, 26);
+ ctx.font = 'bold 20px Helvetica';
+ ctx.lineWidth = 1;
+ ctx.textAlign = "center";
+ ctx.strokeStyle = '#080';
+ ctx.strokeText(code, 31, 20);
+ ctx.save();
- this.getCode = function() {
- return code;
- };
+ this.getCode = function() {
+ return code;
+ };
- this.toDataURL = function() {
- return _canvas.toDataURL();
- };
+ this.toDataURL = function() {
+ return _canvas.toDataURL();
+ };
};
*/
var fs = require('fs')
- , jade = require('jade')
- , nodemailer = require('nodemailer')
- , jadetemplate = fs.readFileSync(__dirname + '/template.jade')
- , texttemplate = fs.readFileSync(__dirname + '/template.txt', 'utf-8');
+ , jade = require('jade')
+ , nodemailer = require('nodemailer')
+ , jadetemplate = fs.readFileSync(__dirname + '/template.jade')
+ , texttemplate = fs.readFileSync(__dirname + '/template.txt', 'utf-8');
/**
* Generate the HTML version of the message.
*/
var plaintextMessage = function(token) {
- return texttemplate.replace(/<token>/, token);
+ return texttemplate.replace(/<token>/, token);
};
/**
*/
var transport = nodemailer.createTransport('SMTP', {
- service: 'SendGrid',
- auth: {
- user: process.env.SENDGRID_USER,
- pass: process.env.SENDGRID_PASS
- }
+ service: 'SendGrid',
+ auth: {
+ user: process.env.SENDGRID_USER,
+ pass: process.env.SENDGRID_PASS
+ }
});
/**
*/
exports.sendEmail = function(to, token, callback) {
- transport.sendMail({
- from: 'binb <no-reply@binb.nodejitsu.com>',
- to: to,
- subject: 'binb password recovery',
- html: HTMLMessage({token:token}),
- text: plaintextMessage(token)
- }, function(err, response) {
- if(err) {
- return callback(err);
- }
- callback(null, response);
- });
+ transport.sendMail({
+ from: 'binb <no-reply@binb.nodejitsu.com>',
+ to: to,
+ subject: 'binb password recovery',
+ html: HTMLMessage({token:token}),
+ text: plaintextMessage(token)
+ }, function(err, response) {
+ if(err) {
+ return callback(err);
+ }
+ callback(null, response);
+ });
};
doctype html
html
- head
- meta(charset="UTF-8")
- title binb password recovery
- body(style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;")
- div(style="width:600px;margin:0 auto;border:3px solid #CCC;border-radius:5px;background-color:#F0F0F0;")
- div(style="padding:16px 16px 0;font-size:15px;color:#505050;")
- img(alt="logo",src="https://dl.dropbox.com/u/58444696/binb-logo.png")
- h2 Password recovery
- p To initiate the password reset process for your binb account,
- | click the link below:
- a(style="color:#0088CC;text-decoration:none;",
- href="http://binb.nodejitsu.com/resetpasswd?token=#{token}")
- | http://bind.nodejitsu.com/resetpasswd?token=#{token}
- p If you can't click it, please copy and paste the URL in a new tab/window.
- p If you haven't requested a password reset, you can disregard this message,
- | because it's likely that another user entered your email address
- | by mistake while trying to reset a password.
- p.note(style="font-size:13px;")
- b Note:
- | This email cannot accept replies.
+ head
+ meta(charset="UTF-8")
+ title binb password recovery
+ body(style="font-family:'Helvetica Neue',Helvetica,Arial,sans-serif;")
+ div(style="width:600px;margin:0 auto;border:3px solid #CCC;border-radius:5px;background-color:#F0F0F0;")
+ div(style="padding:16px 16px 0;font-size:15px;color:#505050;")
+ img(alt="logo",src="https://dl.dropbox.com/u/58444696/binb-logo.png")
+ h2 Password recovery
+ p To initiate the password reset process for your binb account,
+ | click the link below:
+ a(style="color:#0088CC;text-decoration:none;",
+ href="http://binb.nodejitsu.com/resetpasswd?token=#{token}")
+ | http://bind.nodejitsu.com/resetpasswd?token=#{token}
+ p If you can't click it, please copy and paste the URL in a new tab/window.
+ p If you haven't requested a password reset, you can disregard this message,
+ | because it's likely that another user entered your email address
+ | by mistake while trying to reset a password.
+ p.note(style="font-size:13px;")
+ b Note:
+ | This email cannot accept replies.
*/
var checkDistance = function(s1, s2, k) {
- if (k === 0) {
- return s1 === s2;
- }
- if (Math.abs(s1.length - s2.length) > k) {
- return false;
- }
- var d = [];
- for (var i=0; i <= s1.length; i++) {
- d[i] = []; // Now d is a matrix with s1.length + 1 rows
- d[i][0] = i;
- }
- for (var j=1; j <= s2.length; j++) {
- d[0][j] = j;
- }
- for (i=1; i <= s1.length; i++) {
- var l = ((i-k) < 1) ? 1 : i-k;
- var 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];
- }
- else {
- if ((j === l) && (d[i][j-1] === undefined)) {
- d[i][j] = Math.min(d[i-1][j-1]+1, d[i-1][j]+1);
- }
- else if ((j === m) && (d[i-1][j] === undefined)) {
- d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1);
- }
- else {
- d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1, d[i-1][j]+1);
- }
- }
+ if (k === 0) {
+ return s1 === s2;
+ }
+ if (Math.abs(s1.length - s2.length) > k) {
+ return false;
+ }
+ var d = [];
+ for (var i=0; i <= s1.length; i++) {
+ d[i] = []; // Now d is a matrix with s1.length + 1 rows
+ d[i][0] = i;
+ }
+ for (var j=1; j <= s2.length; j++) {
+ d[0][j] = j;
+ }
+ for (i=1; i <= s1.length; i++) {
+ var l = ((i-k) < 1) ? 1 : i-k;
+ var 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];
+ }
+ else {
+ if ((j === l) && (d[i][j-1] === undefined)) {
+ d[i][j] = Math.min(d[i-1][j-1]+1, d[i-1][j]+1);
+ }
+ else if ((j === m) && (d[i-1][j] === undefined)) {
+ d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1);
}
+ else {
+ d[i][j] = Math.min(d[i][j-1]+1, d[i-1][j-1]+1, d[i-1][j]+1);
+ }
+ }
}
- return d[s1.length][s2.length] <= k;
+ }
+ return d[s1.length][s2.length] <= k;
};
/**
*/
module.exports = function(subject, guess, enableartistrules) {
- if (checkDistance(subject, guess, threshold)) {
- return true;
- }
+ if (checkDistance(subject, guess, threshold)) {
+ return true;
+ }
- // Ignore dots
- if (/\./.test(subject) &&
- checkDistance(subject.replace(/\./g, ''), guess, threshold)) {
- return true;
- }
- // Ignore dashes
- if (/\-/.test(subject) &&
- checkDistance(subject.replace(/\-/g, ''), guess, threshold)) {
- return true;
- }
- // Allow to write "and" in place of "+"
- if (/\+/.test(subject) &&
- checkDistance(subject.replace(/\+/, 'and'), guess, threshold)) {
+ // Ignore dots
+ if (/\./.test(subject) &&
+ checkDistance(subject.replace(/\./g, ''), guess, threshold)) {
+ return true;
+ }
+ // Ignore dashes
+ if (/\-/.test(subject) &&
+ checkDistance(subject.replace(/\-/g, ''), guess, threshold)) {
+ return true;
+ }
+ // Allow to write "and" in place of "+"
+ if (/\+/.test(subject) &&
+ checkDistance(subject.replace(/\+/, 'and'), guess, threshold)) {
+ return true;
+ }
+ // Allow to write "and" in place of " & "
+ if (/ & /.test(subject) && !/\(/.test(subject) &&
+ checkDistance(subject.replace(/ & /, ' and '), guess, threshold)) {
+ return true;
+ }
+
+ if (enableartistrules) {
+ // Ignore "the" at the beginning of artist name
+ if (/^the /.test(subject)) {
+ var nothe = subject.replace(/^the /, '');
+ if (checkDistance(nothe, guess, threshold)) {
return true;
- }
- // Allow to write "and" in place of " & "
- if (/ & /.test(subject) && !/\(/.test(subject) &&
- checkDistance(subject.replace(/ & /, ' and '), guess, threshold)) {
+ }
+ if (/jimi hendrix experience/.test(nothe) &&
+ checkDistance(nothe.replace(/ experience/, ''), guess, threshold)) {
return true;
+ }
}
-
- if (enableartistrules) {
- // Ignore "the" at the beginning of artist name
- if (/^the /.test(subject)) {
- var nothe = subject.replace(/^the /, '');
- if (checkDistance(nothe, guess, threshold)) {
- return true;
- }
- if (/jimi hendrix experience/.test(nothe) &&
- checkDistance(nothe.replace(/ experience/, ''), guess, threshold)) {
- return true;
- }
+ // Split artist name on " & " and ", " (artist name can be composed by more names)
+ var splitted = subject.split(/ & |, /);
+ if (splitted.length !== 1) {
+ for (var i=0; i<splitted.length; i++) {
+ if (checkDistance(splitted[i], guess, threshold)) {
+ return true;
}
- // Split artist name on " & " and ", " (artist name can be composed by more names)
- var splitted = subject.split(/ & |, /);
- if (splitted.length !== 1) {
- for (var i=0; i<splitted.length; i++) {
- if (checkDistance(splitted[i], guess, threshold)) {
- return true;
- }
- if (/^the /.test(splitted[i]) &&
- checkDistance(splitted[i].replace(/^the /, ''), guess, threshold)) {
- return true;
- }
- }
+ if (/^the /.test(splitted[i]) &&
+ checkDistance(splitted[i].replace(/^the /, ''), guess, threshold)) {
+ return true;
}
+ }
}
- else {
- // Ignore commas
- if (/,/.test(subject) &&
- checkDistance(subject.replace(/,/g, ''), guess, threshold)) {
- return true;
- }
- // Ignore additional info e.g. "(Love Theme from Titanic)"
- if (/\(.+\)\??(?: \[.+\])?/.test(subject)) {
- var normalized = subject.replace(/\(.+\)\??(?: \[.+\])?/, '').trim();
- if (checkDistance(normalized, guess, threshold)) {
- return true;
- }
- if (/ & /.test(normalized) &&
- checkDistance(normalized.replace(/ & /, ' and '), guess, threshold)) {
- return true;
- }
- }
- if (/, [pP]t\. [0-9]$/.test(subject) &&
- checkDistance(subject.replace(/, [pP]t\. [0-9]$/, ''), guess, threshold)) {
- return true;
- }
+ }
+ else {
+ // Ignore commas
+ if (/,/.test(subject) &&
+ checkDistance(subject.replace(/,/g, ''), guess, threshold)) {
+ return true;
+ }
+ // Ignore additional info e.g. "(Love Theme from Titanic)"
+ if (/\(.+\)\??(?: \[.+\])?/.test(subject)) {
+ var normalized = subject.replace(/\(.+\)\??(?: \[.+\])?/, '').trim();
+ if (checkDistance(normalized, guess, threshold)) {
+ return true;
+ }
+ if (/ & /.test(normalized) &&
+ checkDistance(normalized.replace(/ & /, ' and '), guess, threshold)) {
+ return true;
+ }
+ }
+ if (/, [pP]t\. [0-9]$/.test(subject) &&
+ checkDistance(subject.replace(/, [pP]t\. [0-9]$/, ''), guess, threshold)) {
+ return true;
}
+ }
- return false;
+ return false;
};
*/
var songsclient = redis.createClient(process.env.SONGS_DB_PORT, process.env.SONGS_DB_HOST)
- , usersclient = redis.createClient(process.env.USERS_DB_PORT, process.env.USERS_DB_HOST);
+ , usersclient = redis.createClient(process.env.USERS_DB_PORT, process.env.USERS_DB_HOST);
if (process.env.NODE_ENV === 'production') {
- songsclient.auth(process.env.SONGS_DB_AUTH);
- usersclient.auth(process.env.USERS_DB_AUTH);
+ songsclient.auth(process.env.SONGS_DB_AUTH);
+ usersclient.auth(process.env.USERS_DB_AUTH);
}
songsclient.on('error', function(err) {
- console.log(err.message);
+ console.log(err.message);
});
usersclient.on('error', function(err) {
- console.log(err.message);
+ console.log(err.message);
});
/**
*/
var amatch = require('./match')
- , clients = require('./redis-clients')
- , collectStats = require('./stats')
- , config = require('../config')
- , fifolength = config.songsinarun * config.gameswithnorepeats
- , io
- , isUsername = require('./utils').isUsername
- , sockets
- , songsdb = clients.songs
- , usersdb = clients.users;
+ , clients = require('./redis-clients')
+ , collectStats = require('./stats')
+ , config = require('../config')
+ , fifolength = config.songsinarun * config.gameswithnorepeats
+ , io
+ , isUsername = require('./utils').isUsername
+ , sockets
+ , songsdb = clients.songs
+ , usersdb = clients.users;
/**
* Expose the constructor.
*/
module.exports = function(options) {
- io = options.io;
- sockets = options.sockets;
- return Room;
+ io = options.io;
+ sockets = options.sockets;
+ return Room;
};
/**
function Room(roomname) {
- var allowedguess = false
- , artist // Artists in lowercase
- , artistName
- , artworkUrl
- , feat // Featured artists
- , finishline = 1
- , playedtracks = [] // The list of already played songs
- , previewUrl
- , songcounter = 0
- , songtimeleft // Milliseconds
- , status
- , title // Title in lowercase
- , trackName
- , trackscount = 0
- , trackViewUrl
- , totusers = 0
- , usersData = Object.create(null);
-
- // User points and statistics
- var addPointsAndStats = function(nickname, allinone) {
- usersData[nickname].guesstime = 30000 - songtimeleft;
- var stats = {};
- switch (finishline) {
- case 1:
- finishline++;
- usersData[nickname].roundpoints = 6;
- if (allinone) {
- usersData[nickname].points += 6;
- stats.points = 6;
- }
- else {
- usersData[nickname].points += 5;
- stats.points = 5;
- }
- usersData[nickname].golds++;
- stats.gold = true;
- break;
- case 2:
- finishline++;
- usersData[nickname].roundpoints = 5;
- if (allinone) {
- usersData[nickname].points += 5;
- stats.points = 5;
- }
- else {
- usersData[nickname].points += 4;
- stats.points = 4;
- }
- usersData[nickname].silvers++;
- stats.silver = true;
- break;
- case 3:
- finishline++;
- usersData[nickname].roundpoints = 4;
- if (allinone) {
- usersData[nickname].points += 4;
- stats.points = 4;
- }
- else {
- usersData[nickname].points += 3;
- stats.points = 3;
- }
- usersData[nickname].bronzes++;
- stats.bronze = true;
- break;
- default:
- usersData[nickname].roundpoints = 3;
- if (allinone) {
- usersData[nickname].points += 3;
- stats.points = 3;
- }
- else {
- usersData[nickname].points += 2;
- stats.points = 2;
- }
+ var allowedguess = false
+ , artist // Artists in lowercase
+ , artistName
+ , artworkUrl
+ , feat // Featured artists
+ , finishline = 1
+ , playedtracks = [] // The list of already played songs
+ , previewUrl
+ , songcounter = 0
+ , songtimeleft // Milliseconds
+ , status
+ , title // Title in lowercase
+ , trackName
+ , trackscount = 0
+ , trackViewUrl
+ , totusers = 0
+ , usersData = Object.create(null);
+
+ // User points and statistics
+ var addPointsAndStats = function(nickname, allinone) {
+ usersData[nickname].guesstime = 30000 - songtimeleft;
+ var stats = {};
+ switch (finishline) {
+ case 1:
+ finishline++;
+ usersData[nickname].roundpoints = 6;
+ if (allinone) {
+ usersData[nickname].points += 6;
+ stats.points = 6;
}
- usersData[nickname].matched = 'both';
- usersData[nickname].guessed++;
- usersData[nickname].totguesstime += usersData[nickname].guesstime;
-
- if (usersData[nickname].registered) {
- stats.userscore = usersData[nickname].points;
- stats.guesstime = usersData[nickname].guesstime;
- collectStats(nickname, stats);
- }
- };
-
- // Add a new user in the room
- var addUser = function(socket, loggedin) {
- sockets[socket.nickname] = socket;
- usersData[socket.nickname] = {
- nickname: socket.nickname,
- registered: loggedin,
- points: 0,
- roundpoints: 0,
- matched: null,
- guessed: 0,
- guesstime: null,
- totguesstime: 0,
- golds: 0,
- silvers: 0,
- bronzes: 0
- };
- totusers++;
- // Broadcast new user event
- io.sockets.emit('updateoverview', roomname, totusers);
- socket.emit('ready', usersData, trackscount, loggedin);
- socket.broadcast.to(roomname).emit('newuser', socket.nickname, usersData);
- };
-
- var gameOver = function() {
- status = 3; // Game over
-
- // Build podium
- var users = [];
- for (var key in usersData) {
- users.push(usersData[key]);
- }
- users.sort(function(a, b) {return b.points - a.points;});
- var podium = users.slice(0,3);
- io.sockets.in(roomname).emit('gameover', podium);
-
- // Collect podium stats
- if (podium[0] && podium[0].registered) {
- collectStats(podium[0].nickname, {firstplace:true});
+ else {
+ usersData[nickname].points += 5;
+ stats.points = 5;
}
- if (podium[1] && podium[1].registered) {
- collectStats(podium[1].nickname, {secondplace:true});
+ usersData[nickname].golds++;
+ stats.gold = true;
+ break;
+ case 2:
+ finishline++;
+ usersData[nickname].roundpoints = 5;
+ if (allinone) {
+ usersData[nickname].points += 5;
+ stats.points = 5;
}
- if (podium[2] && podium[2].registered) {
- collectStats(podium[2].nickname, {thirdplace:true});
+ else {
+ usersData[nickname].points += 4;
+ stats.points = 4;
}
-
- resetPoints(false);
- songcounter = 0;
- // Check if FIFO is full
- if (playedtracks.length === fifolength) {
- playedtracks.splice(0, config.songsinarun);
- }
-
- // Start a new game
- setTimeout(sendLoadTrack, 5000);
- };
-
- // Return the number of users in the room
- this.getPopulation = function() {
- return totusers;
- };
-
- // A user is sending a guess
- this.guess = function(socket, guess) {
- if (allowedguess) {
- if (!usersData[socket.nickname].matched) { // No track no artist
- if ((artist === title) && amatch(title, guess, true)) {
- addPointsAndStats(socket.nickname, true);
- socket.emit('bothmatched');
- io.sockets.in(roomname).emit('updateusers', usersData);
- }
- else if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
- usersData[socket.nickname].roundpoints++;
- usersData[socket.nickname].points++;
- usersData[socket.nickname].matched = 'artist';
- socket.emit('artistmatched');
- io.sockets.in(roomname).emit('updateusers', usersData);
- if (usersData[socket.nickname].registered) {
- var stats = {points:1,userscore:usersData[socket.nickname].points};
- collectStats(socket.nickname, stats);
- }
- }
- else if (amatch(title, guess)) {
- usersData[socket.nickname].roundpoints++;
- usersData[socket.nickname].points++;
- usersData[socket.nickname].matched = 'title';
- socket.emit('titlematched');
- io.sockets.in(roomname).emit('updateusers', usersData);
- if (usersData[socket.nickname].registered) {
- var stats = {points:1,userscore:usersData[socket.nickname].points};
- collectStats(socket.nickname, stats);
- }
- }
- else {
- socket.emit('nomatch');
- }
- }
- else if (usersData[socket.nickname].matched !== 'both') { // Track or artist
- if (usersData[socket.nickname].matched === 'artist') {
- if (amatch(title, guess)) {
- addPointsAndStats(socket.nickname, false);
- socket.emit('bothmatched');
- io.sockets.in(roomname).emit('updateusers', usersData);
- }
- else {
- socket.emit('nomatch');
- }
- }
- else {
- if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
- addPointsAndStats(socket.nickname, false);
- socket.emit('bothmatched');
- io.sockets.in(roomname).emit('updateusers', usersData);
- }
- else {
- socket.emit('nomatch');
- }
- }
- }
- else { // The user has guessed both track and artist
- socket.emit('stoptrying');
- }
+ usersData[nickname].silvers++;
+ stats.silver = true;
+ break;
+ case 3:
+ finishline++;
+ usersData[nickname].roundpoints = 4;
+ if (allinone) {
+ usersData[nickname].points += 4;
+ stats.points = 4;
}
else {
- socket.emit('noguesstime');
+ usersData[nickname].points += 3;
+ stats.points = 3;
}
- };
-
- this.ignore = function(who, executor, callback) {
- // Check if the player to be ignored is in the room
- if (usersData[who]) {
- // Inform the bad player that he/she is being ignored
- var recipient = sockets[who];
- recipient.emit('chatmsg', executor+' is ignoring you.', 'binb', who);
- return callback(who);
+ usersData[nickname].bronzes++;
+ stats.bronze = true;
+ break;
+ default:
+ usersData[nickname].roundpoints = 3;
+ if (allinone) {
+ usersData[nickname].points += 3;
+ stats.points = 3;
}
- callback(false);
- };
-
- this.joinRoom = function(socket) {
- socket.roomname = roomname;
- socket.join(roomname);
- addUser(socket, true);
- };
-
- // Kick a user
- this.kick = function(who, why, executor, callback) {
- usersdb.hget('user:'+executor, 'role', function (err, role) {
- if (role > 0) { // Check role
- if (usersData[who]) {
- if (why) {
- why = ' ('+why+')';
- }
- var notice = 'you have been kicked by '+executor+why+'.';
- var recipient = sockets[who];
- recipient.emit('chatmsg', notice, 'binb', who);
- recipient.disconnect();
- }
- return;
- }
- callback();
- });
- };
-
- // A user has left (DCed, etc.)
- this.removeUser = function(nickname) {
- // Delete the references
- delete sockets[nickname];
- delete usersData[nickname];
- totusers--;
- // Broadcast the event
- io.sockets.emit('updateoverview', roomname, totusers);
- io.sockets.in(roomname).emit('userleft', nickname, usersData);
- };
-
- var resetPoints = function(roundonly) {
- for (var key in usersData) {
- if (!roundonly) {
- usersData[key].points = 0;
- usersData[key].guessed = 0;
- usersData[key].totguesstime = 0;
- usersData[key].golds = 0;
- usersData[key].silvers = 0;
- usersData[key].bronzes = 0;
- }
- usersData[key].roundpoints = 0;
- usersData[key].matched = null;
- usersData[key].guesstime = null;
+ else {
+ usersData[nickname].points += 2;
+ stats.points = 2;
}
+ }
+ usersData[nickname].matched = 'both';
+ usersData[nickname].guessed++;
+ usersData[nickname].totguesstime += usersData[nickname].guesstime;
+
+ if (usersData[nickname].registered) {
+ stats.userscore = usersData[nickname].points;
+ stats.guesstime = usersData[nickname].guesstime;
+ collectStats(nickname, stats);
+ }
+ };
+
+ // Add a new user in the room
+ var addUser = function(socket, loggedin) {
+ sockets[socket.nickname] = socket;
+ usersData[socket.nickname] = {
+ nickname: socket.nickname,
+ registered: loggedin,
+ points: 0,
+ roundpoints: 0,
+ matched: null,
+ guessed: 0,
+ guesstime: null,
+ totguesstime: 0,
+ golds: 0,
+ silvers: 0,
+ bronzes: 0
};
-
- // A user is sending a chat message
- this.sendChatMessage = function(msg, socket, to) {
- if (typeof to === 'string') {
- // Check if the recipient is in the room
- if (usersData[to]) {
- socket.emit('chatmsg', msg, socket.nickname, to);
- var recipient = sockets[to];
- recipient.emit('chatmsg', msg, socket.nickname, to);
- }
- return;
+ totusers++;
+ // Broadcast new user event
+ io.sockets.emit('updateoverview', roomname, totusers);
+ socket.emit('ready', usersData, trackscount, loggedin);
+ socket.broadcast.to(roomname).emit('newuser', socket.nickname, usersData);
+ };
+
+ var gameOver = function() {
+ status = 3; // Game over
+
+ // Build podium
+ var users = [];
+ for (var key in usersData) {
+ users.push(usersData[key]);
+ }
+ users.sort(function(a, b) {return b.points - a.points;});
+ var podium = users.slice(0,3);
+ io.sockets.in(roomname).emit('gameover', podium);
+
+ // Collect podium stats
+ if (podium[0] && podium[0].registered) {
+ collectStats(podium[0].nickname, {firstplace:true});
+ }
+ if (podium[1] && podium[1].registered) {
+ collectStats(podium[1].nickname, {secondplace:true});
+ }
+ if (podium[2] && podium[2].registered) {
+ collectStats(podium[2].nickname, {thirdplace:true});
+ }
+
+ resetPoints(false);
+ songcounter = 0;
+ // Check if FIFO is full
+ if (playedtracks.length === fifolength) {
+ playedtracks.splice(0, config.songsinarun);
+ }
+
+ // Start a new game
+ setTimeout(sendLoadTrack, 5000);
+ };
+
+ // Return the number of users in the room
+ this.getPopulation = function() {
+ return totusers;
+ };
+
+ // A user is sending a guess
+ this.guess = function(socket, guess) {
+ if (allowedguess) {
+ if (!usersData[socket.nickname].matched) { // No track no artist
+ if ((artist === title) && amatch(title, guess, true)) {
+ addPointsAndStats(socket.nickname, true);
+ socket.emit('bothmatched');
+ io.sockets.in(roomname).emit('updateusers', usersData);
}
- // Censor answers from chat
- var msglcase = msg.toLowerCase();
- if (allowedguess && (amatch(artist, msglcase, true) ||
- (feat && amatch(feat, msglcase, true)) || amatch(title, msglcase))) {
- var notice = 'You are probably right, but you have to use the box above.';
- socket.emit('chatmsg', notice, 'binb', socket.nickname);
- return;
+ else if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
+ usersData[socket.nickname].roundpoints++;
+ usersData[socket.nickname].points++;
+ usersData[socket.nickname].matched = 'artist';
+ socket.emit('artistmatched');
+ io.sockets.in(roomname).emit('updateusers', usersData);
+ if (usersData[socket.nickname].registered) {
+ var stats = {points:1,userscore:usersData[socket.nickname].points};
+ collectStats(socket.nickname, stats);
+ }
}
- io.sockets.in(roomname).emit('chatmsg', msg, socket.nickname);
- };
-
- // Extract a random track from the database and send the load event
- var sendLoadTrack = function() {
- songsdb.srandmember(roomname, function(err, res) {
- // Check if extracted track is in the list of already played tracks
- if (~playedtracks.indexOf(res)) {
- return sendLoadTrack();
- }
- playedtracks.push(res);
- var args = [
- 'song:'+res
- , 'artistName'
- , 'trackName'
- , 'previewUrl'
- , 'artworkUrl60'
- , 'trackViewUrl'
- ];
- songsdb.hmget(args, function(e, replies) {
- artistName = replies[0];
- artist = artistName.toLowerCase();
- trackName = replies[1];
- title = trackName.toLowerCase();
- feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null;
- previewUrl = replies[2];
- artworkUrl = replies[3];
- trackViewUrl = replies[4];
- io.sockets.in(roomname).emit('loadtrack', previewUrl);
- setTimeout(sendPlayTrack, 5000);
- });
- });
- status = 1; // Loading next song
- };
-
- var sendPlayTrack = function() {
- songcounter++;
- status = 0; // Playing track
- var data = {
- counter: songcounter,
- tot: config.songsinarun,
- users: usersData
- };
- io.sockets.in(roomname).emit('playtrack', data);
- songTimeLeft(Date.now() + 30000, 50);
- allowedguess = true;
- setTimeout(sendTrackInfo, 30000);
- };
-
- // Send the room status
- this.sendStatus = function(callback) {
- var data = {
- status: status,
- timeleft: songtimeleft,
- previewUrl: previewUrl
- };
- callback(data);
- };
-
- var sendTrackInfo = function() {
- var trackinfo = {
- artworkUrl: artworkUrl,
- artistName: artistName,
- trackName: trackName,
- trackViewUrl: trackViewUrl,
- };
- io.sockets.in(roomname).emit('trackinfo', trackinfo);
- finishline = 1;
- allowedguess = false;
-
- if (songcounter < config.songsinarun) {
- resetPoints(true);
- sendLoadTrack();
- return;
+ else if (amatch(title, guess)) {
+ usersData[socket.nickname].roundpoints++;
+ usersData[socket.nickname].points++;
+ usersData[socket.nickname].matched = 'title';
+ socket.emit('titlematched');
+ io.sockets.in(roomname).emit('updateusers', usersData);
+ if (usersData[socket.nickname].registered) {
+ var stats = {points:1,userscore:usersData[socket.nickname].points};
+ collectStats(socket.nickname, stats);
+ }
}
-
- status = 2; // Sending last track info
- setTimeout(gameOver, 5000);
- };
-
- // A user is submitting a name
- this.setNickName = function(socket, nickname) {
- var feedback = null;
-
- if (nickname === 'binb') {
- feedback = '<span class="label label-important">That name is reserved.</span>';
- }
- else if (!isUsername(nickname)) {
- feedback = '<span class="label label-important">Name must contain only ';
- feedback += 'alphanumeric characters.</span>';
+ else {
+ socket.emit('nomatch');
}
- else if (sockets[nickname]) {
- feedback = '<span class="label label-important">Name already taken.</span>';
+ }
+ else if (usersData[socket.nickname].matched !== 'both') { // Track or artist
+ if (usersData[socket.nickname].matched === 'artist') {
+ if (amatch(title, guess)) {
+ addPointsAndStats(socket.nickname, false);
+ socket.emit('bothmatched');
+ io.sockets.in(roomname).emit('updateusers', usersData);
+ }
+ else {
+ socket.emit('nomatch');
+ }
}
-
- if (feedback) {
- return socket.emit('invalidnickname', feedback);
+ else {
+ if (amatch(artist, guess, true) || (feat && amatch(feat, guess, true))) {
+ addPointsAndStats(socket.nickname, false);
+ socket.emit('bothmatched');
+ io.sockets.in(roomname).emit('updateusers', usersData);
+ }
+ else {
+ socket.emit('nomatch');
+ }
}
-
- // Check if requested nickname belong to a registered user
- var key = 'user:'+nickname;
- usersdb.exists(key, function(err, resp) {
- if (resp === 1) {
- feedback = '<span class="label label-important">That name belongs ';
- feedback += 'to a registered user.</span>';
- return socket.emit('invalidnickname', feedback);
- }
- socket.nickname = nickname;
- socket.roomname = roomname;
- socket.join(roomname);
- addUser(socket, false);
- });
- };
-
- // Timer for the playing song
- var songTimeLeft = function(end, delay) {
- songtimeleft = end - Date.now();
- if (songtimeleft < delay) {
- return;
+ }
+ else { // The user has guessed both track and artist
+ socket.emit('stoptrying');
+ }
+ }
+ else {
+ socket.emit('noguesstime');
+ }
+ };
+
+ this.ignore = function(who, executor, callback) {
+ // Check if the player to be ignored is in the room
+ if (usersData[who]) {
+ // Inform the bad player that he/she is being ignored
+ var recipient = sockets[who];
+ recipient.emit('chatmsg', executor+' is ignoring you.', 'binb', who);
+ return callback(who);
+ }
+ callback(false);
+ };
+
+ this.joinRoom = function(socket) {
+ socket.roomname = roomname;
+ socket.join(roomname);
+ addUser(socket, true);
+ };
+
+ // Kick a user
+ this.kick = function(who, why, executor, callback) {
+ usersdb.hget('user:'+executor, 'role', function (err, role) {
+ if (role > 0) { // Check role
+ if (usersData[who]) {
+ if (why) {
+ why = ' ('+why+')';
+ }
+ var notice = 'you have been kicked by '+executor+why+'.';
+ var recipient = sockets[who];
+ recipient.emit('chatmsg', notice, 'binb', who);
+ recipient.disconnect();
}
- setTimeout(songTimeLeft, delay, end, delay);
+ return;
+ }
+ callback();
+ });
+ };
+
+ // A user has left (DCed, etc.)
+ this.removeUser = function(nickname) {
+ // Delete the references
+ delete sockets[nickname];
+ delete usersData[nickname];
+ totusers--;
+ // Broadcast the event
+ io.sockets.emit('updateoverview', roomname, totusers);
+ io.sockets.in(roomname).emit('userleft', nickname, usersData);
+ };
+
+ var resetPoints = function(roundonly) {
+ for (var key in usersData) {
+ if (!roundonly) {
+ usersData[key].points = 0;
+ usersData[key].guessed = 0;
+ usersData[key].totguesstime = 0;
+ usersData[key].golds = 0;
+ usersData[key].silvers = 0;
+ usersData[key].bronzes = 0;
+ }
+ usersData[key].roundpoints = 0;
+ usersData[key].matched = null;
+ usersData[key].guesstime = null;
+ }
+ };
+
+ // A user is sending a chat message
+ this.sendChatMessage = function(msg, socket, to) {
+ if (typeof to === 'string') {
+ // Check if the recipient is in the room
+ if (usersData[to]) {
+ socket.emit('chatmsg', msg, socket.nickname, to);
+ var recipient = sockets[to];
+ recipient.emit('chatmsg', msg, socket.nickname, to);
+ }
+ return;
+ }
+ // Censor answers from chat
+ var msglcase = msg.toLowerCase();
+ if (allowedguess && (amatch(artist, msglcase, true) ||
+ (feat && amatch(feat, msglcase, true)) || amatch(title, msglcase))) {
+ var notice = 'You are probably right, but you have to use the box above.';
+ socket.emit('chatmsg', notice, 'binb', socket.nickname);
+ return;
+ }
+ io.sockets.in(roomname).emit('chatmsg', msg, socket.nickname);
+ };
+
+ // Extract a random track from the database and send the load event
+ var sendLoadTrack = function() {
+ songsdb.srandmember(roomname, function(err, res) {
+ // Check if extracted track is in the list of already played tracks
+ if (~playedtracks.indexOf(res)) {
+ return sendLoadTrack();
+ }
+ playedtracks.push(res);
+ var args = [
+ 'song:'+res
+ , 'artistName'
+ , 'trackName'
+ , 'previewUrl'
+ , 'artworkUrl60'
+ , 'trackViewUrl'
+ ];
+ songsdb.hmget(args, function(e, replies) {
+ artistName = replies[0];
+ artist = artistName.toLowerCase();
+ trackName = replies[1];
+ title = trackName.toLowerCase();
+ feat = /feat\. (.+?)[)\]]/.test(title) ? RegExp.$1 : null;
+ previewUrl = replies[2];
+ artworkUrl = replies[3];
+ trackViewUrl = replies[4];
+ io.sockets.in(roomname).emit('loadtrack', previewUrl);
+ setTimeout(sendPlayTrack, 5000);
+ });
+ });
+ status = 1; // Loading next song
+ };
+
+ var sendPlayTrack = function() {
+ songcounter++;
+ status = 0; // Playing track
+ var data = {
+ counter: songcounter,
+ tot: config.songsinarun,
+ users: usersData
};
-
- // Start the room
- this.start = function() {
- songsdb.scard(roomname, function(err, res) {
- trackscount = res;
- });
- sendLoadTrack();
+ io.sockets.in(roomname).emit('playtrack', data);
+ songTimeLeft(Date.now() + 30000, 50);
+ allowedguess = true;
+ setTimeout(sendTrackInfo, 30000);
+ };
+
+ // Send the room status
+ this.sendStatus = function(callback) {
+ var data = {
+ status: status,
+ timeleft: songtimeleft,
+ previewUrl: previewUrl
};
-
- this.unignore = function(who, executor) {
- if (usersData[who]) {
- // Inform the bad player that he/she is no longer ignored
- var notice = executor+' has stopped ignoring you.';
- var recipient = sockets[who];
- recipient.emit('chatmsg', notice, 'binb', who);
- }
+ callback(data);
+ };
+
+ var sendTrackInfo = function() {
+ var trackinfo = {
+ artworkUrl: artworkUrl,
+ artistName: artistName,
+ trackName: trackName,
+ trackViewUrl: trackViewUrl,
};
+ io.sockets.in(roomname).emit('trackinfo', trackinfo);
+ finishline = 1;
+ allowedguess = false;
+
+ if (songcounter < config.songsinarun) {
+ resetPoints(true);
+ sendLoadTrack();
+ return;
+ }
+
+ status = 2; // Sending last track info
+ setTimeout(gameOver, 5000);
+ };
+
+ // A user is submitting a name
+ this.setNickName = function(socket, nickname) {
+ var feedback = null;
+
+ if (nickname === 'binb') {
+ feedback = '<span class="label label-important">That name is reserved.</span>';
+ }
+ else if (!isUsername(nickname)) {
+ feedback = '<span class="label label-important">Name must contain only ';
+ feedback += 'alphanumeric characters.</span>';
+ }
+ else if (sockets[nickname]) {
+ feedback = '<span class="label label-important">Name already taken.</span>';
+ }
+
+ if (feedback) {
+ return socket.emit('invalidnickname', feedback);
+ }
+
+ // Check if requested nickname belong to a registered user
+ var key = 'user:'+nickname;
+ usersdb.exists(key, function(err, resp) {
+ if (resp === 1) {
+ feedback = '<span class="label label-important">That name belongs ';
+ feedback += 'to a registered user.</span>';
+ return socket.emit('invalidnickname', feedback);
+ }
+ socket.nickname = nickname;
+ socket.roomname = roomname;
+ socket.join(roomname);
+ addUser(socket, false);
+ });
+ };
+
+ // Timer for the playing song
+ var songTimeLeft = function(end, delay) {
+ songtimeleft = end - Date.now();
+ if (songtimeleft < delay) {
+ return;
+ }
+ setTimeout(songTimeLeft, delay, end, delay);
+ };
+
+ // Start the room
+ this.start = function() {
+ songsdb.scard(roomname, function(err, res) {
+ trackscount = res;
+ });
+ sendLoadTrack();
+ };
+
+ this.unignore = function(who, executor) {
+ if (usersData[who]) {
+ // Inform the bad player that he/she is no longer ignored
+ var notice = executor+' has stopped ignoring you.';
+ var recipient = sockets[who];
+ recipient.emit('chatmsg', notice, 'binb', who);
+ }
+ };
}
*/
module.exports = function(username, stats) {
- var key = 'user:'+username;
- if (stats.points) {
- // Update total points
- db.hincrby(key, 'totpoints', stats.points);
- // Update the score of the member in the sorted set
- db.zincrby('users', stats.points, username);
- }
- if (stats.userscore) {
- // Set personal best
- db.hget(key, 'bestscore', function(err, res) {
- if (res < stats.userscore) {
- db.hset(key, 'bestscore', stats.userscore);
- }
- });
- }
- if (stats.gold) {
- // Update the number of golds
- db.hincrby(key, 'golds', 1);
- }
- if (stats.silver) {
- db.hincrby(key, 'silvers', 1);
- }
- if (stats.bronze) {
- db.hincrby(key, 'bronzes', 1);
- }
- if (stats.guesstime) {
- // Update the number of guessed tracks
- db.hincrby(key, 'guessed', 1);
- // Update total guess time
- db.hincrby(key, 'totguesstime', stats.guesstime);
- // Set best answer time
- db.hget(key, 'bestguesstime', function(err, res) {
- if (stats.guesstime < res) {
- db.hset(key, 'bestguesstime', stats.guesstime);
- }
- });
- // Set worst answer time
- db.hget(key, 'worstguesstime', function(err, res) {
- if (stats.guesstime > res) {
- db.hset(key, 'worstguesstime', stats.guesstime);
- }
- });
- }
- if (stats.firstplace) {
- // Update the number of first places
- db.hincrby(key, 'victories', 1);
- }
- if (stats.secondplace) {
- db.hincrby(key, 'secondplaces', 1);
- }
- if (stats.thirdplace) {
- db.hincrby(key, 'thirdplaces', 1);
- }
+ var key = 'user:'+username;
+ if (stats.points) {
+ // Update total points
+ db.hincrby(key, 'totpoints', stats.points);
+ // Update the score of the member in the sorted set
+ db.zincrby('users', stats.points, username);
+ }
+ if (stats.userscore) {
+ // Set personal best
+ db.hget(key, 'bestscore', function(err, res) {
+ if (res < stats.userscore) {
+ db.hset(key, 'bestscore', stats.userscore);
+ }
+ });
+ }
+ if (stats.gold) {
+ // Update the number of golds
+ db.hincrby(key, 'golds', 1);
+ }
+ if (stats.silver) {
+ db.hincrby(key, 'silvers', 1);
+ }
+ if (stats.bronze) {
+ db.hincrby(key, 'bronzes', 1);
+ }
+ if (stats.guesstime) {
+ // Update the number of guessed tracks
+ db.hincrby(key, 'guessed', 1);
+ // Update total guess time
+ db.hincrby(key, 'totguesstime', stats.guesstime);
+ // Set best answer time
+ db.hget(key, 'bestguesstime', function(err, res) {
+ if (stats.guesstime < res) {
+ db.hset(key, 'bestguesstime', stats.guesstime);
+ }
+ });
+ // Set worst answer time
+ db.hget(key, 'worstguesstime', function(err, res) {
+ if (stats.guesstime > res) {
+ db.hset(key, 'worstguesstime', stats.guesstime);
+ }
+ });
+ }
+ if (stats.firstplace) {
+ // Update the number of first places
+ db.hincrby(key, 'victories', 1);
+ }
+ if (stats.secondplace) {
+ db.hincrby(key, 'secondplaces', 1);
+ }
+ if (stats.thirdplace) {
+ db.hincrby(key, 'thirdplaces', 1);
+ }
};
*/
module.exports = function(username, email, salt, hash, joindate) {
- this.username = username;
- this.email = email;
- this.salt = salt;
- this.password = hash;
- this.joindate = joindate;
- this.totpoints = 0;
- this.bestscore = 0;
- this.golds = 0;
- this.silvers = 0;
- this.bronzes = 0;
- this.bestguesstime = 30000;
- this.worstguesstime = 0;
- this.totguesstime = 0;
- this.guessed = 0;
- this.victories = 0;
- this.secondplaces = 0;
- this.thirdplaces = 0;
+ this.username = username;
+ this.email = email;
+ this.salt = salt;
+ this.password = hash;
+ this.joindate = joindate;
+ this.totpoints = 0;
+ this.bestscore = 0;
+ this.golds = 0;
+ this.silvers = 0;
+ this.bronzes = 0;
+ this.bestguesstime = 30000;
+ this.worstguesstime = 0;
+ this.totguesstime = 0;
+ this.guessed = 0;
+ this.victories = 0;
+ this.secondplaces = 0;
+ this.thirdplaces = 0;
};
*/
exports.buildLeaderboards = function(pointsresults, timesresults) {
- var obj = {
- pointsleaderboard: [],
- timesleaderboard: []
- };
- for (var i=0; i<pointsresults.length; i+=2) {
- obj.pointsleaderboard.push({
- username: pointsresults[i],
- totpoints: pointsresults[i+1]
- });
- obj.timesleaderboard.push({
- username: timesresults[i],
- bestguesstime: (timesresults[i+1] / 1000).toFixed(2)
- });
- }
- return obj;
+ var obj = {
+ pointsleaderboard: [],
+ timesleaderboard: []
+ };
+ for (var i=0; i<pointsresults.length; i+=2) {
+ obj.pointsleaderboard.push({
+ username: pointsresults[i],
+ totpoints: pointsresults[i+1]
+ });
+ obj.timesleaderboard.push({
+ username: timesresults[i],
+ bestguesstime: (timesresults[i+1] / 1000).toFixed(2)
+ });
+ }
+ return obj;
};
/**
*/
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}$/;
- return filter.test(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}$/;
+ return filter.test(str);
};
/**
*/
exports.isUsername = function(str) {
- var filter = /^[a-zA-Z0-9\-_]{1,15}$/;
- return filter.test(str);
+ var 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.'
- ];
- return slogans[Math.floor(Math.random() * slogans.length)];
+ var 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'
- ];
- return params;
+ var params = [
+ 'users'
+ , 'by'
+ , 'user:*->bestguesstime'
+ , 'get'
+ , '#'
+ , 'get'
+ , 'user:*->bestguesstime'
+ , 'limit'
+ , offset
+ , '30'
+ ];
+ return params;
};
@font-face {
- font-family: 'ChristopherhandRegular';
- src: url('/static/fonts/comesinhandy-webfont.eot');
- src: url('/static/fonts/comesinhandy-webfont.eot?#iefix') format('embedded-opentype'),
- url('/static/fonts/comesinhandy-webfont.woff') format('woff'),
- url('/static/fonts/comesinhandy-webfont.ttf') format('truetype');
- font-weight: normal;
- font-style: normal;
+ font-family: 'ChristopherhandRegular';
+ src: url('/static/fonts/comesinhandy-webfont.eot');
+ src: url('/static/fonts/comesinhandy-webfont.eot?#iefix') format('embedded-opentype'),
+ url('/static/fonts/comesinhandy-webfont.woff') format('woff'),
+ url('/static/fonts/comesinhandy-webfont.ttf') format('truetype');
+ font-weight: normal;
+ font-style: normal;
}
body {
- background: url('/static/img/bg.jpg') repeat-x scroll 0 0 #F5F6F7;
- padding-top: 45px;
+ background: url('/static/img/bg.jpg') repeat-x scroll 0 0 #F5F6F7;
+ padding-top: 45px;
}
section {
- margin-top: 30px;
+ margin-top: 30px;
}
h1, h2, h3, h4, h5, h6 {
- margin: 0;
+ margin: 0;
}
h1 {
- font-size: 30px;
- line-height: 36px;
+ font-size: 30px;
+ line-height: 36px;
}
h2 {
- font-size: 24px;
- line-height: 36px;
+ font-size: 24px;
+ line-height: 36px;
}
h3 {
- font-size: 18px;
- line-height: 27px;
+ font-size: 18px;
+ line-height: 27px;
}
h4, h5, h6 {
- line-height: 18px;
+ line-height: 18px;
}
h4 {
- font-size: 14px;
+ font-size: 14px;
}
h5 {
- font-size: 12px;
+ font-size: 12px;
}
h6 {
- font-size: 11px;
- color: #999999;
- text-transform: uppercase;
+ font-size: 11px;
+ color: #999999;
+ text-transform: uppercase;
}
.icons {
- background: url('/static/img/sprites.png') no-repeat;
+ background: url('/static/img/sprites.png') no-repeat;
}
.align-left {
- text-align: left;
+ text-align: left;
}
.navbar .brand {
- padding: 2px 20px 4px;
+ padding: 2px 20px 4px;
}
.logo {
- font-family: 'ChristopherhandRegular';
+ font-family: 'ChristopherhandRegular';
}
.navbar .brand .logo {
- height: 34px;
- padding-left: 68px;
- line-height: 40px;
- background-position: -36px -174px;
- font-size: 25px;
+ height: 34px;
+ padding-left: 68px;
+ line-height: 40px;
+ background-position: -36px -174px;
+ font-size: 25px;
}
.navbar .nav > li > a {
- padding: 11px 10px;
+ padding: 11px 10px;
}
.navbar .nav.pull-right {
- margin-left: 10px;
- margin-right: 0;
+ margin-left: 10px;
+ margin-right: 0;
}
.page-header .logo {
- display: inline-block;
- height: 54px;
- padding-left: 109px;
- line-height: 68px;
- background-position: 0 -120px;
- font-size: 34px;
- color: #0088CC;
+ display: inline-block;
+ height: 54px;
+ padding-left: 109px;
+ line-height: 68px;
+ background-position: 0 -120px;
+ font-size: 34px;
+ color: #0088CC;
}
.form-horizontal .control-group {
- margin-bottom: 10px;
+ margin-bottom: 10px;
}
.form-horizontal .control-label {
- width: 100px;
+ width: 100px;
}
.form-horizontal .controls {
- margin-left: 120px;
+ margin-left: 120px;
}
form .clearfix {
- margin-bottom: 10px;
+ margin-bottom: 10px;
}
.well {
- background-color: #DDDDDD;
- margin-bottom: 18px;
+ background-color: #DDDDDD;
+ margin-bottom: 18px;
}
.alert {
- margin-bottom: 9px;
+ margin-bottom: 9px;
}
.submit-button {
- margin-left: 120px;
- margin-top: 9px;
+ margin-left: 120px;
+ margin-top: 9px;
}
.forgot-passwd {
- display: inline-block;
- vertical-align: top;
- margin: 14px 0 0 15px;
+ display: inline-block;
+ vertical-align: top;
+ margin: 14px 0 0 15px;
}
#captcha-input {
- width: 122px;
+ width: 122px;
}
#captcha {
- margin-right: 20px;
+ margin-right: 20px;
}
.page-header {
- padding: 0;
- margin: 0 0 17px 0;
- border-bottom: 1px solid #ddd;
- -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
- box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ padding: 0;
+ margin: 0 0 17px 0;
+ border-bottom: 1px solid #ddd;
+ -webkit-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ -moz-box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
+ box-shadow: 0 1px 0 rgba(255, 255, 255, 0.5);
}
#login, #guess, #message {
- margin-bottom: 0;
+ margin-bottom: 0;
}
#login {
- float: left;
+ float: left;
}
#join {
- margin-right: 45px;
+ margin-right: 45px;
}
.modal-footer .divider, .modal-footer .divider span {
- position: absolute;
+ position: absolute;
}
.modal-footer .divider {
- border-left: 1px solid #ddd;
- height: 38px;
- top: 9px;
- left: 442px;
+ border-left: 1px solid #ddd;
+ height: 38px;
+ top: 9px;
+ left: 442px;
}
.modal-footer .divider span {
- color: #aaa;
- background-color: #F5F5F5;
- top: 10px;
- left: -6px;
+ color: #aaa;
+ background-color: #F5F5F5;
+ top: 10px;
+ left: -6px;
}
.users-counter, #total-tracks, #tracks a, #nodejitsu-logo, .footer-info {
- float: right;
+ float: right;
}
.thumbnails {
- margin-bottom: 0;
+ margin-bottom: 0;
}
.thumbnails > li {
- margin: 0 0 18px 80px;
+ margin: 0 0 18px 80px;
}
.thumbnail {
- border: 1px solid #ccc;
- height: 140px;
- opacity: 0.7;
+ border: 1px solid #ccc;
+ height: 140px;
+ opacity: 0.7;
}
.thumbnail:hover {
- opacity: 1;
+ opacity: 1;
}
.thumbnail img {
- float: left;
- width: 70px;
- height: 70px;
+ float: left;
+ width: 70px;
+ height: 70px;
}
.highscores, .profile {
- font-weight: bold;
- font-size: 22px;
- line-height: 32px;
+ font-weight: bold;
+ font-size: 22px;
+ line-height: 32px;
}
.highscores .img, .profile .img, .medals {
- width: 32px;
- height: 32px;
+ width: 32px;
+ height: 32px;
}
.profile .img {
- margin-right: 5px;
- background-position: 0 -56px;
+ margin-right: 5px;
+ background-position: 0 -56px;
}
.highscores .img {
- margin-right: 7px;
- background-position: -64px 0;
+ margin-right: 7px;
+ background-position: -64px 0;
}
.leaderboard-wrapper, .stats {
- border: 1px solid #ccc;
- border-left: 0;
- margin-top: 8px;
+ border: 1px solid #ccc;
+ border-left: 0;
+ margin-top: 8px;
}
.leaderboard-wrapper {
- height: 349px;
- overflow: auto;
- margin-bottom: 18px;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
+ height: 349px;
+ overflow: auto;
+ margin-bottom: 18px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
}
.leaderboard {
- margin: 0;
- border: 0;
+ margin: 0;
+ border: 0;
}
.leaderboard td, .stats td {
- border-left: 1px solid #ccc;
- border-top: 1px solid #ccc;
- vertical-align: middle;
+ border-left: 1px solid #ccc;
+ border-top: 1px solid #ccc;
+ vertical-align: middle;
}
.leaderboard td [class^="icon-"] {
- vertical-align: top;
- margin-top: 2px;
+ vertical-align: top;
+ margin-top: 2px;
}
.leaderboard tr:first-child td {
- border-top: 0;
+ border-top: 0;
}
.leaderboard tbody tr:nth-child(odd) td, .stats tbody tr:nth-child(odd) td {
- background-color: #ddd;
+ background-color: #ddd;
}
.leaderboard tbody tr:hover td, .stats tbody tr:hover td {
- background-color: #dadada;
+ background-color: #dadada;
}
.loading {
- width: 18px;
- position: absolute;
- top: 360px;
- left: 191px;
- display: none;
+ width: 18px;
+ position: absolute;
+ top: 360px;
+ left: 191px;
+ display: none;
}
.loading-block {
- background-color: #6184B7;
- border: 1px solid #466085;
- float: left;
- height: 12px;
- margin-left: 1px;
- width: 3px;
- opacity: 0.1;
- -o-animation-name: bounce;
- -o-animation-duration: 1s;
- -o-animation-iteration-count: infinite;
- -o-transform: scale(0.7);
- -moz-animation-name: bounce;
- -moz-animation-duration: 1s;
- -moz-animation-iteration-count: infinite;
- -moz-transform: scale(0.7);
- -ms-transform: scale(0.7);
- -webkit-animation-name: bounce;
- -webkit-animation-duration: 1s;
- -webkit-animation-iteration-count: infinite;
- -webkit-transform: scale(0.7);
- animation-name: bounce;
- animation-duration: 1s;
- animation-iteration-count: infinite;
- transform: scale(0.7);
+ background-color: #6184B7;
+ border: 1px solid #466085;
+ float: left;
+ height: 12px;
+ margin-left: 1px;
+ width: 3px;
+ opacity: 0.1;
+ -o-animation-name: bounce;
+ -o-animation-duration: 1s;
+ -o-animation-iteration-count: infinite;
+ -o-transform: scale(0.7);
+ -moz-animation-name: bounce;
+ -moz-animation-duration: 1s;
+ -moz-animation-iteration-count: infinite;
+ -moz-transform: scale(0.7);
+ -ms-transform: scale(0.7);
+ -webkit-animation-name: bounce;
+ -webkit-animation-duration: 1s;
+ -webkit-animation-iteration-count: infinite;
+ -webkit-transform: scale(0.7);
+ animation-name: bounce;
+ animation-duration: 1s;
+ animation-iteration-count: infinite;
+ transform: scale(0.7);
}
.loading-block:first-child {
- -o-animation-delay: 0.4s;
- -moz-animation-delay: 0.4s;
- -webkit-animation-delay: 0.4s;
- animation-delay: 0.4s;
+ -o-animation-delay: 0.4s;
+ -moz-animation-delay: 0.4s;
+ -webkit-animation-delay: 0.4s;
+ animation-delay: 0.4s;
}
.loading-block:nth-child(2) {
- -o-animation-delay: 0.5s;
- -moz-animation-delay: 0.5s;
- -webkit-animation-delay: 0.5s;
- animation-delay: 0.5s;
+ -o-animation-delay: 0.5s;
+ -moz-animation-delay: 0.5s;
+ -webkit-animation-delay: 0.5s;
+ animation-delay: 0.5s;
}
.loading-block:last-child {
- -o-animation-delay: 0.6s;
- -moz-animation-delay: 0.6s;
- -webkit-animation-delay: 0.6s;
- animation-delay: 0.6s;
+ -o-animation-delay: 0.6s;
+ -moz-animation-delay: 0.6s;
+ -webkit-animation-delay: 0.6s;
+ animation-delay: 0.6s;
}
@-o-keyframes bounce {
- 0% {
- -o-transform: scale(1);
- opacity: 1;
- }
- 100% {
- -o-transform: scale(0.7);
- opacity: 0.1;
- }
+ 0% {
+ -o-transform: scale(1);
+ opacity: 1;
+ }
+ 100% {
+ -o-transform: scale(0.7);
+ opacity: 0.1;
+ }
}
@-moz-keyframes bounce {
- 0% {
- -moz-transform: scale(1);
- opacity: 1;
- }
- 100% {
- -moz-transform: scale(0.7);
- opacity: 0.1;
- }
+ 0% {
+ -moz-transform: scale(1);
+ opacity: 1;
+ }
+ 100% {
+ -moz-transform: scale(0.7);
+ opacity: 0.1;
+ }
}
@-webkit-keyframes bounce {
- 0% {
- -webkit-transform: scale(1);
- opacity: 1;
- }
- 100% {
- -webkit-transform: scale(0.7);
- opacity: 0.1;
- }
+ 0% {
+ -webkit-transform: scale(1);
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: scale(0.7);
+ opacity: 0.1;
+ }
}
@keyframes bounce {
- 0% {
- transform: scale(1);
- opacity: 1;
- }
- 100% {
- transform:s cale(0.7);
- opacity: 0.1;
- }
+ 0% {
+ transform: scale(1);
+ opacity: 1;
+ }
+ 100% {
+ transform:s cale(0.7);
+ opacity: 0.1;
+ }
}
.room {
- height: 25px;
- line-height: 25px;
- position: absolute;
- top: 61px;
- background-color: rgba(51,51,51, 0.7);
- color: white;
- font-weight: bold;
- font-size: 14px;
- width: 210px;
- text-align: center;
- text-transform: capitalize;
+ height: 25px;
+ line-height: 25px;
+ position: absolute;
+ top: 61px;
+ background-color: rgba(51,51,51, 0.7);
+ color: white;
+ font-weight: bold;
+ font-size: 14px;
+ width: 210px;
+ text-align: center;
+ text-transform: capitalize;
}
.dropdown-menu li > a {
- padding: 2px 10px;
- white-space: normal;
+ padding: 2px 10px;
+ white-space: normal;
}
.users-counter {
- font-size: 12px;
- margin-right: 4px;
+ font-size: 12px;
+ margin-right: 4px;
}
.matched {
- color: #f3a22f;
+ color: #f3a22f;
}
.cups, .medals {
- margin-left: auto;
- margin-right: auto;
+ margin-left: auto;
+ margin-right: auto;
}
.cups {
- width: 16px;
- height: 16px;
+ width: 16px;
+ height: 16px;
}
.rank1 {
- background-position: -32px -16px;
+ background-position: -32px -16px;
}
.rank2 {
- background-position: -32px -48px;
+ background-position: -32px -48px;
}
.rank3 {
- background-position: -32px -80px;
+ background-position: -32px -80px;
}
.scoreboard th, .scoreboard td {
- vertical-align: middle;
- text-align: center;
+ vertical-align: middle;
+ text-align: center;
}
.scoreboard .name {
- font-weight: bold;
+ font-weight: bold;
}
.relative {
- position: relative;
+ position: relative;
}
#app-name {
- display: inline-block;
+ display: inline-block;
}
#total-tracks {
- color: #BFBFBF;
- margin-top: 34px;
+ color: #BFBFBF;
+ margin-top: 34px;
}
#cassette {
- margin-top: 22px;
- height: 137px;
- background: url('/static/img/cassette.png') no-repeat 0 0;
+ margin-top: 22px;
+ height: 137px;
+ background: url('/static/img/cassette.png') no-repeat 0 0;
}
#countdown {
- position: absolute;
- width: 26px;
- text-align: center;
- top: 80px;
- left: 175px;
+ position: absolute;
+ width: 26px;
+ text-align: center;
+ top: 80px;
+ left: 175px;
}
#wheel-left, #wheel-right {
- position: absolute;
- width: 24px;
- height: 24px;
- top: 49px;
- background-position: 0 -32px;
+ position: absolute;
+ width: 24px;
+ height: 24px;
+ top: 49px;
+ background-position: 0 -32px;
}
#wheel-left {
- left: 51px;
+ left: 51px;
}
#wheel-right {
- left: 145px;
+ left: 145px;
}
#tape-left, #tape-right {
- height: 70px;
- width: 70px;
- position: absolute;
- top: 25px;
- background-color: black;
- -webkit-border-radius: 70px;
- -moz-border-radius: 70px;
- border-radius: 70px;
- z-index: -1;
+ height: 70px;
+ width: 70px;
+ position: absolute;
+ top: 25px;
+ background-color: black;
+ -webkit-border-radius: 70px;
+ -moz-border-radius: 70px;
+ border-radius: 70px;
+ z-index: -1;
}
#tape-left {
- left: 20px;
+ left: 20px;
}
#tape-right {
- left: 106px;
+ left: 106px;
}
#progress-bar, #progress {
- height: 7px;
- -webkit-border-radius: 4px;
- -moz-border-radius: 4px;
- border-radius: 4px;
- -webkit-box-shadow: inset 0 1px 2px 0 #333;
- -moz-box-shadow: inset 0 1px 2px 0 #333;
- box-shadow: inset 0 1px 2px 0 #333;
+ height: 7px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ border-radius: 4px;
+ -webkit-box-shadow: inset 0 1px 2px 0 #333;
+ -moz-box-shadow: inset 0 1px 2px 0 #333;
+ box-shadow: inset 0 1px 2px 0 #333;
}
#progress-bar {
- position: absolute;
- width: 148px;
- top: 85px;
- left: 20px;
- border: 1px solid #404040;
- border: 1px solid rgba(0, 0, 0, 0.5);
+ position: absolute;
+ width: 148px;
+ top: 85px;
+ left: 20px;
+ border: 1px solid #404040;
+ border: 1px solid rgba(0, 0, 0, 0.5);
}
#progress {
- background-color: #6184b7;
- width: 0;
+ background-color: #6184b7;
+ width: 0;
}
#touch-backdrop {
- height: 137px;
- -webkit-border-radius: 5px;
- -moz-border-radius: 5px;
- border-radius: 5px;
- background: rgba(50,50,50,0.8);
+ height: 137px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ background: rgba(50,50,50,0.8);
}
#touch-play {
- position: absolute;
- top: 54px;
- left: 73px;
+ position: absolute;
+ top: 54px;
+ left: 73px;
}
#volume {
- height: 159px;
+ height: 159px;
}
#volume-button, #volume-slider, #volume-total, #volume-current, #volume-handle {
- position: absolute;
+ position: absolute;
}
#volume-button {
- bottom: 0;
- height: 20px;
- width: 20px;
+ bottom: 0;
+ height: 20px;
+ width: 20px;
}
#volume-button .button {
- display: block;
- height: 18px;
- width: 18px;
- border: 1px solid;
- border-color: #CCCCCC #CCCCCC #AAAAAA;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- cursor: pointer;
- filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#ffffffff,EndColorStr=#ffe0e0e0);
- background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
- background-image: -ms-linear-gradient(top,#fff 0,#e0e0e0 100%);
- background-image: -o-linear-gradient(top,#fff 0,#e0e0e0 100%);
- background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e0e0e0));
- background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
- background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
+ display: block;
+ height: 18px;
+ width: 18px;
+ border: 1px solid;
+ border-color: #CCCCCC #CCCCCC #AAAAAA;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ cursor: pointer;
+ filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#ffffffff,EndColorStr=#ffe0e0e0);
+ background-image: -moz-linear-gradient(top,#fff 0,#e0e0e0 100%);
+ background-image: -ms-linear-gradient(top,#fff 0,#e0e0e0 100%);
+ background-image: -o-linear-gradient(top,#fff 0,#e0e0e0 100%);
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#fff),color-stop(100%,#e0e0e0));
+ background-image: -webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);
+ background-image: linear-gradient(to bottom,#fff 0,#e0e0e0 100%);
}
#volume-button .button:hover {
- border-color: #999999;
- -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25);
- -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25);
- box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25);
+ border-color: #999999;
+ -webkit-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25);
+ -moz-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25);
+ box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.25);
}
#volume-button .button:active {
- border-color: #999999 #AAAAAA #CCCCCC;
- -webkit-box-shadow: 0 1px 2px 0 #aaa inset;
- -moz-box-shadow: 0 1px 2px 0 #aaa inset;
- box-shadow: 0 1px 2px 0 #aaa inset;
- filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#e6e6e6,EndColorStr=#dcdcdc);
- background-image: -moz-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
- background-image: -ms-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
- background-image: -o-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
- background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#e6e6e6),color-stop(100%,#dcdcdc));
- background-image: -webkit-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
- background-image: linear-gradient(to bottom,#e6e6e6 0,#dcdcdc 100%);
+ border-color: #999999 #AAAAAA #CCCCCC;
+ -webkit-box-shadow: 0 1px 2px 0 #aaa inset;
+ -moz-box-shadow: 0 1px 2px 0 #aaa inset;
+ box-shadow: 0 1px 2px 0 #aaa inset;
+ filter:progid:DXImageTransform.Microsoft.Gradient(GradientType=0,StartColorStr=#e6e6e6,EndColorStr=#dcdcdc);
+ background-image: -moz-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
+ background-image: -ms-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
+ background-image: -o-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
+ background-image: -webkit-gradient(linear,left top,left bottom,color-stop(0,#e6e6e6),color-stop(100%,#dcdcdc));
+ background-image: -webkit-linear-gradient(top,#e6e6e6 0,#dcdcdc 100%);
+ background-image: linear-gradient(to bottom,#e6e6e6 0,#dcdcdc 100%);
}
#volume-button .button #icon {
- margin: 1px;
- width: 16px;
- height: 16px;
+ margin: 1px;
+ width: 16px;
+ height: 16px;
}
#volume-button .button .volume-none {
- background-position: 0 -88px;
+ background-position: 0 -88px;
}
#volume-button .button .volume-low {
- background-position: -16px -88px;
+ background-position: -16px -88px;
}
#volume-button .button .volume-medium {
- background-position: 0 -104px;
+ background-position: 0 -104px;
}
#volume-button .button .volume-high {
- background-position: -16px -104px;
+ background-position: -16px -104px;
}
#volume-slider {
- display: none;
- height: 116px;
- width: 20px;
- top: -116px;
- -webkit-border-radius: 3px;
- -moz-border-radius: 3px;
- border-radius: 3px;
- background: rgba(50, 50, 50, 0.1);
- z-index: 1;
+ display: none;
+ height: 116px;
+ width: 20px;
+ top: -116px;
+ -webkit-border-radius: 3px;
+ -moz-border-radius: 3px;
+ border-radius: 3px;
+ background: rgba(50, 50, 50, 0.1);
+ z-index: 1;
}
#volume-total, #volume-current {
- left: 8px;
- top: 8px;
- width: 4px;
- height: 100px;
+ left: 8px;
+ top: 8px;
+ width: 4px;
+ height: 100px;
}
#volume-total, #volume-current, #volume-handle {
- -webkit-border-radius: 2px;
- -moz-border-radius: 2px;
- border-radius: 2px;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
}
#volume-total {
- -webkit-box-shadow: inset 0 0 3px 0 #333;
- -moz-box-shadow: inset 0 0 3px 0 #333;
- box-shadow: inset 0 0 3px 0 #333;
+ -webkit-box-shadow: inset 0 0 3px 0 #333;
+ -moz-box-shadow: inset 0 0 3px 0 #333;
+ box-shadow: inset 0 0 3px 0 #333;
}
#volume-current {
- -webkit-box-shadow: inset 0 0 1px 0 #000;
- -moz-box-shadow: inset 0 0 1px 0 #000;
- box-shadow: inset 0 0 1px 0 #000;
- background-color: #6184b7;
+ -webkit-box-shadow: inset 0 0 1px 0 #000;
+ -moz-box-shadow: inset 0 0 1px 0 #000;
+ box-shadow: inset 0 0 1px 0 #000;
+ background-color: #6184b7;
}
#volume-handle {
- left: 1px;
- width: 16px;
- height: 4px;
- background: #ddd;
- background: rgba(255, 255, 255, 0.9);
- cursor: N-resize;
- border: 1px solid #999;
+ left: 1px;
+ width: 16px;
+ height: 4px;
+ background: #ddd;
+ background: rgba(255, 255, 255, 0.9);
+ cursor: N-resize;
+ border: 1px solid #999;
}
#summary {
- text-align: center;
- margin-bottom: 18px;
+ text-align: center;
+ margin-bottom: 18px;
}
#users-wrapper {
- margin-left: 120px;
- width: 300px;
+ margin-left: 120px;
+ width: 300px;
}
#users {
- padding-left: 20px;
- margin-bottom: 72px;
- max-height: 398px;
- overflow: auto;
+ padding-left: 20px;
+ margin-bottom: 72px;
+ max-height: 398px;
+ overflow: auto;
}
#users .name, #tracks .artist {
- font-weight: bold;
+ font-weight: bold;
}
#message-wrapper {
- text-align: right;
+ text-align: right;
}
#users li, #tracks li, #chat li {
- color: #404040;
+ color: #404040;
}
#users li {
- height: 18px;
- position: relative;
+ height: 18px;
+ position: relative;
}
#users .private {
- display: none;
- font-size: 9.75px;
- padding: 2px 4px;
- position: absolute;
- left: -19px;
+ display: none;
+ font-size: 9.75px;
+ padding: 2px 4px;
+ position: absolute;
+ left: -19px;
}
.registered, .round-rank {
- height: 16px;
- width: 16px;
- margin: 1px 2px 0 0;
+ height: 16px;
+ width: 16px;
+ margin: 1px 2px 0 0;
}
.registered {
- background-position: 0 -16px;
+ background-position: 0 -16px;
}
.registered:hover {
- background-position: -16px -16px;
+ background-position: -16px -16px;
}
#users .name {
- margin-right: 4px;
+ margin-right: 4px;
}
#users .name, .registered {
- cursor: pointer;
+ cursor: pointer;
}
#users .you {
- cursor: auto;
+ cursor: auto;
}
#users .points, #users .round-points {
- margin-right: 10px;
+ margin-right: 10px;
}
.stand1 {
- background-position: 0 0;
+ background-position: 0 0;
}
.stand2 {
- background-position: -16px 0;
+ background-position: -16px 0;
}
.stand3 {
- background-position: -32px 0;
+ background-position: -32px 0;
}
#users .guess-time {
- font-size: 11px;
- line-height: 18px;
+ font-size: 11px;
+ line-height: 18px;
}
#toggle-chat {
- position: absolute;
- top: -17px;
- left: 805px;
- color: #BFBFBF;
- height: 16px;
- line-height: 16px;
- font-size: 11px;
- border: 1px solid #DDDDDD;
- -moz-border-radius: 4px 4px 0 0;
- -webkit-border-radius: 4px 4px 0 0;
- border-radius: 4px 4px 0 0;
- cursor: pointer;
- padding: 0 10px;
- text-decoration: none;
+ position: absolute;
+ top: -17px;
+ left: 805px;
+ color: #BFBFBF;
+ height: 16px;
+ line-height: 16px;
+ font-size: 11px;
+ border: 1px solid #DDDDDD;
+ -moz-border-radius: 4px 4px 0 0;
+ -webkit-border-radius: 4px 4px 0 0;
+ border-radius: 4px 4px 0 0;
+ cursor: pointer;
+ padding: 0 10px;
+ text-decoration: none;
}
#toggle-chat:hover {
- border-color: #CCCCCC;
- background-color: #f5f5f5;
- color: #333333;
- background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
- background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
- background-image: linear-gradient(top, #ffffff, #e6e6e6);
- filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
- -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
+ border-color: #CCCCCC;
+ background-color: #f5f5f5;
+ color: #333333;
+ background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -ms-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
+ background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
+ background-image: linear-gradient(top, #ffffff, #e6e6e6);
+ filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#e6e6e6', GradientType=0);
+ -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2),0 1px 2px rgba(0, 0, 0, 0.05);
}
#toggle-chat:active {
- background-image: none;
- -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
- -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
- box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
- background-color: #e6e6e6;
- background-color: #d9d9d9 \9;
- outline: 0;
+ background-image: none;
+ -webkit-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
+ -moz-box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
+ box-shadow: inset 0 2px 4px rgba(0, 0, 0, 0.15),0 1px 2px rgba(0, 0, 0, 0.05);
+ background-color: #e6e6e6;
+ background-color: #d9d9d9 \9;
+ outline: 0;
}
#chat-wrapper {
- margin-bottom: 4px;
- height: 160px;
- background-color: white;
+ margin-bottom: 4px;
+ height: 160px;
+ background-color: white;
}
#chat {
- height: 152px;
- width: 446px;
- margin: 4px 6px;
- overflow: auto;
+ height: 152px;
+ width: 446px;
+ margin: 4px 6px;
+ overflow: auto;
}
.bordered {
- border: 1px solid #ccc;
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
- -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075);
- -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075);
- box-shadow: 0 1px 2px rgba(0,0,0,.075);
+ border: 1px solid #ccc;
+ -webkit-border-radius: 6px;
+ -moz-border-radius: 6px;
+ border-radius: 6px;
+ -webkit-box-shadow: 0 1px 2px rgba(0,0,0,.075);
+ -moz-box-shadow: 0 1px 2px rgba(0,0,0,.075);
+ box-shadow: 0 1px 2px rgba(0,0,0,.075);
}
#chat .join, #chat .left {
- font-style: italic;
+ font-style: italic;
}
#chat .private {
- color: #a65fc3;
+ color: #a65fc3;
}
#feedback {
- text-align: center;
+ text-align: center;
}
#feedback .correct, #users .correct{
- color: #46A546;
+ color: #46A546;
}
#feedback .wrong, #chat .error {
- color: #C43C35;
+ color: #C43C35;
}
#guess.correct {
- border-color: #46A546;
+ border-color: #46A546;
}
#guess.correct:focus {
- -webkit-box-shadow: 0 0 6px #7aba7b;
- -moz-box-shadow: 0 0 6px #7aba7b;
- box-shadow: 0 0 6px #7aba7b;
+ -webkit-box-shadow: 0 0 6px #7aba7b;
+ -moz-box-shadow: 0 0 6px #7aba7b;
+ box-shadow: 0 0 6px #7aba7b;
}
#guess.wrong {
- border-color: #C43C35;
+ border-color: #C43C35;
}
#guess.wrong:focus {
- -webkit-box-shadow: 0 0 6px #d59392;
- -moz-box-shadow: 0 0 6px #d59392;
- box-shadow: 0 0 6px #d59392;
+ -webkit-box-shadow: 0 0 6px #d59392;
+ -moz-box-shadow: 0 0 6px #d59392;
+ box-shadow: 0 0 6px #d59392;
}
#tracks {
- margin: 18px 0;
- max-height: 240px;
- overflow: auto;
+ margin: 18px 0;
+ max-height: 240px;
+ overflow: auto;
}
#tracks li {
- margin: 0 2px 2px 0;
- padding: 8px;
- min-height: 40px;
- background: -moz-linear-gradient(center top , #FBFBFB, #F5F5F5);
- background: -webkit-gradient(linear, center top, center bottom, from(#FBFBFB), to(#F5F5F5));
- background: -webkit-linear-gradient(center top , #FBFBFB, #F5F5F5);
- background: -o-linear-gradient(center top , #FBFBFB, #F5F5F5);
- background: -ms-linear-gradient(center top , #FBFBFB, #F5F5F5);
- background: linear-gradient(center top , #FBFBFB, #F5F5F5);
+ margin: 0 2px 2px 0;
+ padding: 8px;
+ min-height: 40px;
+ background: -moz-linear-gradient(center top , #FBFBFB, #F5F5F5);
+ background: -webkit-gradient(linear, center top, center bottom, from(#FBFBFB), to(#F5F5F5));
+ background: -webkit-linear-gradient(center top , #FBFBFB, #F5F5F5);
+ background: -o-linear-gradient(center top , #FBFBFB, #F5F5F5);
+ background: -ms-linear-gradient(center top , #FBFBFB, #F5F5F5);
+ background: linear-gradient(center top , #FBFBFB, #F5F5F5);
}
.registered, #users .name, #users .points, .round-rank, .round-points, #users .guess-time, #tracks img.artwork, #tracks .info, .highscores .img, .profile .img, #copy, #facebook-button, #twitter-button, #github-button {
- float: left;
+ float: left;
}
#tracks img.artwork {
- width: 40px;
- height: 40px;
- margin-right: 10px;
+ width: 40px;
+ height: 40px;
+ margin-right: 10px;
}
#tracks .info {
- margin-right: 15px;
+ margin-right: 15px;
}
#tracks .artist, #tracks .title {
- white-space: nowrap;
- max-width: 270px;
- overflow: hidden;
- -o-text-overflow: ellipsis;
- -ms-text-overflow: ellipsis;
- text-overflow: ellipsis;
+ white-space: nowrap;
+ max-width: 270px;
+ overflow: hidden;
+ -o-text-overflow: ellipsis;
+ -ms-text-overflow: ellipsis;
+ text-overflow: ellipsis;
}
#tracks .artist {
- margin-top: 1px;
- font-size: 14px;
+ margin-top: 1px;
+ font-size: 14px;
}
#tracks .round-rank {
- margin-top: 12px;
+ margin-top: 12px;
}
#tracks .round-points {
- margin-top: 11px;
+ margin-top: 11px;
}
#tracks a {
- display: block;
- width: 44px;
- height: 15px;
- margin-top: 13px;
- background-position: 0 -248px;
+ display: block;
+ width: 44px;
+ height: 15px;
+ margin-top: 13px;
+ background-position: 0 -248px;
}
#tracks a:hover {
- background-position: -44px -248px;
+ background-position: -44px -248px;
}
#tracks a:active {
- background-position: 0 -263px;
+ background-position: 0 -263px;
}
#disclaimer {
- position: absolute;
- left: 60px;
- bottom: 18px;
- color: #BFBFBF;
- width: 340px;
+ position: absolute;
+ left: 60px;
+ bottom: 18px;
+ color: #BFBFBF;
+ width: 340px;
}
footer {
- padding: 0;
- margin-top: 17px;
- border-top: 1px solid #DDDDDD;
- color: #BFBFBF;
- text-shadow: 0 1px 0 #FFFFFF;
+ padding: 0;
+ margin-top: 17px;
+ border-top: 1px solid #DDDDDD;
+ color: #BFBFBF;
+ text-shadow: 0 1px 0 #FFFFFF;
}
#footer-inner, #twitter-button, #github-button {
- height: 20px;
+ height: 20px;
}
#footer-inner {
- border-top: 1px solid white;
- padding: 5px 20px 0 20px;
- margin-bottom: 30px;
+ border-top: 1px solid white;
+ padding: 5px 20px 0 20px;
+ margin-bottom: 30px;
}
#copy {
- margin-right: 20px;
+ margin-right: 20px;
}
#facebook-button {
- width: 90px;
- height: 21px
+ width: 90px;
+ height: 21px
}
#twitter-button, #github-button {
- width: 100px;
+ width: 100px;
}
#copy, .footer-info {
- line-height: 20px;
+ line-height: 20px;
}
.footer-info {
- white-space: pre-wrap;
+ white-space: pre-wrap;
}
#nodejitsu-logo {
- display: block;
- width: 84px;
- height: 20px;
- background-position: 0 -208px;
+ display: block;
+ width: 84px;
+ height: 20px;
+ background-position: 0 -208px;
}
#nodejitsu-logo:hover {
- background-position: 0 -228px;
+ background-position: 0 -228px;
}
(function() {
- var elapsedtime = 0
- , DOM = {}
- , historycursor = 0
- , historyvalues = []
- , ignoredplayers = {}
- , jplayer
- , nickname
- , pvtmsgto
- , subscriber = false
- , roundpoints = 0
- , roomname = window.location.pathname.replace('/', '')
- , socket
- , stopanimation = false
- , touchplay
- , urlregex = /(https?:\/\/[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])/
- , uri = window.location.protocol+'//'+window.location.host; // Socket.IO server URI
-
- var amstrings = [
- 'Yes, that\'s the artist. What about the title?'
- , 'Exactly, now tell me the title!'
- , 'Do you also know the title?'
- ];
-
- var bmstrings = [
- 'Yeah true! do you like this track?'
- , 'Good job!'
- , 'Great!'
- , 'Very well done!'
- , 'Exactly!'
- , 'Excellent!'
- , 'Woohoo!'
- ];
-
- var nmstrings = [
- 'Nope, sorry!'
- , 'No way!'
- , 'Fail'
- , 'Nope'
- , 'No'
- , 'That\'s wrong'
- , 'What?!'
- , 'Wrong', 'Haha, what?!'
- , 'You kidding?'
- , 'Don\'t make me laugh'
- , 'You mad?'
- , 'Try again'
- ];
-
- 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...'
- ];
-
- var tmstrings = [
- 'Yes, you guessed the title. Who is the artist?'
- , 'Now tell me the artist!'
- , 'Correct, do you also know the artist?'
- ];
-
- String.prototype.encodeEntities = function() {
- return this.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
- };
-
- // Add a chat entry, whether message, notification, etc.
- var addChatEntry = function(childNode) {
- var li = $('<li class="entry"></li>');
- li.append(childNode);
- DOM.chat.append(li);
- DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight;
- };
-
- var addFeedback = function(txt, style) {
- if (typeof style === 'string') {
- var fbspan = $('<span class="'+style+'"></span>');
- fbspan.text(txt);
- DOM.feedback.html(fbspan);
- DOM.guessbox.addClass(style);
- setTimeout(function() {DOM.guessbox.removeClass(style);}, 350);
- return;
- }
- DOM.feedback.text(txt);
- };
-
- var addPrivate = function(usrname) {
- if (pvtmsgto) {
- clearPrivate();
- }
- if (nickname === usrname) {
- return;
- }
- DOM.recipient.css('margin-right', '4px');
- DOM.recipient.text('To '+usrname+':');
- var width = DOM.recipient.outerWidth(true) + 1;
- DOM.recipient.hide();
- DOM.messagebox.animate({'width':'-='+width+'px'}, 'fast', function() {
- DOM.recipient.show();
- });
- var el = $('.name').filter(function(index) {
- return $(this).text() === usrname;
- });
- el.prevAll('.private').show();
- el.unbind('click');
- el.click(clearPrivate);
- pvtmsgto = usrname;
- DOM.messagebox.focus();
- };
-
- // Add track info
- var addTrackInfo = function(data) {
- if (touchplay) {
- touchplay.removeClass('btn-success').addClass('btn-danger disabled');
- touchplay.html('<i class="icon-play icon-white"></i> Wait');
- }
- cassetteAnimation(Date.now()+5000, false);
-
- var artistName = data.artistName.replace(/"/g, '"')
- , trackName = data.trackName.replace(/"/g, '"')
- , attrs = ''
- , rp = '';
-
- var html = '<li class="bordered"><img class="artwork" src="'+data.artworkUrl+'"/>';
- html += '<div class="info"><div class="artist" title="'+artistName+'">'+artistName+'</div>';
- html += '<div class="title" title="'+trackName+'">'+trackName+'</div></div>';
-
- if (roundpoints > 0) {
- rp = '+'+roundpoints;
- if (roundpoints > 3) {
- var stand = 7 - roundpoints;
- attrs += 'class="icons round-rank stand'+stand+'"';
- }
- }
- html += '<div '+attrs+'></div><div class="round-points">'+rp+'</div>';
- html += '<a class="icons" target="itunes_store" href="'+data.trackViewUrl+'"></a></li>';
-
- DOM.tracks.prepend($(html));
- };
-
- var addVolumeControl = function() {
- var volumebutton = $('<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>').appendTo('#volume');
-
- var clicked = false
- , icon = volumebutton.find('#icon')
- , mouseisdown = false
- , mouseisover = false
- , oldvalue = 1
- , volumecurrent = volumebutton.find('#volume-current')
- , volumehandle = volumebutton.find('#volume-handle')
- , volumeslider = volumebutton.find('#volume-slider')
- , volumetotal = volumebutton.find('#volume-total');
-
- var handleIcon = function (volume) {
- if (volume === 0) {
- icon.removeClass().addClass('icons volume-none');
- }
- else if (volume <= 0.33) {
- icon.removeClass().addClass('icons volume-low');
- }
- else if (volume <= 0.66) {
- icon.removeClass().addClass('icons volume-medium');
- }
- 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;
-
- clicked = false;
-
- if (newy < 0) {
- newy = 0;
- }
- else if (newy > railheight) {
- newy = railheight;
- }
-
- volumecurrent.height(railheight - newy);
- volumecurrent.css('top', newy + totalTop);
- volumehandle.css('top', totalTop + newy - (volumehandle.height() / 2));
-
- volume = Math.max(0, volume);
- volume = Math.min(volume, 1);
-
- setVolume(volume);
- };
-
- var loadFromCookie = function() {
- if (/volume\s*\=/.test(document.cookie)) {
- var value = document.cookie.replace(/.*volume\s*\=\s*([^;]*);?.*/, '$1');
- value = parseFloat(value);
- positionVolumeHandle(value);
- setVolume(value);
- return;
- }
- positionVolumeHandle(1);
- };
-
- var positionVolumeHandle = function(volume) {
- if (!volumeslider.is(':visible')) {
- volumeslider.show();
- positionVolumeHandle(volume);
- volumeslider.hide();
- return;
- }
- var totalheight = volumetotal.height();
- var totalposition = volumetotal.position();
- var newtop = totalheight - (totalheight * volume);
- volumecurrent.height(totalheight - newtop );
- volumecurrent.css('top', totalposition.top + newtop);
- 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()+';';
- };
-
- var setVolume = function(volume) {
- handleIcon(volume);
- jplayer.jPlayer('volume', volume);
- oldvalue = volume;
- setCookie(volume);
- };
-
- volumebutton.find('.button').click(function() {
- if (!clicked) {
- clicked = true;
- if (oldvalue !== 0) {
- handleIcon(0);
- jplayer.jPlayer('volume', 0);
- positionVolumeHandle(0);
- }
- }
- else {
- clicked = false;
- if (oldvalue !== 0) {
- handleIcon(oldvalue);
- jplayer.jPlayer('volume', oldvalue);
- positionVolumeHandle(oldvalue);
- }
- }
- });
-
- 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(e) {
- mouseisdown = false;
- if (!mouseisover) {
- volumeslider.hide();
- }
- }).on('mousemove', function(e) {
- if (mouseisdown) {
- handleVolumeMove(e);
- }
- });
-
- loadFromCookie();
- };
-
- // 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>';
- html += '<div class="modal-body"><div class="alert alert-error alert-block">';
- html += '<h4 class="alert-heading">Warning!</h4>You are already in a room.<br/>';
- html += 'Leave the other room and refresh this page or close this one.</div></div>';
- $(html).appendTo(DOM.modal);
- DOM.modal.modal('show');
- };
-
- // Start cassette animation
- var cassetteAnimation = function(endtime, forward) {
- var millisleft = endtime - Date.now()
- , secleft = millisleft / 1000
- , width
- , deg
- , offsetleft
- , offsetright
- , css;
-
- if (forward) {
- width = 148 - (148*secleft/30);
- deg = 360 - (360*secleft/30);
- offsetleft = 44 - 24*secleft/30;
- offsetright = 130 - 24*secleft/30;
- DOM.progress.width(width);
- DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)');
- DOM.tapeleft.css('left', offsetleft+'px');
- DOM.taperight.css('left', offsetright+'px');
- }
- else {
- width = 148*secleft/5;
- deg = 360*secleft/5;
- offsetleft = 20 + 24*secleft/5;
- offsetright = 106 + 24*secleft/5;
- DOM.progress.width(width);
- DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)');
- DOM.tapeleft.css('left', offsetleft+'px');
- DOM.taperight.css('left', offsetright+'px');
- }
-
- if (forward) {
- DOM.countdown.text(secleft.toFixed(1));
- if (touchplay) {elapsedtime = 30 - Math.round(secleft);}
- }
- else {
- DOM.countdown.text(Math.round(secleft));
- }
-
- if (stopanimation || millisleft < 50) {
- return;
- }
-
- setTimeout(function() {cassetteAnimation(endtime, forward);}, 50);
- };
-
- var clearPrivate = function() {
- var width = DOM.recipient.outerWidth(true) + 1;
- DOM.recipient.css('margin-right', '0');
- DOM.recipient.text('');
- DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast');
- var el = $('.name').filter(function(index) {
- return $(this).text() === pvtmsgto;
- });
- el.prevAll('.private').hide();
- el.unbind('click');
- el.click(function() {
- addPrivate($(this).text());
- });
- pvtmsgto = null;
- DOM.messagebox.focus();
- };
-
- // Game over countdown
- var countDown = function(endtime) {
- var millisleft = endtime - Date.now();
- var secleft = millisleft / 1000;
- $('.modal-footer span').text(Math.round(secleft));
- if (millisleft < 200) {
- return;
- }
- setTimeout(function() {countDown(endtime);}, 200);
- };
-
- // Let the user know when he/she has disconnected
- var disconnect = function() {
- stopanimation = true;
- jplayer.jPlayer('stop');
- var errorspan = $('<span class="error">ERROR: You have disconnected.</span>');
- addChatEntry(errorspan);
- addFeedback('Something wrong happened');
- DOM.users.empty();
- };
+ var elapsedtime = 0
+ , DOM = {}
+ , historycursor = 0
+ , historyvalues = []
+ , ignoredplayers = {}
+ , jplayer
+ , nickname
+ , pvtmsgto
+ , subscriber = false
+ , roundpoints = 0
+ , roomname = window.location.pathname.replace('/', '')
+ , socket
+ , stopanimation = false
+ , touchplay
+ , urlregex = /(https?:\/\/[\-A-Za-z0-9+&@#\/%?=~_()|!:,.;]*[\-A-Za-z0-9+&@#\/%=~_()|])/
+ , uri = window.location.protocol+'//'+window.location.host; // Socket.IO server URI
+
+ var amstrings = [
+ 'Yes, that\'s the artist. What about the title?'
+ , 'Exactly, now tell me the title!'
+ , 'Do you also know the title?'
+ ];
+
+ var bmstrings = [
+ 'Yeah true! do you like this track?'
+ , 'Good job!'
+ , 'Great!'
+ , 'Very well done!'
+ , 'Exactly!'
+ , 'Excellent!'
+ , 'Woohoo!'
+ ];
+
+ var nmstrings = [
+ 'Nope, sorry!'
+ , 'No way!'
+ , 'Fail'
+ , 'Nope'
+ , 'No'
+ , 'That\'s wrong'
+ , 'What?!'
+ , 'Wrong', 'Haha, what?!'
+ , 'You kidding?'
+ , 'Don\'t make me laugh'
+ , 'You mad?'
+ , 'Try again'
+ ];
+
+ 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...'
+ ];
+
+ var tmstrings = [
+ 'Yes, you guessed the title. Who is the artist?'
+ , 'Now tell me the artist!'
+ , 'Correct, do you also know the artist?'
+ ];
+
+ String.prototype.encodeEntities = function() {
+ return this.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
+ };
+
+ // Add a chat entry, whether message, notification, etc.
+ var addChatEntry = function(childNode) {
+ var li = $('<li class="entry"></li>');
+ li.append(childNode);
+ DOM.chat.append(li);
+ DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight;
+ };
+
+ var addFeedback = function(txt, style) {
+ if (typeof style === 'string') {
+ var fbspan = $('<span class="'+style+'"></span>');
+ fbspan.text(txt);
+ DOM.feedback.html(fbspan);
+ DOM.guessbox.addClass(style);
+ setTimeout(function() {DOM.guessbox.removeClass(style);}, 350);
+ return;
+ }
+ DOM.feedback.text(txt);
+ };
- var gameOver = function(podium) {
- var html = '<div class="modal-header"><h3>Game Over</h3></div>';
- html += '<div class="modal-body"><table class="table table-striped scoreboard">';
- html += '<thead><tr><th>#</th><th>Name</th><th>Points</th>';
- html += '<th><div class="icons cups stand1"></div></th>';
- html += '<th><div class="icons cups stand2"></div></th>';
- html += '<th><div class="icons cups stand3"></div></th><th>Guessed</th><th>Mean time</th>';
- html += '</thead><tbody>';
-
- for(var i=0;i<3;i++) {
- if (podium[i]) {
- html += '<tr><td><div class="icons medals rank'+(i+1)+'"></div></td>';
- html += '<td class="name">'+podium[i].nickname+'</td>';
- html += '<td>'+podium[i].points+'</td>';
- html += '<td>'+podium[i].golds+'</td><td>'+podium[i].silvers+'</td>';
- html += '<td>'+podium[i].bronzes+'</td><td>'+podium[i].guessed+'</td>';
- var meantime = "N/A";
- if (podium[i].guessed !== 0) {
- meantime = podium[i].totguesstime / podium[i].guessed;
- meantime = (meantime / 1000).toFixed(1)+' s';
- }
- html += '<td>'+meantime+'</td></tr>';
- }
- }
+ var addPrivate = function(usrname) {
+ if (pvtmsgto) {
+ clearPrivate();
+ }
+ if (nickname === usrname) {
+ return;
+ }
+ DOM.recipient.css('margin-right', '4px');
+ DOM.recipient.text('To '+usrname+':');
+ var width = DOM.recipient.outerWidth(true) + 1;
+ DOM.recipient.hide();
+ DOM.messagebox.animate({'width':'-='+width+'px'}, 'fast', function() {
+ DOM.recipient.show();
+ });
+ var el = $('.name').filter(function(index) {
+ return $(this).text() === usrname;
+ });
+ el.prevAll('.private').show();
+ el.unbind('click');
+ el.click(clearPrivate);
+ pvtmsgto = usrname;
+ DOM.messagebox.focus();
+ };
+
+ // Add track info
+ var addTrackInfo = function(data) {
+ if (touchplay) {
+ touchplay.removeClass('btn-success').addClass('btn-danger disabled');
+ touchplay.html('<i class="icon-play icon-white"></i> Wait');
+ }
+ cassetteAnimation(Date.now()+5000, false);
+
+ var artistName = data.artistName.replace(/"/g, '"')
+ , trackName = data.trackName.replace(/"/g, '"')
+ , attrs = ''
+ , rp = '';
+
+ var html = '<li class="bordered"><img class="artwork" src="'+data.artworkUrl+'"/>';
+ html += '<div class="info"><div class="artist" title="'+artistName+'">'+artistName+'</div>';
+ html += '<div class="title" title="'+trackName+'">'+trackName+'</div></div>';
+
+ if (roundpoints > 0) {
+ rp = '+'+roundpoints;
+ if (roundpoints > 3) {
+ var stand = 7 - roundpoints;
+ attrs += 'class="icons round-rank stand'+stand+'"';
+ }
+ }
+ html += '<div '+attrs+'></div><div class="round-points">'+rp+'</div>';
+ html += '<a class="icons" target="itunes_store" href="'+data.trackViewUrl+'"></a></li>';
+
+ DOM.tracks.prepend($(html));
+ };
+
+ var addVolumeControl = function() {
+ var volumebutton = $('<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>').appendTo('#volume');
+
+ var clicked = false
+ , icon = volumebutton.find('#icon')
+ , mouseisdown = false
+ , mouseisover = false
+ , oldvalue = 1
+ , volumecurrent = volumebutton.find('#volume-current')
+ , volumehandle = volumebutton.find('#volume-handle')
+ , volumeslider = volumebutton.find('#volume-slider')
+ , volumetotal = volumebutton.find('#volume-total');
+
+ var handleIcon = function (volume) {
+ if (volume === 0) {
+ icon.removeClass().addClass('icons volume-none');
+ }
+ else if (volume <= 0.33) {
+ icon.removeClass().addClass('icons volume-low');
+ }
+ else if (volume <= 0.66) {
+ icon.removeClass().addClass('icons volume-medium');
+ }
+ 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;
+
+ clicked = false;
+
+ if (newy < 0) {
+ newy = 0;
+ }
+ else if (newy > railheight) {
+ newy = railheight;
+ }
+
+ volumecurrent.height(railheight - newy);
+ volumecurrent.css('top', newy + totalTop);
+ volumehandle.css('top', totalTop + newy - (volumehandle.height() / 2));
+
+ volume = Math.max(0, volume);
+ volume = Math.min(volume, 1);
+
+ setVolume(volume);
+ };
+
+ var loadFromCookie = function() {
+ if (/volume\s*\=/.test(document.cookie)) {
+ var value = document.cookie.replace(/.*volume\s*\=\s*([^;]*);?.*/, '$1');
+ value = parseFloat(value);
+ positionVolumeHandle(value);
+ setVolume(value);
+ return;
+ }
+ positionVolumeHandle(1);
+ };
+
+ var positionVolumeHandle = function(volume) {
+ if (!volumeslider.is(':visible')) {
+ volumeslider.show();
+ positionVolumeHandle(volume);
+ volumeslider.hide();
+ return;
+ }
+ var totalheight = volumetotal.height();
+ var totalposition = volumetotal.position();
+ var newtop = totalheight - (totalheight * volume);
+ volumecurrent.height(totalheight - newtop );
+ volumecurrent.css('top', totalposition.top + newtop);
+ 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()+';';
+ };
+
+ var setVolume = function(volume) {
+ handleIcon(volume);
+ jplayer.jPlayer('volume', volume);
+ oldvalue = volume;
+ setCookie(volume);
+ };
+
+ volumebutton.find('.button').click(function() {
+ if (!clicked) {
+ clicked = true;
+ if (oldvalue !== 0) {
+ handleIcon(0);
+ jplayer.jPlayer('volume', 0);
+ positionVolumeHandle(0);
+ }
+ }
+ else {
+ clicked = false;
+ if (oldvalue !== 0) {
+ handleIcon(oldvalue);
+ jplayer.jPlayer('volume', oldvalue);
+ positionVolumeHandle(oldvalue);
+ }
+ }
+ });
- html +='</tbody></table></div>';
- html += '<div class="modal-footer align-left">A new game will start in ';
- html += '<span></span> second/s</div>';
- DOM.modal.append($(html));
- DOM.modal.modal('show');
- countDown(Date.now()+10000);
- };
+ volumebutton.hover(function() {
+ mouseisover = true;
+ volumeslider.show();
+ }, function() {
+ mouseisover = false;
+ if (!mouseisdown) {
+ volumeslider.hide();
+ }
+ });
- // Receive a chat message
- var getChatMessage = function(chatmsg, from, to) {
- if (ignoredplayers[from]) {
- return;
- }
- var prefix = from;
- var msgspan = $('<span class="message"></span>');
- if (to) {
- // Private Message
- prefix = (nickname === from) ? '(To '+to+')' : '(From '+prefix+')';
- msgspan.addClass('private');
- }
- var msg = prefix+': '+chatmsg;
- msgspan.html(urlize(msg));
- addChatEntry(msgspan);
- };
+ volumeslider.on('mouseover', function() {
+ mouseisover = true;
+ }).on('mousedown', function(e) {
+ handleVolumeMove(e);
+ mouseisdown = true;
+ return false;
+ });
- var hideChat = function() {
- DOM.togglechat.text('Show chat').unbind('click');
- DOM.chatwrapper.toggle(300);
- DOM.tracks.animate({maxHeight:'434px'}, 300);
- DOM.togglechat.click(showChat);
- };
+ $(document).on('mouseup', function(e) {
+ mouseisdown = false;
+ if (!mouseisover) {
+ volumeslider.hide();
+ }
+ }).on('mousemove', function(e) {
+ if (mouseisdown) {
+ handleVolumeMove(e);
+ }
+ });
- // Put a player in the ignore list
- var ignorePlayer = function(args, outcome) {
- if (ignoredplayers[args[0]]) {
- outcome.text('(From binb): '+args[0]+' is already ignored.');
- return addChatEntry(outcome);
- }
- socket.emit('ignore', args[0], function(player) {
- if (player) {
- ignoredplayers[player] = true;
- outcome.text('(From binb): '+player+' is now ignored.');
- return addChatEntry(outcome);
- }
- outcome.append('player not found.');
- addChatEntry(outcome);
- });
- };
+ loadFromCookie();
+ };
+
+ // 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>';
+ html += '<div class="modal-body"><div class="alert alert-error alert-block">';
+ html += '<h4 class="alert-heading">Warning!</h4>You are already in a room.<br/>';
+ html += 'Leave the other room and refresh this page or close this one.</div></div>';
+ $(html).appendTo(DOM.modal);
+ DOM.modal.modal('show');
+ };
+
+ // Start cassette animation
+ var cassetteAnimation = function(endtime, forward) {
+ var millisleft = endtime - Date.now()
+ , secleft = millisleft / 1000
+ , width
+ , deg
+ , offsetleft
+ , offsetright
+ , css;
+
+ if (forward) {
+ width = 148 - (148*secleft/30);
+ deg = 360 - (360*secleft/30);
+ offsetleft = 44 - 24*secleft/30;
+ offsetright = 130 - 24*secleft/30;
+ DOM.progress.width(width);
+ DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)');
+ DOM.tapeleft.css('left', offsetleft+'px');
+ DOM.taperight.css('left', offsetright+'px');
+ }
+ else {
+ width = 148*secleft/5;
+ deg = 360*secleft/5;
+ offsetleft = 20 + 24*secleft/5;
+ offsetright = 106 + 24*secleft/5;
+ DOM.progress.width(width);
+ DOM.cassettewheels.css('transform', 'rotate('+deg+'deg)');
+ DOM.tapeleft.css('left', offsetleft+'px');
+ DOM.taperight.css('left', offsetright+'px');
+ }
- // Submitted name was invalid
- var invalidNickName = function(feedback) {
- joinAnonymously(feedback+'<br/>Try with another one:');
- };
+ if (forward) {
+ DOM.countdown.text(secleft.toFixed(1));
+ if (touchplay) {elapsedtime = 30 - Math.round(secleft);}
+ }
+ else {
+ DOM.countdown.text(Math.round(secleft));
+ }
- // Prompt for name and send it
- var joinAnonymously = function(msg) {
- if (/nickname\s*\=/.test(document.cookie) && !msg) {
- var nickname = document.cookie.replace(/.*nickname\s*\=\s*([^;]*);?.*/, '$1');
- return socket.emit('joinanonymously', nickname, roomname);
- }
+ if (stopanimation || millisleft < 50) {
+ return;
+ }
- if (DOM.modal.hasClass('in')) {
- $('.modal-body p').html(msg);
- return $('#login').focus();
- }
+ setTimeout(function() {cassetteAnimation(endtime, forward);}, 50);
+ };
- var html = '<div class="modal-header">';
- html += '<h3>You are joining the '+roomname+' room</h3></div>';
- html += '<div class="modal-body"><p>'+(msg || "What's your name?")+'</p></div>';
- html += '<div class="modal-footer relative">';
- html += '<input id="login" maxlength="15" type="text" name="nickname" />';
- html += '<button id="join" class="btn btn-success">';
- html += '<i class="icon-user icon-white"></i> Join the game</button>';
- html += '<span class="divider"><span>or</span></span>';
- html += '<a class="btn btn-primary" href="/login?followup=/'+roomname+'">';
- html += '<i class="icon-lock icon-white"></i> Login</a></div>';
-
- $(html).appendTo(DOM.modal);
- var login = $('#login');
- var button = $('#join');
-
- button.click(function() {
- if ($.trim(login.val()) !== '') {
- nickname = login.val();
- socket.emit('joinanonymously', nickname, roomname);
- }
- else {
- var txt = 'Nickname can\'t be empty.';
- invalidNickName('<span class="label label-important">'+txt+'</span>');
- }
- login.val('');
- });
+ var clearPrivate = function() {
+ var width = DOM.recipient.outerWidth(true) + 1;
+ DOM.recipient.css('margin-right', '0');
+ DOM.recipient.text('');
+ DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast');
+ var el = $('.name').filter(function(index) {
+ return $(this).text() === pvtmsgto;
+ });
+ el.prevAll('.private').hide();
+ el.unbind('click');
+ el.click(function() {
+ addPrivate($(this).text());
+ });
+ pvtmsgto = null;
+ DOM.messagebox.focus();
+ };
+
+ // Game over countdown
+ var countDown = function(endtime) {
+ var millisleft = endtime - Date.now();
+ var secleft = millisleft / 1000;
+ $('.modal-footer span').text(Math.round(secleft));
+ if (millisleft < 200) {
+ return;
+ }
+ setTimeout(function() {countDown(endtime);}, 200);
+ };
+
+ // Let the user know when he/she has disconnected
+ var disconnect = function() {
+ stopanimation = true;
+ jplayer.jPlayer('stop');
+ var errorspan = $('<span class="error">ERROR: You have disconnected.</span>');
+ addChatEntry(errorspan);
+ addFeedback('Something wrong happened');
+ DOM.users.empty();
+ };
+
+ var gameOver = function(podium) {
+ var html = '<div class="modal-header"><h3>Game Over</h3></div>';
+ html += '<div class="modal-body"><table class="table table-striped scoreboard">';
+ html += '<thead><tr><th>#</th><th>Name</th><th>Points</th>';
+ html += '<th><div class="icons cups stand1"></div></th>';
+ html += '<th><div class="icons cups stand2"></div></th>';
+ html += '<th><div class="icons cups stand3"></div></th><th>Guessed</th><th>Mean time</th>';
+ html += '</thead><tbody>';
+
+ for(var i=0;i<3;i++) {
+ if (podium[i]) {
+ html += '<tr><td><div class="icons medals rank'+(i+1)+'"></div></td>';
+ html += '<td class="name">'+podium[i].nickname+'</td>';
+ html += '<td>'+podium[i].points+'</td>';
+ html += '<td>'+podium[i].golds+'</td><td>'+podium[i].silvers+'</td>';
+ html += '<td>'+podium[i].bronzes+'</td><td>'+podium[i].guessed+'</td>';
+ var meantime = "N/A";
+ if (podium[i].guessed !== 0) {
+ meantime = podium[i].totguesstime / podium[i].guessed;
+ meantime = (meantime / 1000).toFixed(1)+' s';
+ }
+ html += '<td>'+meantime+'</td></tr>';
+ }
+ }
- login.keyup(function(event) {
- if (event.keyCode === 13) {
- button.click();
- }
- });
+ html +='</tbody></table></div>';
+ html += '<div class="modal-footer align-left">A new game will start in ';
+ html += '<span></span> second/s</div>';
+ DOM.modal.append($(html));
+ DOM.modal.modal('show');
+ countDown(Date.now()+10000);
+ };
+
+ // Receive a chat message
+ var getChatMessage = function(chatmsg, from, to) {
+ if (ignoredplayers[from]) {
+ return;
+ }
+ var prefix = from;
+ var msgspan = $('<span class="message"></span>');
+ if (to) {
+ // Private Message
+ prefix = (nickname === from) ? '(To '+to+')' : '(From '+prefix+')';
+ msgspan.addClass('private');
+ }
+ var msg = prefix+': '+chatmsg;
+ msgspan.html(urlize(msg));
+ addChatEntry(msgspan);
+ };
+
+ var hideChat = function() {
+ DOM.togglechat.text('Show chat').unbind('click');
+ DOM.chatwrapper.toggle(300);
+ DOM.tracks.animate({maxHeight:'434px'}, 300);
+ DOM.togglechat.click(showChat);
+ };
+
+ // Put a player in the ignore list
+ var ignorePlayer = function(args, outcome) {
+ if (ignoredplayers[args[0]]) {
+ outcome.text('(From binb): '+args[0]+' is already ignored.');
+ return addChatEntry(outcome);
+ }
+ socket.emit('ignore', args[0], function(player) {
+ if (player) {
+ ignoredplayers[player] = true;
+ outcome.text('(From binb): '+player+' is now ignored.');
+ return addChatEntry(outcome);
+ }
+ outcome.append('player not found.');
+ addChatEntry(outcome);
+ });
+ };
+
+ // Submitted name was invalid
+ var invalidNickName = function(feedback) {
+ joinAnonymously(feedback+'<br/>Try with another one:');
+ };
+
+ // Prompt for name and send it
+ var joinAnonymously = function(msg) {
+ if (/nickname\s*\=/.test(document.cookie) && !msg) {
+ nickname = document.cookie.replace(/.*nickname\s*\=\s*([^;]*);?.*/, '$1');
+ return socket.emit('joinanonymously', nickname, roomname);
+ }
- DOM.modal.modal('show');
- DOM.modal.on('shown', function() {
- login.focus();
- });
- };
+ if (DOM.modal.hasClass('in')) {
+ $('.modal-body p').html(msg);
+ return $('#login').focus();
+ }
- var jplayerReady = function() {
- socket.emit('loggedin', function(data) {
- if (data) {
- nickname = data;
- subscriber = true;
- return socket.emit('joinroom', roomname);
- }
- joinAnonymously();
- });
- if (!$.jPlayer.platform.mobile && !$.jPlayer.platform.tablet) {
- return addVolumeControl();
- }
- var touchbackdrop = $('<div id="touch-backdrop">'+
- '<button id="touch-play" class="btn btn-danger disabled">'+
- '<i class="icon-play icon-white"></i> Wait'+
- '</button></div>').appendTo('#cassette');
- touchplay = $('#touch-play');
- touchplay.click(function() {
- if (!$(this).hasClass('btn-danger')) {
- touchplay = null;
- jplayer.jPlayer('play', elapsedtime);
- touchbackdrop.remove();
- }
- });
- };
+ var html = '<div class="modal-header">';
+ html += '<h3>You are joining the '+roomname+' room</h3></div>';
+ html += '<div class="modal-body"><p>'+(msg || "What's your name?")+'</p></div>';
+ html += '<div class="modal-footer relative">';
+ html += '<input id="login" maxlength="15" type="text" name="nickname" />';
+ html += '<button id="join" class="btn btn-success">';
+ html += '<i class="icon-user icon-white"></i> Join the game</button>';
+ html += '<span class="divider"><span>or</span></span>';
+ html += '<a class="btn btn-primary" href="/login?followup=/'+roomname+'">';
+ html += '<i class="icon-lock icon-white"></i> Login</a></div>';
+
+ $(html).appendTo(DOM.modal);
+ var login = $('#login');
+ var button = $('#join');
+
+ button.click(function() {
+ if ($.trim(login.val()) !== '') {
+ nickname = login.val();
+ socket.emit('joinanonymously', nickname, roomname);
+ }
+ else {
+ var txt = 'Nickname can\'t be empty.';
+ invalidNickName('<span class="label label-important">'+txt+'</span>');
+ }
+ login.val('');
+ });
- // Kick a player
- var kickPlayer = function(args, outcome) {
- outcome.append('you are not allowed to kick a player.');
- if (!subscriber) {
- return addChatEntry(outcome);
- }
- var why = args[1] || '';
- socket.emit('kick', args[0], why, function() {
- addChatEntry(outcome);
- });
- };
+ login.keyup(function(event) {
+ if (event.keyCode === 13) {
+ button.click();
+ }
+ });
- var loadTrack = function(previewUrl) {
- jplayer.jPlayer('mute');
- jplayer.jPlayer('setMedia', {m4a: previewUrl});
- };
+ DOM.modal.modal('show');
+ DOM.modal.on('shown', function() {
+ login.focus();
+ });
+ };
+
+ var jplayerReady = function() {
+ socket.emit('loggedin', function(data) {
+ if (data) {
+ nickname = data;
+ subscriber = true;
+ return socket.emit('joinroom', roomname);
+ }
+ joinAnonymously();
+ });
+ if (!$.jPlayer.platform.mobile && !$.jPlayer.platform.tablet) {
+ return addVolumeControl();
+ }
+ var touchbackdrop = $('<div id="touch-backdrop">'+
+ '<button id="touch-play" class="btn btn-danger disabled">'+
+ '<i class="icon-play icon-white"></i> Wait'+
+ '</button></div>').appendTo('#cassette');
+ touchplay = $('#touch-play');
+ touchplay.click(function() {
+ if (!$(this).hasClass('btn-danger')) {
+ touchplay = null;
+ jplayer.jPlayer('play', elapsedtime);
+ touchbackdrop.remove();
+ }
+ });
+ };
- /**
- * Given a string, parse the string extracting fields separated by whitespace
- * and optionally enclosed within double quotes (which are stripped off), and
- * build an array of copies of the string for each field.
- */
-
- var parseCommand = function(input) {
- var inquotes = false
- , token = ''
- , tokens = [];
- for (var i = 0; i < input.length; i++) {
- if (input[i] === '\\') {
- if (++i === input.length) {
- throw new Error('SyntaxError: Unexpected end of input');
- }
- if (input[i] === '\\' || input[i] === '"' || !inquotes) {
- token += input[i];
- continue;
- }
- token += '\\'+input[i];
- continue;
- }
- if (input[i] === '"') {
- inquotes = !inquotes;
- var j = i + 1;
- if (!inquotes && (input[j] === ' ' || j === input.length)) {
- tokens.push(token);
- token = '';
- i = j;
- }
- continue;
- }
- if (input[i] === ' ') {
- if (inquotes) {
- token += ' ';
- }
- else if (token.length) {
- tokens.push(token);
- token = '';
- }
- continue;
- }
- token += input[i];
- }
+ // Kick a player
+ var kickPlayer = function(args, outcome) {
+ outcome.append('you are not allowed to kick a player.');
+ if (!subscriber) {
+ return addChatEntry(outcome);
+ }
+ var why = args[1] || '';
+ socket.emit('kick', args[0], why, function() {
+ addChatEntry(outcome);
+ });
+ };
+
+ var loadTrack = function(previewUrl) {
+ jplayer.jPlayer('mute');
+ jplayer.jPlayer('setMedia', {m4a: previewUrl});
+ };
+
+ /**
+ * Given a string, parse the string extracting fields separated by whitespace
+ * and optionally enclosed within double quotes (which are stripped off), and
+ * build an array of copies of the string for each field.
+ */
+
+ var parseCommand = function(input) {
+ var inquotes = false
+ , token = ''
+ , tokens = [];
+ for (var i = 0; i < input.length; i++) {
+ if (input[i] === '\\') {
+ if (++i === input.length) {
+ throw new Error('SyntaxError: Unexpected end of input');
+ }
+ if (input[i] === '\\' || input[i] === '"' || !inquotes) {
+ token += input[i];
+ continue;
+ }
+ token += '\\'+input[i];
+ continue;
+ }
+ if (input[i] === '"') {
+ inquotes = !inquotes;
+ var j = i + 1;
+ if (!inquotes && (input[j] === ' ' || j === input.length)) {
+ tokens.push(token);
+ token = '';
+ i = j;
+ }
+ continue;
+ }
+ if (input[i] === ' ') {
if (inquotes) {
- throw new Error('SyntaxError: Unexpected end of input');
- }
- if (token.length) {
- tokens.push(token);
- }
- return tokens;
- };
-
- // Play a track
- var playTrack = function(data) {
- if (touchplay) {
- touchplay.removeClass('btn-danger disabled').addClass('btn-success');
- touchplay.html('<i class="icon-play icon-white"></i> Play');
- }
- jplayer.jPlayer('unmute');
- jplayer.jPlayer('play');
- updateUsers(data.users);
- cassetteAnimation(Date.now()+30000, true);
- if (data.counter === 1) {
- DOM.modal.modal('hide').empty();
- DOM.tracks.empty();
- }
- DOM.track.text(data.counter+'/'+data.tot);
- addFeedback('What is this song?');
- };
-
- // Successfully joined the room
- var ready = function(usersData, trackscount, loggedin) {
- if (!loggedin && !/nickname\s*\=/.test(document.cookie)) {
- document.cookie = 'nickname='+nickname+';path=/;';
- }
-
- DOM.modal.modal('hide').empty();
- $('#total-tracks span').text(trackscount);
- var msg = nickname+' joined the game';
- var joinspan = $('<span class="join"></span>');
- joinspan.text(msg);
- addChatEntry(joinspan);
- updateUsers(usersData);
-
- DOM.messagebox.keydown(function(event) {
- if (event.keyCode === 13) {
- var val = $.trim(DOM.messagebox.val());
- if (val !== '') {
- if (pvtmsgto) {
- socket.emit('sendchatmsg', val, pvtmsgto);
- }
- else if (/^\/[^ ]/.test(val)) {
- slashCommandHandler(val);
- }
- else {
- socket.emit('sendchatmsg', val);
- }
- }
- DOM.messagebox.val('');
- }
- });
-
- DOM.guessbox.keydown(function(event) {
- switch (event.keyCode) {
- case 13: // return
- var guess = $.trim(DOM.guessbox.val());
- if (guess !== '') {
- socket.emit('guess', guess.toLowerCase());
- historyvalues.push(guess);
- if (historyvalues.length > 20) {
- historyvalues.splice(0, 1);
- }
- historycursor = historyvalues.length;
- }
- DOM.guessbox.val('');
- break;
- case 38: // up-arrow
- if (historycursor > 0) {
- DOM.guessbox.val(historyvalues[--historycursor]);
- }
- break;
- case 40: // down-arrow
- if (historycursor < historyvalues.length - 1) {
- DOM.guessbox.val(historyvalues[++historycursor]);
- }
- else {
- historycursor = historyvalues.length;
- DOM.guessbox.val('');
- }
- }
- });
-
- DOM.guessbox.focus();
-
- socket.on('artistmatched', function() {
- addFeedback(amstrings[Math.floor(Math.random()*amstrings.length)], 'correct');
- });
- socket.on('bothmatched', function() {
- addFeedback(bmstrings[Math.floor(Math.random()*bmstrings.length)], 'correct');
- });
- socket.on('chatmsg', getChatMessage);
- socket.on('gameover', gameOver);
- socket.on('loadtrack', loadTrack);
- socket.on('newuser', userJoin);
- socket.on('noguesstime', function() {
- addFeedback('You have to wait the next song...');
- });
- socket.on('nomatch', function() {
- addFeedback(nmstrings[Math.floor(Math.random()*nmstrings.length)], 'wrong');
- });
- socket.on('playtrack', playTrack);
- socket.on('stoptrying', function() {
- addFeedback('You guessed both artist and title. Please wait...');
- });
- socket.on('titlematched', function() {
- addFeedback(tmstrings[Math.floor(Math.random()*tmstrings.length)], 'correct');
- });
- socket.on('trackinfo', addTrackInfo);
- socket.on('updateusers', updateUsers);
- socket.on('userleft', userLeft);
- socket.emit('getstatus', setStatus);
- };
-
- // Show the number of players inside each room
- var roomsOverview = function(data) {
- for (var prop in data) {
- if (prop !== roomname) {
- DOM.userscounters[prop].text(data[prop]);
- }
- }
- };
-
- var setStatus = function(data) {
- if (data.status === 0) {
- cassetteAnimation(Date.now()+data.timeleft, true);
+ token += ' ';
}
- else if (data.status === 1) {
- loadTrack(data.previewUrl);
+ else if (token.length) {
+ tokens.push(token);
+ token = '';
}
- addFeedback(states[data.status]);
- };
-
- var setVariables = function() {
- DOM.cassettewheels = $('#cassette .wheel');
- DOM.chat = $('#chat');
- DOM.chatwrapper = $('#chat-outer-wrapper');
- DOM.countdown = $('#countdown');
- DOM.feedback = $('#feedback');
- DOM.guessbox = $('#guess');
- DOM.messagebox = $('#message');
- DOM.modal = $('#modal');
- DOM.points = $('#summary .points');
- DOM.progress = $('#progress');
- DOM.rank = $('#summary .rank');
- DOM.recipient = $('#recipient');
- DOM.tapeleft = $('#tape-left');
- DOM.taperight = $('#tape-right');
- DOM.togglechat = $('#toggle-chat');
- DOM.track = $('#summary .track');
- DOM.tracks = $('#tracks');
- DOM.users = $('#users');
- DOM.userscounters = {};
- $('.users-counter').each(function() {
- DOM.userscounters[$(this).prevAll('.room-name').text()] = $(this);
- });
- };
-
- var showChat = function() {
- DOM.togglechat.text('Hide chat').unbind('click');
- DOM.chatwrapper.toggle(300);
- DOM.tracks.animate({maxHeight:'240px'}, 300, function() {
- DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight;
- });
- DOM.togglechat.click(hideChat);
- };
-
- var slashCommandHandler = function(line) {
- var args;
- var outcome = $('<span class="message private">(From binb): </span>');
+ continue;
+ }
+ token += input[i];
+ }
+ if (inquotes) {
+ throw new Error('SyntaxError: Unexpected end of input');
+ }
+ if (token.length) {
+ tokens.push(token);
+ }
+ return tokens;
+ };
+
+ // Play a track
+ var playTrack = function(data) {
+ if (touchplay) {
+ touchplay.removeClass('btn-danger disabled').addClass('btn-success');
+ touchplay.html('<i class="icon-play icon-white"></i> Play');
+ }
+ jplayer.jPlayer('unmute');
+ jplayer.jPlayer('play');
+ updateUsers(data.users);
+ cassetteAnimation(Date.now()+30000, true);
+ if (data.counter === 1) {
+ DOM.modal.modal('hide').empty();
+ DOM.tracks.empty();
+ }
+ DOM.track.text(data.counter+'/'+data.tot);
+ addFeedback('What is this song?');
+ };
+
+ // Successfully joined the room
+ var ready = function(usersData, trackscount, loggedin) {
+ if (!loggedin && !/nickname\s*\=/.test(document.cookie)) {
+ document.cookie = 'nickname='+nickname+';path=/;';
+ }
- try {
- args = parseCommand(line);
- }
- catch (err) {
- outcome.append(err.message);
- return addChatEntry(outcome);
- }
+ DOM.modal.modal('hide').empty();
+ $('#total-tracks span').text(trackscount);
+ var msg = nickname+' joined the game';
+ var joinspan = $('<span class="join"></span>');
+ joinspan.text(msg);
+ addChatEntry(joinspan);
+ updateUsers(usersData);
+
+ DOM.messagebox.keydown(function(event) {
+ if (event.keyCode === 13) {
+ var val = $.trim(DOM.messagebox.val());
+ if (val !== '') {
+ if (pvtmsgto) {
+ socket.emit('sendchatmsg', val, pvtmsgto);
+ }
+ else if (/^\/[^ ]/.test(val)) {
+ slashCommandHandler(val);
+ }
+ else {
+ socket.emit('sendchatmsg', val);
+ }
+ }
+ DOM.messagebox.val('');
+ }
+ });
- var cmdname = args.shift();
- var command = slashcommands[cmdname.substr(1)];
+ DOM.guessbox.keydown(function(event) {
+ switch (event.keyCode) {
+ case 13: // return
+ var guess = $.trim(DOM.guessbox.val());
+ if (guess !== '') {
+ socket.emit('guess', guess.toLowerCase());
+ historyvalues.push(guess);
+ if (historyvalues.length > 20) {
+ historyvalues.splice(0, 1);
+ }
+ historycursor = historyvalues.length;
+ }
+ DOM.guessbox.val('');
+ break;
+ case 38: // up-arrow
+ if (historycursor > 0) {
+ DOM.guessbox.val(historyvalues[--historycursor]);
+ }
+ break;
+ case 40: // down-arrow
+ if (historycursor < historyvalues.length - 1) {
+ DOM.guessbox.val(historyvalues[++historycursor]);
+ }
+ else {
+ historycursor = historyvalues.length;
+ DOM.guessbox.val('');
+ }
+ }
+ });
- if (command) {
- if (args.length < command.minargs) {
- outcome.append(command.usage);
- return addChatEntry(outcome);
- }
- if (command.checkrecipient && (!args[0] || args[0] === nickname)) {
- outcome.append('invalid argument.');
- return addChatEntry(outcome);
- }
- return command.fn(args, outcome);
- }
+ DOM.guessbox.focus();
- outcome.text('(From binb): unknown command '+cmdname+'.');
- addChatEntry(outcome);
- };
+ socket.on('artistmatched', function() {
+ addFeedback(amstrings[Math.floor(Math.random()*amstrings.length)], 'correct');
+ });
+ socket.on('bothmatched', function() {
+ addFeedback(bmstrings[Math.floor(Math.random()*bmstrings.length)], 'correct');
+ });
+ socket.on('chatmsg', getChatMessage);
+ socket.on('gameover', gameOver);
+ socket.on('loadtrack', loadTrack);
+ socket.on('newuser', userJoin);
+ socket.on('noguesstime', function() {
+ addFeedback('You have to wait the next song...');
+ });
+ socket.on('nomatch', function() {
+ addFeedback(nmstrings[Math.floor(Math.random()*nmstrings.length)], 'wrong');
+ });
+ socket.on('playtrack', playTrack);
+ socket.on('stoptrying', function() {
+ addFeedback('You guessed both artist and title. Please wait...');
+ });
+ socket.on('titlematched', function() {
+ addFeedback(tmstrings[Math.floor(Math.random()*tmstrings.length)], 'correct');
+ });
+ socket.on('trackinfo', addTrackInfo);
+ socket.on('updateusers', updateUsers);
+ socket.on('userleft', userLeft);
+ socket.emit('getstatus', setStatus);
+ };
+
+ // Show the number of players inside each room
+ var roomsOverview = function(data) {
+ for (var prop in data) {
+ if (prop !== roomname) {
+ DOM.userscounters[prop].text(data[prop]);
+ }
+ }
+ };
- // Remove a player from the ignore list
- var unignorePlayer = function(args, outcome) {
- if (!ignoredplayers[args[0]]) {
- outcome.text('(From binb): you have not ignored '+args[0]+'.');
- return addChatEntry(outcome);
- }
- delete ignoredplayers[args[0]];
- socket.emit('unignore', args[0]);
- outcome.text('(From binb): '+args[0]+' is no longer ignored.');
- addChatEntry(outcome);
- };
+ var setStatus = function(data) {
+ if (data.status === 0) {
+ cassetteAnimation(Date.now()+data.timeleft, true);
+ }
+ else if (data.status === 1) {
+ loadTrack(data.previewUrl);
+ }
+ addFeedback(states[data.status]);
+ };
+
+ var setVariables = function() {
+ DOM.cassettewheels = $('#cassette .wheel');
+ DOM.chat = $('#chat');
+ DOM.chatwrapper = $('#chat-outer-wrapper');
+ DOM.countdown = $('#countdown');
+ DOM.feedback = $('#feedback');
+ DOM.guessbox = $('#guess');
+ DOM.messagebox = $('#message');
+ DOM.modal = $('#modal');
+ DOM.points = $('#summary .points');
+ DOM.progress = $('#progress');
+ DOM.rank = $('#summary .rank');
+ DOM.recipient = $('#recipient');
+ DOM.tapeleft = $('#tape-left');
+ DOM.taperight = $('#tape-right');
+ DOM.togglechat = $('#toggle-chat');
+ DOM.track = $('#summary .track');
+ DOM.tracks = $('#tracks');
+ DOM.users = $('#users');
+ DOM.userscounters = {};
+ $('.users-counter').each(function() {
+ DOM.userscounters[$(this).prevAll('.room-name').text()] = $(this);
+ });
+ };
- // Update the list of players
- var updateUsers = function(usersData) {
- DOM.users.empty();
+ var showChat = function() {
+ DOM.togglechat.text('Hide chat').unbind('click');
+ DOM.chatwrapper.toggle(300);
+ DOM.tracks.animate({maxHeight:'240px'}, 300, function() {
+ DOM.chat[0].scrollTop = DOM.chat[0].scrollHeight;
+ });
+ DOM.togglechat.click(hideChat);
+ };
- var users = [];
- for (var key in usersData) {
- users.push(usersData[key]);
- }
- users.sort(function(a, b) {return b.points - a.points;});
-
- // Flag to test if our private recipient is in the list of active users
- var found = false;
- for (var i=0; i<users.length; i++) {
- var user = users[i]
- , li = $('<li></li>')
- , pvt = $('<span class="private label label-info">P</span>')
- , username = $('<span class="name"></span>').text(user.nickname)
- , points = $('<span class="points">('+user.points+')</span>')
- , roundrank = $('<span></span>')
- , roundpointsel = $('<span class="round-points"></span>')
- , guesstime = $('<span class="guess-time"></span>');
-
- li.append(pvt, username, points, roundrank, roundpointsel, guesstime);
- if (user.registered) {
- var href = 'href="/user/'+user.nickname+'"';
- pvt.after('<a class="icons registered" target="_blank" '+href+'></a>');
- }
- DOM.users.append(li);
+ var slashCommandHandler = function(line) {
+ var args;
+ var outcome = $('<span class="message private">(From binb): </span>');
- if (pvtmsgto === user.nickname) {
- pvt.show();
- username.click(clearPrivate);
- found = true;
- }
- else {
- username.click(function() {
- addPrivate($(this).text());
- });
- }
+ try {
+ args = parseCommand(line);
+ }
+ catch (err) {
+ outcome.append(err.message);
+ return addChatEntry(outcome);
+ }
- if (nickname === user.nickname) {
- username.addClass('you');
- roundpoints = user.roundpoints;
- DOM.rank.text(i+1);
- DOM.points.text(user.points);
- }
+ var cmdname = args.shift();
+ var command = slashcommands[cmdname.substr(1)];
+
+ if (command) {
+ if (args.length < command.minargs) {
+ outcome.append(command.usage);
+ return addChatEntry(outcome);
+ }
+ if (command.checkrecipient && (!args[0] || args[0] === nickname)) {
+ outcome.append('invalid argument.');
+ return addChatEntry(outcome);
+ }
+ return command.fn(args, outcome);
+ }
- if (user.roundpoints > 0) {
- roundpointsel.text('+'+user.roundpoints);
- if (user.roundpoints === 1) {
- username.addClass('matched');
- }
- else {
- if (user.roundpoints > 3) {
- var stand = 7 - user.roundpoints;
- roundrank.addClass('icons round-rank stand'+stand);
- var gtime = (user.guesstime / 1000).toFixed(1);
- guesstime.text(gtime+' s');
- }
- username.addClass('correct');
- }
- }
- }
+ outcome.text('(From binb): unknown command '+cmdname+'.');
+ addChatEntry(outcome);
+ };
- if (!found && pvtmsgto) {
- var width = DOM.recipient.outerWidth(true) + 1;
- DOM.recipient.css('margin-right', '0');
- DOM.recipient.text('');
- DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast');
- pvtmsgto = null;
- DOM.messagebox.focus();
- }
- };
+ // Remove a player from the ignore list
+ var unignorePlayer = function(args, outcome) {
+ if (!ignoredplayers[args[0]]) {
+ outcome.text('(From binb): you have not ignored '+args[0]+'.');
+ return addChatEntry(outcome);
+ }
+ delete ignoredplayers[args[0]];
+ socket.emit('unignore', args[0]);
+ outcome.text('(From binb): '+args[0]+' is no longer ignored.');
+ addChatEntry(outcome);
+ };
+
+ // Update the list of players
+ var updateUsers = function(usersData) {
+ DOM.users.empty();
+
+ var users = [];
+ for (var key in usersData) {
+ users.push(usersData[key]);
+ }
+ users.sort(function(a, b) {return b.points - a.points;});
+
+ // Flag to test if our private recipient is in the list of active users
+ var found = false;
+ for (var i=0; i<users.length; i++) {
+ var user = users[i]
+ , li = $('<li></li>')
+ , pvt = $('<span class="private label label-info">P</span>')
+ , username = $('<span class="name"></span>').text(user.nickname)
+ , points = $('<span class="points">('+user.points+')</span>')
+ , roundrank = $('<span></span>')
+ , roundpointsel = $('<span class="round-points"></span>')
+ , guesstime = $('<span class="guess-time"></span>');
+
+ li.append(pvt, username, points, roundrank, roundpointsel, guesstime);
+ if (user.registered) {
+ var href = 'href="/user/'+user.nickname+'"';
+ pvt.after('<a class="icons registered" target="_blank" '+href+'></a>');
+ }
+ DOM.users.append(li);
+
+ if (pvtmsgto === user.nickname) {
+ pvt.show();
+ username.click(clearPrivate);
+ found = true;
+ }
+ else {
+ username.click(function() {
+ addPrivate($(this).text());
+ });
+ }
- var updateRoomsOverview = function(room, players) {
- if (room !== roomname) {
- DOM.userscounters[room].text(players);
- }
- };
+ if (nickname === user.nickname) {
+ username.addClass('you');
+ roundpoints = user.roundpoints;
+ DOM.rank.text(i+1);
+ DOM.points.text(user.points);
+ }
- // Convert any URLs in text into clickable links
- var urlize = function(text) {
- if (urlregex.test(text)) {
- var html = '';
- var splits = text.split(urlregex);
- for (var i=0; i<splits.length; i++) {
- var escapedsplit = splits[i].encodeEntities();
- if (urlregex.test(splits[i])) {
- html += '<a target="_blank" href="'+escapedsplit+'">'+escapedsplit+'</a>';
- continue;
- }
- html += escapedsplit;
- }
- return html;
+ if (user.roundpoints > 0) {
+ roundpointsel.text('+'+user.roundpoints);
+ if (user.roundpoints === 1) {
+ username.addClass('matched');
}
- return text.encodeEntities();
- };
-
- // A new player has joined the game
- var userJoin = function(username, usersData) {
- var joinmsg = username+' joined the game';
- var joinspan = $('<span class="join"></span>');
- joinspan.text(joinmsg);
- addChatEntry(joinspan);
- updateUsers(usersData);
- };
-
- // A player has left the game
- var userLeft = function(username, usersData) {
- var leftmsg = username+' left the game';
- var leftspan = $('<span class="left"></span>');
- leftspan.text(leftmsg);
- addChatEntry(leftspan);
- updateUsers(usersData);
- };
+ else {
+ if (user.roundpoints > 3) {
+ var stand = 7 - user.roundpoints;
+ roundrank.addClass('icons round-rank stand'+stand);
+ var gtime = (user.guesstime / 1000).toFixed(1);
+ guesstime.text(gtime+' s');
+ }
+ username.addClass('correct');
+ }
+ }
+ }
- var slashcommands = {
- ignore: {
- checkrecipient: true, // Assume that the first argument (argv[0]) is the recipient
- fn: ignorePlayer,
- minargs: 1,
- usage: 'usage: /ignore <player name>'
- },
- kick: {
- checkrecipient: true,
- fn: kickPlayer,
- minargs: 1,
- usage: 'usage: /kick <player name> [message]'
- },
- unignore: {
- checkrecipient: true,
- fn: unignorePlayer,
- minargs: 1,
- usage: 'usage: /unignore <player name>'
- }
- };
+ if (!found && pvtmsgto) {
+ var width = DOM.recipient.outerWidth(true) + 1;
+ DOM.recipient.css('margin-right', '0');
+ DOM.recipient.text('');
+ DOM.messagebox.animate({'width':'+='+width+'px'}, 'fast');
+ pvtmsgto = null;
+ DOM.messagebox.focus();
+ }
+ };
- // Set up the app
- setVariables();
- DOM.modal.modal({keyboard:false, show:false, backdrop:'static'});
- DOM.togglechat.click(hideChat);
- if ($.browser.mozilla) {
- // Block ESC button in firefox (breaks socket connections)
- $(document).keypress(function(event) {
- if(event.keyCode === 27) {
- return false;
- }
- });
+ var updateRoomsOverview = function(room, players) {
+ if (room !== roomname) {
+ DOM.userscounters[room].text(players);
}
- socket = io.connect(uri, {'reconnect':false});
- socket.on('connect', function() {
- jplayer = $('#player').jPlayer({
- ready: jplayerReady,
- swfPath: '/static/swf/',
- supplied: 'm4a',
- preload: 'auto',
- volume: 1
- });
- socket.on('alreadyinaroom', alreadyInARoom);
- socket.on('disconnect', disconnect);
- socket.on('invalidnickname', invalidNickName);
- socket.on('ready', ready);
- socket.on('updateoverview', updateRoomsOverview);
- socket.emit('getoverview', roomsOverview);
+ };
+
+ // Convert any URLs in text into clickable links
+ var urlize = function(text) {
+ if (urlregex.test(text)) {
+ var html = '';
+ var splits = text.split(urlregex);
+ for (var i=0; i<splits.length; i++) {
+ var escapedsplit = splits[i].encodeEntities();
+ if (urlregex.test(splits[i])) {
+ html += '<a target="_blank" href="'+escapedsplit+'">'+escapedsplit+'</a>';
+ continue;
+ }
+ html += escapedsplit;
+ }
+ return html;
+ }
+ return text.encodeEntities();
+ };
+
+ // A new player has joined the game
+ var userJoin = function(username, usersData) {
+ var joinmsg = username+' joined the game';
+ var joinspan = $('<span class="join"></span>');
+ joinspan.text(joinmsg);
+ addChatEntry(joinspan);
+ updateUsers(usersData);
+ };
+
+ // A player has left the game
+ var userLeft = function(username, usersData) {
+ var leftmsg = username+' left the game';
+ var leftspan = $('<span class="left"></span>');
+ leftspan.text(leftmsg);
+ addChatEntry(leftspan);
+ updateUsers(usersData);
+ };
+
+ var slashcommands = {
+ ignore: {
+ checkrecipient: true, // Assume that the first argument (argv[0]) is the recipient
+ fn: ignorePlayer,
+ minargs: 1,
+ usage: 'usage: /ignore <player name>'
+ },
+ kick: {
+ checkrecipient: true,
+ fn: kickPlayer,
+ minargs: 1,
+ usage: 'usage: /kick <player name> [message]'
+ },
+ unignore: {
+ checkrecipient: true,
+ fn: unignorePlayer,
+ minargs: 1,
+ usage: 'usage: /unignore <player name>'
+ }
+ };
+
+ // Set up the app
+ setVariables();
+ DOM.modal.modal({keyboard:false, show:false, backdrop:'static'});
+ DOM.togglechat.click(hideChat);
+ if ($.browser.mozilla) {
+ // Block ESC button in firefox (breaks socket connections)
+ $(document).keypress(function(event) {
+ if(event.keyCode === 27) {
+ return false;
+ }
+ });
+ }
+ socket = io.connect(uri, {'reconnect':false});
+ socket.on('connect', function() {
+ jplayer = $('#player').jPlayer({
+ ready: jplayerReady,
+ swfPath: '/static/swf/',
+ supplied: 'm4a',
+ preload: 'auto',
+ volume: 1
});
+ socket.on('alreadyinaroom', alreadyInARoom);
+ socket.on('disconnect', disconnect);
+ socket.on('invalidnickname', invalidNickName);
+ socket.on('ready', ready);
+ socket.on('updateoverview', updateRoomsOverview);
+ socket.emit('getoverview', roomsOverview);
+ });
})();
(function() {
- if ($.browser.mozilla) {
- // Block ESC button in firefox (breaks socket connections).
- $(document).keypress(function(event) {
- if(event.keyCode === 27) {
- return false;
- }
- });
- }
- $.get('/artworks', function(data) {
- $('.thumbnail').each(function(index) {
- var i = index * 6;
- var j = i + 6;
- for(i; i < j; i++) {
- $('<img src="'+data.results[i]+'" />').appendTo($(this));
- }
- });
+ if ($.browser.mozilla) {
+ // Block ESC button in firefox (breaks socket connections).
+ $(document).keypress(function(event) {
+ if(event.keyCode === 27) {
+ return false;
+ }
});
- var uri = window.location.protocol+'//'+window.location.host;
- var socket = io.connect(uri, {'reconnect':false});
- socket.on('connect', function() {
- socket.emit('getoverview', function(data) {
- for (var prop in data) {
- $('#'+prop).text(data[prop]);
- }
- });
- socket.on('updateoverview', function(room, players) {
- $('#'+room).text(players);
- });
+ }
+ $.get('/artworks', function(data) {
+ $('.thumbnail').each(function(index) {
+ var i = index * 6;
+ var j = i + 6;
+ for(i; i < j; i++) {
+ $('<img src="'+data.results[i]+'" />').appendTo($(this));
+ }
});
+ });
+ var uri = window.location.protocol+'//'+window.location.host;
+ var socket = io.connect(uri, {'reconnect':false});
+ socket.on('connect', function() {
+ socket.emit('getoverview', function(data) {
+ for (var prop in data) {
+ $('#'+prop).text(data[prop]);
+ }
+ });
+ socket.on('updateoverview', function(room, players) {
+ $('#'+room).text(players);
+ });
+ });
})();
(function() {
- var appendResults = function(data, leaderboard, offset, type) {
- for (var i=0; i<data.length; i+=2) {
- var link = $('<a href="/user/'+data[i]+'"></a>').text(data[i])
- , col1 = '<td>'+(++offset)+'</td>'
- , col2 = $('<td></td>').append(link)
- , col3 = (type === 'points')
- ? '<td>'+data[i+1]+'</td>'
- : '<td><i class="icon-time"></i> '+(data[i+1] / 1000).toFixed(2)+' sec</td>';
- var row = $('<tr></tr>').append(col1, col2, col3);
- leaderboard.append(row);
- }
- };
+ var appendResults = function(data, leaderboard, offset, type) {
+ for (var i=0; i<data.length; i+=2) {
+ var link = $('<a href="/user/'+data[i]+'"></a>').text(data[i])
+ , col1 = '<td>'+(++offset)+'</td>'
+ , col2 = $('<td></td>').append(link)
+ , col3 = (type === 'points')
+ ? '<td>'+data[i+1]+'</td>'
+ : '<td><i class="icon-time"></i> '+(data[i+1] / 1000).toFixed(2)+' sec</td>';
+ var row = $('<tr></tr>').append(col1, col2, col3);
+ leaderboard.append(row);
+ }
+ };
- $('.leaderboard-wrapper').each(function(index) {
- var leaderboard = $(this).find('tbody')
- , loading = $(this).find('.loading')
- , offset = 0
- , type = (index === 0) ? 'points' : 'times';
+ $('.leaderboard-wrapper').each(function(index) {
+ var leaderboard = $(this).find('tbody')
+ , loading = $(this).find('.loading')
+ , offset = 0
+ , type = (index === 0) ? 'points' : 'times';
- $(this).scroll(function() {
- var diff = $(this).prop('scrollHeight') - $(this).scrollTop();
- if (diff === $(this).height() && offset < 180) {
- offset += 30;
- loading.show();
- $.get('/sliceleaderboard', {begin: offset, by: type}, function(data) {
- loading.hide();
- appendResults(data, leaderboard, offset, type);
- });
- }
+ $(this).scroll(function() {
+ var diff = $(this).prop('scrollHeight') - $(this).scrollTop();
+ if (diff === $(this).height() && offset < 180) {
+ offset += 30;
+ loading.show();
+ $.get('/sliceleaderboard', {begin: offset, by: type}, function(data) {
+ loading.hide();
+ appendResults(data, leaderboard, offset, type);
});
+ }
});
+ });
})();
*/
var async = require('async')
- , Captcha = require('../lib/captcha')
- , db = require('../lib/redis-clients').songs
- , randomSlogan = require('../lib/utils').randomSlogan
- , rooms = require('../config').rooms;
+ , Captcha = require('../lib/captcha')
+ , db = require('../lib/redis-clients').songs
+ , randomSlogan = require('../lib/utils').randomSlogan
+ , rooms = require('../config').rooms;
/**
* Generate a task.
*/
var task = function(genre) {
- return function(callback) {
- db.srandmember(genre, function(err, res) {
- db.hget('song:'+res, 'artworkUrl100', callback);
- });
- };
+ return function(callback) {
+ db.srandmember(genre, function(err, res) {
+ db.hget('song:'+res, 'artworkUrl100', callback);
+ });
+ };
};
/**
*/
exports.artworks = function(req, res) {
- var tasks = [];
- for (var i=0; i<rooms.length; i++) {
- for (var j=0; j<6; j++) {
- tasks.push(task(rooms[i]));
- }
+ var tasks = [];
+ for (var i=0; i<rooms.length; i++) {
+ for (var j=0; j<6; j++) {
+ tasks.push(task(rooms[i]));
}
- async.parallel(tasks, function(err, results) {
- var obj = {
- resultCount: results.length,
- results: results
- };
- res.json(obj);
- });
+ }
+ async.parallel(tasks, function(err, results) {
+ var obj = {
+ resultCount: results.length,
+ results: results
+ };
+ res.json(obj);
+ });
};
exports.changePasswd = function(req, res) {
- if (!req.session.user) {
- return res.redirect('/login?followup=/changepasswd');
- }
- res.render('changepasswd', {
- followup: req.query.followup || '/',
- loggedin: req.session.user,
- slogan: randomSlogan()
- });
+ if (!req.session.user) {
+ return res.redirect('/login?followup=/changepasswd');
+ }
+ res.render('changepasswd', {
+ followup: req.query.followup || '/',
+ loggedin: req.session.user,
+ slogan: randomSlogan()
+ });
};
exports.home = function(req, res) {
- res.render('home', {
- loggedin: req.session.user,
- rooms: rooms,
- slogan: randomSlogan()
- });
+ res.render('home', {
+ loggedin: req.session.user,
+ rooms: rooms,
+ slogan: randomSlogan()
+ });
};
exports.login = function(req, res) {
- res.render('login', {
- followup: req.query.followup || '/',
- slogan: randomSlogan()
- });
+ res.render('login', {
+ followup: req.query.followup || '/',
+ slogan: randomSlogan()
+ });
};
exports.recoverPasswd = function(req, res) {
- var captcha = new Captcha();
- req.session.captchacode = captcha.getCode();
- res.render('recoverpasswd', {
- captchaurl: captcha.toDataURL(),
- followup: req.query.followup || '/',
- slogan: randomSlogan()
- });
+ var captcha = new Captcha();
+ req.session.captchacode = captcha.getCode();
+ res.render('recoverpasswd', {
+ captchaurl: captcha.toDataURL(),
+ followup: req.query.followup || '/',
+ slogan: randomSlogan()
+ });
};
exports.resetPasswd = function(req, res) {
- res.render('resetpasswd', {
- slogan: randomSlogan(),
- token: req.query.token || ''
- });
+ res.render('resetpasswd', {
+ slogan: randomSlogan(),
+ token: req.query.token || ''
+ });
};
exports.room = function(req, res) {
- if (~rooms.indexOf(req.params.room)) {
- return res.render('room', {
- loggedin: req.session.user,
- roomname: req.params.room,
- rooms: rooms,
- slogan: randomSlogan()
- });
- }
- res.send(404);
+ if (~rooms.indexOf(req.params.room)) {
+ return res.render('room', {
+ loggedin: req.session.user,
+ roomname: req.params.room,
+ rooms: rooms,
+ slogan: randomSlogan()
+ });
+ }
+ res.send(404);
};
exports.signup = function(req, res) {
- var captcha = new Captcha();
- req.session.captchacode = captcha.getCode();
- res.render('signup', {
- captchaurl: captcha.toDataURL(),
- followup: req.query.followup || '/',
- slogan: randomSlogan()
- });
+ var captcha = new Captcha();
+ req.session.captchacode = captcha.getCode();
+ res.render('signup', {
+ captchaurl: captcha.toDataURL(),
+ followup: req.query.followup || '/',
+ slogan: randomSlogan()
+ });
};
/**
*/
exports.validationErrors = function(req, res, next) {
- res.locals.errors = req.session.errors;
- res.locals.oldvalues = req.session.oldvalues;
- delete req.session.errors;
- delete req.session.oldvalues;
- next();
+ res.locals.errors = req.session.errors;
+ res.locals.oldvalues = req.session.oldvalues;
+ delete req.session.errors;
+ delete req.session.oldvalues;
+ next();
};
*/
var crypto = require('crypto')
- , db = require('../lib/redis-clients').users
- , mailer = require('../lib/email/mailer')
- , rooms = require('../config').rooms
- , User = require('../lib/user')
- , utils = require('../lib/utils');
+ , db = require('../lib/redis-clients').users
+ , mailer = require('../lib/email/mailer')
+ , rooms = require('../config').rooms
+ , User = require('../lib/user')
+ , 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]);
+ safeurls.push('/'+rooms[i]);
}
/**
*/
exports.leaderboards = function(req, res) {
- db.zrevrange('users', 0, 29, 'withscores', function(err, pointsresults) {
- db.sort(utils.sortParams(0), function(e, timesresults) {
- var leaderboards = utils.buildLeaderboards(pointsresults, timesresults);
- res.locals.slogan = utils.randomSlogan();
- res.render('leaderboards', leaderboards);
- });
+ db.zrevrange('users', 0, 29, 'withscores', function(err, pointsresults) {
+ db.sort(utils.sortParams(0), function(e, timesresults) {
+ var leaderboards = utils.buildLeaderboards(pointsresults, timesresults);
+ res.locals.slogan = utils.randomSlogan();
+ res.render('leaderboards', leaderboards);
});
+ });
};
/**
*/
exports.sliceLeaderboard = function(req, res) {
- var begin = parseInt(req.query.begin, 10)
- , by = req.query.by;
- if (isNaN(begin) || begin > 180 || (by !== 'points' && by !== 'times')) {
- return res.send(412);
- }
- var end = begin + 29;
- if (by === 'points') {
- db.zrevrange('users', begin, end, 'withscores', function(err, results) {
- res.json(results);
- });
- return;
- }
- db.sort(utils.sortParams(begin), function(err, results) {
- res.json(results);
+ var begin = parseInt(req.query.begin, 10)
+ , by = req.query.by;
+ if (isNaN(begin) || begin > 180 || (by !== 'points' && by !== 'times')) {
+ return res.send(412);
+ }
+ var end = begin + 29;
+ if (by === 'points') {
+ db.zrevrange('users', begin, end, 'withscores', function(err, results) {
+ res.json(results);
});
+ return;
+ }
+ db.sort(utils.sortParams(begin), function(err, results) {
+ res.json(results);
+ });
};
/**
*/
exports.validateChangePasswd = function(req, res, next) {
- if (!req.session.user || req.body.oldpassword === undefined ||
- req.body.newpassword === undefined) {
- return res.send(412);
- }
-
- var errors = {};
-
- if (req.body.oldpassword.trim() === '') {
- errors.oldpassword = "can't be empty";
- }
- 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";
- }
-
- if (errors.oldpassword || errors.newpassword) {
- req.session.errors = errors;
- return res.redirect(req.url);
- }
-
- next();
+ if (!req.session.user || req.body.oldpassword === undefined ||
+ req.body.newpassword === undefined) {
+ return res.send(412);
+ }
+
+ var errors = {};
+
+ if (req.body.oldpassword.trim() === '') {
+ errors.oldpassword = "can't be empty";
+ }
+ 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";
+ }
+
+ if (errors.oldpassword || errors.newpassword) {
+ req.session.errors = errors;
+ return res.redirect(req.url);
+ }
+
+ next();
};
exports.checkOldPasswd = function(req, res, next) {
- var key = 'user:'+req.session.user;
- db.hmget(key, 'salt', 'password', function(err, data) {
- var hash = crypto.createHash('sha256').update(data[0]+req.body.oldpassword).digest('hex');
- if (hash !== data[1]) {
- req.session.errors = {oldpassword: 'is incorrect'};
- return res.redirect(req.url);
- }
- next();
- });
+ var key = 'user:'+req.session.user;
+ db.hmget(key, 'salt', 'password', function(err, data) {
+ var hash = crypto.createHash('sha256').update(data[0]+req.body.oldpassword).digest('hex');
+ if (hash !== data[1]) {
+ req.session.errors = {oldpassword: 'is incorrect'};
+ return res.redirect(req.url);
+ }
+ next();
+ });
};
exports.changePasswd = function(req, res) {
- var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/'
- , user = req.session.user
- , key = 'user:'+user
- , salt = crypto.randomBytes(6).toString('base64')
- , password = crypto.createHash('sha256').update(salt+req.body.newpassword).digest('hex');
- db.hmset(key, 'salt', salt, 'password', password, function(err, data) {
- // Regenerate the session
- req.session.regenerate(function() {
- req.session.cookie.maxAge = 604800000; // One week
- req.session.user = user;
- res.redirect(followup);
- });
+ var followup = ~safeurls.indexOf(req.query.followup) ? req.query.followup : '/'
+ , user = req.session.user
+ , key = 'user:'+user
+ , salt = crypto.randomBytes(6).toString('base64')
+ , password = crypto.createHash('sha256').update(salt+req.body.newpassword).digest('hex');
+ db.hmset(key, 'salt', salt, 'password', password, function(err, data) {
+ // Regenerate the session
+ req.session.regenerate(function() {
+ req.session.cookie.maxAge = 604800000; // One week
+ req.session.user = user;
+ res.redirect(followup);
});
+ });
};
/**
*/
exports.validateLogin = function(req, res, next) {
- if (req.body.username === undefined || req.body.password === undefined) {
- return res.send(412);
- }
-
- var errors = {};
-
- if (req.body.username.trim() === '') {
- errors.username = "can't be empty";
- }
- if (req.body.password.trim() === '') {
- errors.password = "can't be empty";
- }
-
- req.session.oldvalues = {username: req.body.username};
- if (errors.username || errors.password) {
- req.session.errors = errors;
- return res.redirect(req.url);
- }
- next();
+ if (req.body.username === undefined || req.body.password === undefined) {
+ return res.send(412);
+ }
+
+ var errors = {};
+
+ if (req.body.username.trim() === '') {
+ errors.username = "can't be empty";
+ }
+ if (req.body.password.trim() === '') {
+ errors.password = "can't be empty";
+ }
+
+ req.session.oldvalues = {username: req.body.username};
+ if (errors.username || errors.password) {
+ req.session.errors = errors;
+ return res.redirect(req.url);
+ }
+ next();
};
exports.checkUser = function(req, res, next) {
- var key = 'user:'+req.body.username;
- db.exists(key, function(err, data) {
- if (data === 1) {
- // User exists, proceed with authentication
- return next();
- }
- req.session.errors = {alert: 'The username you specified does not exists.'};
- res.redirect(req.url);
- });
+ var key = 'user:'+req.body.username;
+ db.exists(key, function(err, data) {
+ if (data === 1) {
+ // User exists, proceed with authentication
+ return next();
+ }
+ req.session.errors = {alert: 'The username you specified does not exists.'};
+ res.redirect(req.url);
+ });
};
exports.authenticate = function(req, res) {
- var key = 'user:'+req.body.username;
- db.hmget(key, 'salt', 'password', function(err, data) {
- var hash = crypto.createHash('sha256').update(data[0]+req.body.password).digest('hex');
- if (hash === data[1]) {
- var 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
- req.session.user = req.body.username;
- res.redirect(followup);
- });
- return;
- }
- req.session.errors = {alert: 'The password you specified is not correct.'};
- res.redirect(req.url);
- });
+ var key = 'user:'+req.body.username;
+ db.hmget(key, 'salt', 'password', function(err, data) {
+ var hash = crypto.createHash('sha256').update(data[0]+req.body.password).digest('hex');
+ if (hash === data[1]) {
+ var 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
+ req.session.user = req.body.username;
+ res.redirect(followup);
+ });
+ return;
+ }
+ req.session.errors = {alert: 'The password you specified is not correct.'};
+ res.redirect(req.url);
+ });
};
/**
*/
exports.logout = function(req, res) {
- // Destroy the session
- req.session.destroy(function() {
- res.redirect('/');
- });
+ // Destroy the session
+ req.session.destroy(function() {
+ res.redirect('/');
+ });
};
/**
*/
exports.validateSignUp = function(req, res, next) {
- if (req.body.username === undefined || req.body.email === undefined ||
- req.body.password === undefined || req.body.captcha === undefined) {
- return res.send(412);
- }
-
- var errors = {};
-
- if (req.body.username === 'binb') {
- errors.username = 'is reserved';
- }
- 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.length < 6) {
- errors.password = 'must be at least 6 characters long';
- }
- if (req.body.captcha !== req.session.captchacode) {
- errors.captcha = 'no match';
- }
-
- // Save old values to repopulate the fields in case of future errors
- req.session.oldvalues = {
- username: req.body.username,
- email: req.body.email
- };
-
- if (errors.username || errors.email || errors.password || errors.captcha) {
- req.session.errors = errors;
- return res.redirect(req.url);
- }
-
- next();
+ if (req.body.username === undefined || req.body.email === undefined ||
+ req.body.password === undefined || req.body.captcha === undefined) {
+ return res.send(412);
+ }
+
+ var errors = {};
+
+ if (req.body.username === 'binb') {
+ errors.username = 'is reserved';
+ }
+ 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.length < 6) {
+ errors.password = 'must be at least 6 characters long';
+ }
+ if (req.body.captcha !== req.session.captchacode) {
+ errors.captcha = 'no match';
+ }
+
+ // Save old values to repopulate the fields in case of future errors
+ req.session.oldvalues = {
+ username: req.body.username,
+ email: req.body.email
+ };
+
+ if (errors.username || errors.email || errors.password || errors.captcha) {
+ req.session.errors = errors;
+ return res.redirect(req.url);
+ }
+
+ next();
};
exports.userExists = function(req, res, next) {
- var key = 'user:'+req.body.username;
- db.exists(key, function(err, data) {
- if (data === 1) {
- // User already exists
- req.session.errors = {alert: 'A user with that name already exists.'};
- return res.redirect(req.url);
- }
- next();
- });
+ var key = 'user:'+req.body.username;
+ db.exists(key, function(err, data) {
+ if (data === 1) {
+ // User 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;
- db.exists(key, function(err, data) {
- if (data === 1) {
- // Email already exists
- req.session.errors = {alert: 'A user with that email already exists.'};
- return res.redirect(req.url);
- }
- next();
- });
+ var key = 'email:'+req.body.email;
+ db.exists(key, function(err, data) {
+ if (data === 1) {
+ // 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) {
- var userkey = 'user:'+req.body.username
- , mailkey = 'email:'+req.body.email
- , salt = crypto.randomBytes(6).toString('base64')
- , hash = crypto.createHash('sha256').update(salt+req.body.password).digest('hex')
- , date = new Date()
- , day = date.getDate()
- , month = date.getMonth() + 1
- , year = date.getFullYear();
-
- if (day < 10) {
- day = '0' + day;
- }
- if (month < 10) {
- month = '0' + month;
- }
- var joindate = day+'/'+month+'/'+year;
- var user = new User(req.body.username, req.body.email, salt, hash, joindate);
- // Add new user in the db
- db.hmset(userkey, user);
- db.set(mailkey, userkey);
- db.zadd('users', 0, req.body.username);
- db.sadd('emails', req.body.email);
- // Delete old fields values
- delete req.session.oldvalues;
- res.render('login', {
- followup: req.query.followup || '/',
- slogan: utils.randomSlogan(),
- success: 'You successfully created your account. You are now ready to login.'
- });
+ var userkey = 'user:'+req.body.username
+ , mailkey = 'email:'+req.body.email
+ , salt = crypto.randomBytes(6).toString('base64')
+ , hash = crypto.createHash('sha256').update(salt+req.body.password).digest('hex')
+ , date = new Date()
+ , day = date.getDate()
+ , month = date.getMonth() + 1
+ , year = date.getFullYear();
+
+ if (day < 10) {
+ day = '0' + day;
+ }
+ if (month < 10) {
+ month = '0' + month;
+ }
+ var joindate = day+'/'+month+'/'+year;
+ var user = new User(req.body.username, req.body.email, salt, hash, joindate);
+ // Add new user in the db
+ db.hmset(userkey, user);
+ db.set(mailkey, userkey);
+ db.zadd('users', 0, req.body.username);
+ db.sadd('emails', req.body.email);
+ // Delete old fields values
+ delete req.session.oldvalues;
+ res.render('login', {
+ followup: req.query.followup || '/',
+ slogan: utils.randomSlogan(),
+ success: 'You successfully created your account. You are now ready to login.'
+ });
};
/**
*/
exports.validateRecoverPasswd = function(req, res, next) {
- if (req.body.email === undefined || req.body.captcha === undefined) {
- return res.send(412);
- }
-
- var errors = {};
-
- if (!utils.isEmail(req.body.email)) {
- errors.email = 'is not an email address';
- }
- if (req.body.captcha !== req.session.captchacode) {
- errors.captcha = 'no match';
- }
-
- req.session.oldvalues = {email: req.body.email};
-
- if (errors.email || errors.captcha) {
- req.session.errors = errors;
- return res.redirect(req.url);
- }
-
- next();
+ if (req.body.email === undefined || req.body.captcha === undefined) {
+ return res.send(412);
+ }
+
+ var errors = {};
+
+ if (!utils.isEmail(req.body.email)) {
+ errors.email = 'is not an email address';
+ }
+ if (req.body.captcha !== req.session.captchacode) {
+ errors.captcha = 'no match';
+ }
+
+ req.session.oldvalues = {email: req.body.email};
+
+ if (errors.email || errors.captcha) {
+ req.session.errors = errors;
+ return res.redirect(req.url);
+ }
+
+ next();
};
exports.sendEmail = function(req, res) {
- var key = 'email:'+req.body.email;
- db.get(key, function(err, data) {
- if (data !== null) {
- // Email exists, generate a secure random token
- delete req.session.captchacode;
- var token = crypto.randomBytes(48).toString('hex');
- // Token expires after 4 hours
- db.setex('token:'+token, 14400, data, function(err, reply) {
- mailer.sendEmail(req.body.email, token, function(err, response) {
- if (err) {
- console.log('error sending email: '+err.message);
- }
- });
- });
- delete req.session.oldvalues;
- return res.render('recoverpasswd', {
- followup: req.query.followup || '/',
- slogan: utils.randomSlogan(),
- success: true
- });
- }
- req.session.errors = {alert: 'The email address you specified could not be found'};
- res.redirect(req.url);
- });
+ var key = 'email:'+req.body.email;
+ db.get(key, function(err, data) {
+ if (data !== null) {
+ // Email exists, generate a secure random token
+ delete req.session.captchacode;
+ var token = crypto.randomBytes(48).toString('hex');
+ // Token expires after 4 hours
+ db.setex('token:'+token, 14400, data, function(err, reply) {
+ mailer.sendEmail(req.body.email, token, function(err, response) {
+ if (err) {
+ console.log('error sending email: '+err.message);
+ }
+ });
+ });
+ delete req.session.oldvalues;
+ return res.render('recoverpasswd', {
+ followup: req.query.followup || '/',
+ slogan: utils.randomSlogan(),
+ success: true
+ });
+ }
+ req.session.errors = {alert: 'The email address you specified could not be found'};
+ res.redirect(req.url);
+ });
};
/**
*/
exports.resetPasswd = function(req, res) {
- if (req.body.password === undefined) {
- return res.send(412);
- }
-
- var errors = {};
-
- // Validate new password
- if (req.body.password.length < 6) {
- errors.password = 'must be at least 6 characters long';
- }
- // Check token availability
- if (!req.query.token) {
- errors.alert = 'Missing token.';
- }
-
- if (errors.password || errors.alert) {
- req.session.errors = errors;
- return res.redirect(req.url);
+ if (req.body.password === undefined) {
+ return res.send(412);
+ }
+
+ var errors = {};
+
+ // Validate new password
+ if (req.body.password.length < 6) {
+ errors.password = 'must be at least 6 characters long';
+ }
+ // Check token availability
+ if (!req.query.token) {
+ errors.alert = 'Missing token.';
+ }
+
+ if (errors.password || errors.alert) {
+ req.session.errors = errors;
+ return res.redirect(req.url);
+ }
+
+ var key = 'token:'+req.query.token;
+ db.get(key, function(err, user) {
+ if (user !== null) {
+ // Delete the token
+ db.del(key);
+ // Update password
+ var salt = crypto.randomBytes(6).toString('base64');
+ var password = crypto.createHash('sha256').update(salt+req.body.password).digest('hex');
+ db.hmset(user, 'salt', salt, 'password', password, function(err, data) {
+ res.render('login', {
+ followup: '/',
+ slogan: utils.randomSlogan(),
+ success: 'You can now login with your new password.'
+ });
+ });
+ return;
}
-
- var key = 'token:'+req.query.token;
- db.get(key, function(err, user) {
- if (user !== null) {
- // Delete the token
- db.del(key);
- // Update password
- var salt = crypto.randomBytes(6).toString('base64');
- var password = crypto.createHash('sha256').update(salt+req.body.password).digest('hex');
- db.hmset(user, 'salt', salt, 'password', password, function(err, data) {
- res.render('login', {
- followup: '/',
- slogan: utils.randomSlogan(),
- success: 'You can now login with your new password.'
- });
- });
- return;
- }
- req.session.errors = {alert: 'Invalid or expired token.'};
- res.redirect(req.url);
- });
+ req.session.errors = {alert: 'Invalid or expired token.'};
+ res.redirect(req.url);
+ });
};
/**
*/
exports.profile = function(req, res) {
- var key = 'user:'+req.params[0];
- db.exists(key, function(err, data) {
- if (data === 1) {
- db.hgetall(key, function(e, obj) {
- obj.bestguesstime = (obj.bestguesstime/1000).toFixed(1);
- obj.worstguesstime = (obj.worstguesstime/1000).toFixed(1);
- if (obj.guessed !== '0') {
- obj.meanguesstime = ((obj.totguesstime/obj.guessed)/1000).toFixed(1);
- }
- delete obj.email;
- delete obj.password;
- delete obj.salt;
- delete obj.totguesstime;
- res.locals.slogan = utils.randomSlogan();
- res.render('user', obj);
- });
- return;
+ var key = 'user:'+req.params[0];
+ db.exists(key, function(err, data) {
+ if (data === 1) {
+ db.hgetall(key, function(e, obj) {
+ obj.bestguesstime = (obj.bestguesstime/1000).toFixed(1);
+ obj.worstguesstime = (obj.worstguesstime/1000).toFixed(1);
+ if (obj.guessed !== '0') {
+ obj.meanguesstime = ((obj.totguesstime/obj.guessed)/1000).toFixed(1);
}
- res.send(404);
- });
+ delete obj.email;
+ delete obj.password;
+ delete obj.salt;
+ delete obj.totguesstime;
+ res.locals.slogan = utils.randomSlogan();
+ res.render('user', obj);
+ });
+ return;
+ }
+ res.send(404);
+ });
};
extends layout
block title
- title binb :: Change password
+ title binb :: Change password
block nav
- ul.nav.pull-right
+ ul.nav.pull-right
+ li
+ a(href="/") Home
+ li.dropdown
+ a.dropdown-toggle(data-toggle="dropdown", href="#") Logged in as #{loggedin}
+ span.caret
+ ul.dropdown-menu
li
- a(href="/") Home
- li.dropdown
- a.dropdown-toggle(data-toggle="dropdown", href="#")
- | Logged in as #{loggedin}
- span.caret
- ul.dropdown-menu
- li
- a(href="/user/#{loggedin}", target="_blank") Profile
- li
- a(href="/logout") Logout
+ a(href="/user/#{loggedin}", target="_blank") Profile
+ li
+ a(href="/logout") Logout
block sections
- section
- .row
- .span12.offset2
- form.form-horizontal.well(method="post",
- action="/changepasswd?followup=#{followup}")
- fieldset
- - if (locals.errors)
- - if (errors.oldpassword)
- .control-group.error
- label.control-label(for="oldpassword") Old password
- .controls
- input#oldpassword(type="password", name="oldpassword")
- span.help-inline #{errors.oldpassword}
- - else
- .control-group
- label.control-label(for="oldpassword") Old password
- .controls
- input#oldpassword(type="password", name="oldpassword",
- placeholder="enter your current password...")
- - if (errors.newpassword)
- .control-group.error
- label.control-label(for="newpassword") New password
- .controls
- input#newpassword(type="password", name="newpassword")
- span.help-inline #{errors.newpassword}
- - else
- .control-group
- label.control-label(for="newpassword") New password
- .controls
- input#newpassword(type="password", name="newpassword",
- placeholder="enter your new password...")
- - else
- .control-group
- label.control-label(for="oldpassword") Old password
- .controls
- input#oldpassword(type="password", name="oldpassword",
- placeholder="enter your current password...")
- .control-group
- label.control-label(for="password") New password
- .controls
- input#newpassword(type="password", name="newpassword",
- placeholder="enter your new password...")
- button.submit-button.btn.btn-primary(type="submit")
- i.icon-edit.icon-white
- | Update
+ section
+ .row
+ .span12.offset2
+ form.form-horizontal.well(method="post",
+ action="/changepasswd?followup=#{followup}")
+ fieldset
+ - if (locals.errors)
+ - if (errors.oldpassword)
+ .control-group.error
+ label.control-label(for="oldpassword") Old password
+ .controls
+ input#oldpassword(type="password", name="oldpassword")
+ span.help-inline #{errors.oldpassword}
+ - else
+ .control-group
+ label.control-label(for="oldpassword") Old password
+ .controls
+ input#oldpassword(type="password", name="oldpassword",
+ placeholder="enter your current password...")
+ - if (errors.newpassword)
+ .control-group.error
+ label.control-label(for="newpassword") New password
+ .controls
+ input#newpassword(type="password", name="newpassword")
+ span.help-inline #{errors.newpassword}
+ - else
+ .control-group
+ label.control-label(for="newpassword") New password
+ .controls
+ input#newpassword(type="password", name="newpassword",
+ placeholder="enter your new password...")
+ - else
+ .control-group
+ label.control-label(for="oldpassword") Old password
+ .controls
+ input#oldpassword(type="password", name="oldpassword",
+ placeholder="enter your current password...")
+ .control-group
+ label.control-label(for="password") New password
+ .controls
+ input#newpassword(type="password", name="newpassword",
+ placeholder="enter your new password...")
+ button.submit-button.btn.btn-primary(type="submit")
+ i.icon-edit.icon-white
+ | Update
extends layout
block title
- title binb
+ title binb
block nav
- ul.nav.pull-right
- li.active
- a(href="/") Home
- li
- a(target="_blank", href="/leaderboards")
- i.icon-list-alt.icon-white
- | Leaderboards
- - if (locals.loggedin)
- li.dropdown
- a.dropdown-toggle(data-toggle="dropdown", href="#")
- | Logged in as #{loggedin}
- span.caret
- ul.dropdown-menu
- li
- a(href="/user/#{loggedin}", target="_blank") Profile
- li
- a(href="/changepasswd") Change password
- li
- a(href="/logout") Logout
- - else
- li
- a(href="/signup") Sign up
- li
- a(href="/login") Login
+ ul.nav.pull-right
+ li.active
+ a(href="/") Home
+ li
+ a(target="_blank", href="/leaderboards")
+ i.icon-list-alt.icon-white
+ | Leaderboards
+ - if (locals.loggedin)
+ li.dropdown
+ a.dropdown-toggle(data-toggle="dropdown", href="#") Logged in as #{loggedin}
+ span.caret
+ ul.dropdown-menu
+ li
+ a(href="/user/#{loggedin}", target="_blank") Profile
+ li
+ a(href="/changepasswd") Change password
+ li
+ a(href="/logout") Logout
+ - else
+ li
+ a(href="/signup") Sign up
+ li
+ a(href="/login") Login
block sections
- section
- .row
- .span7
- h3 What's this?
- p binb is a realtime, multiplayer, competitive music listening game.
- .span9
- h3 How to play?
- p All you have to do is to guess the song that is playing. A fixed number
- | of songs will run and for each one correctly guessed you will earn an
- | amount of points. That amount depends on the number of correct guesses
- | (artist and/or title of the song) and on how fast you will be on
- | answering compared to other players. At the end a scoreboard will
- | report the best three players of the match. If you have read this
- | far, what are you waiting? Click on a room below and prove your
- | music knowledge!
- section
- .row
- .span16
- ul.thumbnails
- - each item in rooms
- li.span4
- a.thumbnail.relative(href=item)
- .room #{item} -
- span(id=item)
- | Players
+ section
+ .row
+ .span7
+ h3 What's this?
+ p binb is a realtime, multiplayer, competitive music listening game.
+ .span9
+ h3 How to play?
+ p All you have to do is to guess the song that is playing. A fixed number
+ | of songs will run and for each one correctly guessed you will earn an
+ | amount of points. That amount depends on the number of correct guesses
+ | (artist and/or title of the song) and on how fast you will be on
+ | answering compared to other players. At the end a scoreboard will
+ | report the best three players of the match. If you have read this
+ | far, what are you waiting? Click on a room below and prove your
+ | music knowledge!
+ section
+ .row
+ .span16
+ ul.thumbnails
+ - each item in rooms
+ li.span4
+ a.thumbnail.relative(href=item)
+ .room #{item} -
+ span(id=item)
+ | Players
append scripts
- script(src="/socket.io/socket.io.js")
- script(src="/static/js/home.js")
+ script(src="/socket.io/socket.io.js")
+ script(src="/static/js/home.js")
doctype html
html
- head
- meta(charset="utf-8")
- block title
- meta(name="author", content="Luigi Pinca")
- meta(name="description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!")
- meta(property="og:description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!")
- meta(property="og:image", content="https://dl.dropbox.com/u/58444696/binb-logo-200.png")
- meta(property="og:title", content="binb")
- meta(property="og:type", content="game")
- meta(property="og:url", content="http://binb.nodejitsu.com/")
- link(href="/static/css/bootstrap.min.css", rel="stylesheet")
- link(href="/static/css/style.css", rel="stylesheet")
- script
- var _gaq = _gaq || [];
- _gaq.push(['_setAccount', 'UA-29865853-1']);
- _gaq.push(['_trackPageview']);
- (function() {
- var ga = document.createElement('script');
- ga.type = 'text/javascript'; ga.async = true;
- ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') +
- '.google-analytics.com/ga.js';
- var s = document.getElementsByTagName('script')[0];
- s.parentNode.insertBefore(ga, s);
- })();
- body
- .navbar.navbar-inverse.navbar-fixed-top
- .navbar-inner
- .container
- block brand
- a.brand(href="/")
- .icons.logo #{slogan}
- block nav
+ head
+ meta(charset="utf-8")
+ block title
+ meta(name="author", content="Luigi Pinca")
+ meta(name="description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!")
+ meta(property="og:description", content="Simple, realtime, multiplayer, competitive music listening game. Guess the song and prove your music knowledge!")
+ meta(property="og:image", content="https://dl.dropbox.com/u/58444696/binb-logo-200.png")
+ meta(property="og:title", content="binb")
+ meta(property="og:type", content="game")
+ meta(property="og:url", content="http://binb.nodejitsu.com/")
+ link(href="/static/css/bootstrap.min.css", rel="stylesheet")
+ link(href="/static/css/style.css", rel="stylesheet")
+ script
+ var _gaq = _gaq || [];
+ _gaq.push(['_setAccount', 'UA-29865853-1']);
+ _gaq.push(['_trackPageview']);
+ (function() {
+ var ga = document.createElement('script');
+ ga.type = 'text/javascript'; ga.async = true;
+ ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') +
+ '.google-analytics.com/ga.js';
+ var s = document.getElementsByTagName('script')[0];
+ s.parentNode.insertBefore(ga, s);
+ })();
+ body
+ .navbar.navbar-inverse.navbar-fixed-top
+ .navbar-inner
.container
- block sections
- footer
- #footer-inner
- #copy © 2012 Luigi Pinca
- iframe#facebook-button(allowTransparency="true", frameborder="0", scrolling="no",
- src="//www.facebook.com/plugins/like.php?href=http%3A%2F%2Fbinb.nodejitsu.com&send=false&layout=button_count&show_faces=false&action=like&colorscheme=light&locale=en_US")
- iframe#twitter-button(allowtransparency="true", frameborder="0", scrolling="no",
- src="//platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fbinb.nodejitsu.com")
- iframe#github-button(allowtransparency="true", frameborder="0", scrolling="0",
- src="http://ghbtns.com/github-btn.html?user=lpinca&repo=binb&type=watch&count=true")
- span.footer-info . Optimized for Google Chrome.
- a#nodejitsu-logo.icons(target="_blank", href="http://nodejitsu.com/")
- span.footer-info Powered by
- block media
- block scripts
- script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
- script(src="/static/js/bootstrap.min.js")
- script
- var uvOptions = {};
- (function() {
- var uv = document.createElement('script');
- uv.type = 'text/javascript'; uv.async = true;
- uv.src = ('https:' == document.location.protocol ? 'https://' : 'http://') +
- 'widget.uservoice.com/LSMjFAQRifhD6BjOG2KWw.js';
- var s = document.getElementsByTagName('script')[0];
- s.parentNode.insertBefore(uv, s);
- })();
+ block brand
+ a.brand(href="/")
+ .icons.logo #{slogan}
+ block nav
+ .container
+ block sections
+ footer
+ #footer-inner
+ #copy © 2012 Luigi Pinca
+ iframe#facebook-button(allowTransparency="true", frameborder="0", scrolling="no",
+ src="//www.facebook.com/plugins/like.php?href=http%3A%2F%2Fbinb.nodejitsu.com&send=false&layout=button_count&show_faces=false&action=like&colorscheme=light&locale=en_US")
+ iframe#twitter-button(allowtransparency="true", frameborder="0", scrolling="no",
+ src="//platform.twitter.com/widgets/tweet_button.html?url=http%3A%2F%2Fbinb.nodejitsu.com")
+ iframe#github-button(allowtransparency="true", frameborder="0", scrolling="0",
+ src="http://ghbtns.com/github-btn.html?user=lpinca&repo=binb&type=watch&count=true")
+ span.footer-info . Optimized for Google Chrome.
+ a#nodejitsu-logo.icons(target="_blank", href="http://nodejitsu.com/")
+ span.footer-info Powered by
+ block media
+ block scripts
+ script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
+ script(src="/static/js/bootstrap.min.js")
+ script
+ var uvOptions = {};
+ (function() {
+ var uv = document.createElement('script');
+ uv.type = 'text/javascript'; uv.async = true;
+ uv.src = ('https:' == document.location.protocol ? 'https://' : 'http://') +
+ 'widget.uservoice.com/LSMjFAQRifhD6BjOG2KWw.js';
+ var s = document.getElementsByTagName('script')[0];
+ s.parentNode.insertBefore(uv, s);
+ })();
extends layout
block title
- title binb :: Leaderboards
+ title binb :: Leaderboards
block brand
- a.brand(href="#")
- .icons.logo #{slogan}
+ a.brand(href="#")
+ .icons.logo #{slogan}
block sections
- section
- .row
- .span7.offset1
- .highscores High Scores
- .icons.img
- section
- .row
- .span7.offset1.relative
- h4 Points
- .leaderboard-wrapper
- table.table.table-striped.table-bordered.leaderboard
- tbody
- - each user, i in pointsleaderboard
- tr
- td #{i+1}
- td
- a(href="/user/#{user.username}") #{user.username}
- td #{user.totpoints}
- .loading
- .loading-block
- .loading-block
- .loading-block
- .span7.relative
- h4 Times
- .leaderboard-wrapper
- table.table.table-striped.table-bordered.leaderboard
- tbody
- - each user, i in timesleaderboard
- tr
- td #{i+1}
- td
- a(href="/user/#{user.username}") #{user.username}
- td
- i.icon-time
- | #{user.bestguesstime} sec
- .loading
- .loading-block
- .loading-block
- .loading-block
+ section
+ .row
+ .span7.offset1
+ .highscores High Scores
+ .icons.img
+ section
+ .row
+ .span7.offset1.relative
+ h4 Points
+ .leaderboard-wrapper
+ table.table.table-striped.table-bordered.leaderboard
+ tbody
+ - each user, i in pointsleaderboard
+ tr
+ td #{i+1}
+ td
+ a(href="/user/#{user.username}") #{user.username}
+ td #{user.totpoints}
+ .loading
+ .loading-block
+ .loading-block
+ .loading-block
+ .span7.relative
+ h4 Times
+ .leaderboard-wrapper
+ table.table.table-striped.table-bordered.leaderboard
+ tbody
+ - each user, i in timesleaderboard
+ tr
+ td #{i+1}
+ td
+ a(href="/user/#{user.username}") #{user.username}
+ td
+ i.icon-time
+ | #{user.bestguesstime} sec
+ .loading
+ .loading-block
+ .loading-block
+ .loading-block
block scripts
- script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
- script(src="/static/js/leaderboards.js")
+ script(src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js")
+ script(src="/static/js/leaderboards.js")
extends layout
block title
- title binb :: login
-
+ title binb :: login
+
block nav
- ul.nav.pull-right
- li
- a(href="/") Home
- li
- a(href="/signup?followup=#{followup}") Sign up
- li.active
- a(href="/login?followup=#{followup}") Login
+ ul.nav.pull-right
+ li
+ a(href="/") Home
+ li
+ a(href="/signup?followup=#{followup}") Sign up
+ li.active
+ a(href="/login?followup=#{followup}") Login
block sections
- section
- .row
- .span3
- h3 New user?
- a(href="/signup?followup=#{followup}") Click here to create an account.
- .span13
- - if (locals.errors && errors.alert)
- .alert.alert-error
- a.close(data-dismiss="alert") ×
- strong Oh snap!
- | #{errors.alert}
- - else if (locals.success)
- .alert.alert-success
- a.close(data-dismiss="alert") ×
- strong Well done!
- | #{success}
- form.form-horizontal.well(method="post", action="/login?followup=#{followup}")
- fieldset
- - if (locals.errors)
- - if (errors.username)
- .control-group.error
- label.control-label(for="username") Name
- .controls
- input#username(type="text", name="username",
- maxlength="15", value=oldvalues.username)
- span.help-inline #{errors.username}
- - else
- .control-group
- label.control-label(for="username") Name
- .controls
- input#username(type="text", name="username",
- maxlength="15", value=oldvalues.username)
- - if (errors.password)
- .control-group.error
- label.control-label(for="password") Password
- .controls
- input#password(type="password", name="password")
- span.help-inline #{errors.password}
- - else
- .control-group
- label.control-label(for="password") Password
- .controls
- input#password(type="password", name="password",
- placeholder="enter your password...")
- - else
- .control-group
- label.control-label(for="username") Name
- .controls
- input#username(type="text", name="username",
- maxlength="15", placeholder="enter your nickname...")
- .control-group
- label.control-label(for="password") Password
- .controls
- input#password(type="password", name="password",
- placeholder="enter your password...")
- button.submit-button.btn.btn-primary(type="submit")
- i.icon-lock.icon-white
- | Login
- a.forgot-passwd(href="/recoverpasswd?followup=#{followup}")
- | Forgot your password?
+ section
+ .row
+ .span3
+ h3 New user?
+ a(href="/signup?followup=#{followup}") Click here to create an account.
+ .span13
+ - if (locals.errors && errors.alert)
+ .alert.alert-error
+ a.close(data-dismiss="alert") ×
+ strong Oh snap!
+ | #{errors.alert}
+ - else if (locals.success)
+ .alert.alert-success
+ a.close(data-dismiss="alert") ×
+ strong Well done!
+ | #{success}
+ form.form-horizontal.well(method="post", action="/login?followup=#{followup}")
+ fieldset
+ - if (locals.errors)
+ - if (errors.username)
+ .control-group.error
+ label.control-label(for="username") Name
+ .controls
+ input#username(type="text", name="username",
+ maxlength="15", value=oldvalues.username)
+ span.help-inline #{errors.username}
+ - else
+ .control-group
+ label.control-label(for="username") Name
+ .controls
+ input#username(type="text", name="username",
+ maxlength="15", value=oldvalues.username)
+ - if (errors.password)
+ .control-group.error
+ label.control-label(for="password") Password
+ .controls
+ input#password(type="password", name="password")
+ span.help-inline #{errors.password}
+ - else
+ .control-group
+ label.control-label(for="password") Password
+ .controls
+ input#password(type="password", name="password",
+ placeholder="enter your password...")
+ - else
+ .control-group
+ label.control-label(for="username") Name
+ .controls
+ input#username(type="text", name="username",
+ maxlength="15", placeholder="enter your nickname...")
+ .control-group
+ label.control-label(for="password") Password
+ .controls
+ input#password(type="password", name="password",
+ placeholder="enter your password...")
+ button.submit-button.btn.btn-primary(type="submit")
+ i.icon-lock.icon-white
+ | Login
+ a.forgot-passwd(href="/recoverpasswd?followup=#{followup}")
+ | Forgot your password?
extends layout
block title
- title binb :: Recover password
+ title binb :: Recover password
block nav
- ul.nav.pull-right
- li
- a(href="/") Home
- li
- a(href="/signup?followup=#{followup}") Sign up
- li
- a(href="/login?followup=#{followup}") Login
+ ul.nav.pull-right
+ li
+ a(href="/") Home
+ li
+ a(href="/signup?followup=#{followup}") Sign up
+ li
+ a(href="/login?followup=#{followup}") Login
block sections
- section
- .row
- .span12.offset2
- - if (locals.success)
- .alert.alert-block.alert-success
- h4.alert-heading Success!
- | An email has been sent to you.<br>To start the password reset
- | process, open this email and follow the given instructions.<br>
- | If you don't receive it in a reasonable amount of time, please
- | use the support form on the left.
+ section
+ .row
+ .span12.offset2
+ - if (locals.success)
+ .alert.alert-block.alert-success
+ h4.alert-heading Success!
+ | An email has been sent to you.<br>To start the password reset
+ | process, open this email and follow the given instructions.<br>
+ | If you don't receive it in a reasonable amount of time, please
+ | use the support form on the left.
+ - else
+ - if (locals.errors && errors.alert)
+ .alert.alert-error
+ a.close(data-dismiss="alert") ×
+ strong Oh snap!
+ | #{errors.alert}
+ form.form-horizontal.well(method="post",
+ action="/recoverpasswd?followup=#{followup}")
+ fieldset
+ - if (locals.errors)
+ - if (errors.email)
+ .control-group.error
+ label.control-label(for="email") Email
+ .controls
+ input#email(type="text", name="email",
+ value=oldvalues.email)
+ span.help-inline #{errors.email}
- else
- - if (locals.errors && errors.alert)
- .alert.alert-error
- a.close(data-dismiss="alert") ×
- strong Oh snap!
- | #{errors.alert}
- form.form-horizontal.well(method="post",
- action="/recoverpasswd?followup=#{followup}")
- fieldset
- - if (locals.errors)
- - if (errors.email)
- .control-group.error
- label.control-label(for="email") Email
- .controls
- input#email(type="text", name="email",
- value=oldvalues.email)
- span.help-inline #{errors.email}
- - else
- .control-group
- label.control-label(for="email") Email
- .controls
- input#email(type="text", name="email",
- value=oldvalues.email)
- - if (errors.captcha)
- .control-group.error
- label.control-label(for="captcha-input") Are you human?
- .controls
- img#captcha(src=captchaurl)
- input#captcha-input(type="text", name="captcha",
- maxlength="4")
- span.help-inline #{errors.captcha}
- - else
- .control-group
- label.control-label(for="captcha-input") Are you human?
- .controls
- img#captcha(src=captchaurl)
- input#captcha-input(type="text", name="captcha",
- maxlength="4", placeholder="type what you see...")
- - else
- .control-group
- label.control-label(for="email") Email
- .controls
- input#email(type="text", name="email",
- placeholder="type the email you used to sign up...")
- .control-group
- label.control-label(for="captcha-input") Are you human?
- .controls
- img#captcha(src=captchaurl)
- input#captcha-input(type="text", name="captcha",
- maxlength="4", placeholder="type what you see...")
- button.submit-button.btn.btn-primary(type="submit")
- i.icon-envelope.icon-white
- | Send password reset link
+ .control-group
+ label.control-label(for="email") Email
+ .controls
+ input#email(type="text", name="email",
+ value=oldvalues.email)
+ - if (errors.captcha)
+ .control-group.error
+ label.control-label(for="captcha-input") Are you human?
+ .controls
+ img#captcha(src=captchaurl)
+ input#captcha-input(type="text", name="captcha",
+ maxlength="4")
+ span.help-inline #{errors.captcha}
+ - else
+ .control-group
+ label.control-label(for="captcha-input") Are you human?
+ .controls
+ img#captcha(src=captchaurl)
+ input#captcha-input(type="text", name="captcha",
+ maxlength="4", placeholder="type what you see...")
+ - else
+ .control-group
+ label.control-label(for="email") Email
+ .controls
+ input#email(type="text", name="email",
+ placeholder="type the email you used to sign up...")
+ .control-group
+ label.control-label(for="captcha-input") Are you human?
+ .controls
+ img#captcha(src=captchaurl)
+ input#captcha-input(type="text", name="captcha",
+ maxlength="4", placeholder="type what you see...")
+ button.submit-button.btn.btn-primary(type="submit")
+ i.icon-envelope.icon-white
+ | Send password reset link
extends layout
block title
- title binb :: Reset password
+ title binb :: Reset password
block brand
- a.brand(href="#")
- .icons.logo #{slogan}
+ a.brand(href="#")
+ .icons.logo #{slogan}
block sections
- section
- .row
- .span12.offset2
- - if (locals.errors && errors.alert)
- .alert.alert-error
- a.close(data-dismiss="alert") ×
- strong Oh snap!
- | #{errors.alert}
- form.form-horizontal.well(method="post", action="/resetpasswd?token=#{token}")
- fieldset
- - if (locals.errors && errors.password)
- .control-group.error
- label.control-label(for="password") New password
- .controls
- input#password(type="password", name="password")
- span.help-inline #{errors.password}
- - else
- .control-group
- label.control-label(for="password") New password
- .controls
- input#password(type="password", name="password",
- placeholder="enter your new password...")
- button.submit-button.btn.btn-primary(type="submit")
- i.icon-edit.icon-white
- | Update
+ section
+ .row
+ .span12.offset2
+ - if (locals.errors && errors.alert)
+ .alert.alert-error
+ a.close(data-dismiss="alert") ×
+ strong Oh snap!
+ | #{errors.alert}
+ form.form-horizontal.well(method="post", action="/resetpasswd?token=#{token}")
+ fieldset
+ - if (locals.errors && errors.password)
+ .control-group.error
+ label.control-label(for="password") New password
+ .controls
+ input#password(type="password", name="password")
+ span.help-inline #{errors.password}
+ - else
+ .control-group
+ label.control-label(for="password") New password
+ .controls
+ input#password(type="password", name="password",
+ placeholder="enter your new password...")
+ button.submit-button.btn.btn-primary(type="submit")
+ i.icon-edit.icon-white
+ | Update
extends layout
block title
- title binb :: #{roomname}
+ title binb :: #{roomname}
block brand
block nav
- ul.nav.pull-right
- li
- a(href="/") Home
- li
- a(target="_blank", href="/leaderboards")
- i.icon-list-alt.icon-white
- | Leaderboards
- li.active.dropdown
- a.dropdown-toggle(data-toggle="dropdown",href="#") #{roomname}
- b.caret
- ul.dropdown-menu
- - each item in rooms
- - if (item !== roomname)
- li
- a(href=item)
- span.room-name #{item}
- i.icon-user.pull-right
- span.users-counter
- - if (locals.loggedin)
- li.dropdown
- a.dropdown-toggle(data-toggle="dropdown", href="#")
- | Logged in as #{loggedin}
- span.caret
- ul.dropdown-menu
- li
- a(href="/user/#{loggedin}", target="_blank") Profile
- li
- a(href="/changepasswd?followup=/#{roomname}") Change password
- li
- a(href="/logout") Logout
- - else
+ ul.nav.pull-right
+ li
+ a(href="/") Home
+ li
+ a(target="_blank", href="/leaderboards")
+ i.icon-list-alt.icon-white
+ | Leaderboards
+ li.active.dropdown
+ a.dropdown-toggle(data-toggle="dropdown",href="#") #{roomname}
+ b.caret
+ ul.dropdown-menu
+ - each item in rooms
+ - if (item !== roomname)
li
- a(href="/signup?followup=/#{roomname}") Sign up
- li
- a(href="/login?followup=/#{roomname}") Login
+ a(href=item)
+ span.room-name #{item}
+ i.icon-user.pull-right
+ span.users-counter
+ - if (locals.loggedin)
+ li.dropdown
+ a.dropdown-toggle(data-toggle="dropdown", href="#") Logged in as #{loggedin}
+ span.caret
+ ul.dropdown-menu
+ li
+ a(href="/user/#{loggedin}", target="_blank") Profile
+ li
+ a(href="/changepasswd?followup=/#{roomname}") Change password
+ li
+ a(href="/logout") Logout
+ - else
+ li
+ a(href="/signup?followup=/#{roomname}") Sign up
+ li
+ a(href="/login?followup=/#{roomname}") Login
block sections
- section
- .row
- .span4.offset1
- #cassette.relative
- #wheel-left.icons.wheel
- #tape-left
- #tape-right
- #wheel-right.icons.wheel
- #progress-bar
- #progress
- #countdown
- .span2
- #volume.relative
- .span8
- .page-header
- .icons.logo #{slogan}
- #total-tracks
- span
- | tracks.
- #summary.row
- .span2
- .title Rank
- .rank
- .span4
- .title Points
- .points
- .span2
- .title Track
- .track
- p#feedback Waiting for connection...
- input#guess.span8(type="text", tabindex="1",
- placeholder="guess the artist and/or title here")
- section.relative
- .row
- #users-wrapper.span5.offset2
- ul#users.unstyled
- .span8
- a#toggle-chat Hide chat
- #chat-outer-wrapper
- #chat-wrapper.bordered
- ul#chat.unstyled
- #message-wrapper
- span#recipient
- input#message.span8(type="text", tabindex="2")
- ul#tracks.unstyled
- #disclaimer
- div I do not own any right on the songs that are played here.
- div Tracks are played using iTunes api preview.
+ section
+ .row
+ .span4.offset1
+ #cassette.relative
+ #wheel-left.icons.wheel
+ #tape-left
+ #tape-right
+ #wheel-right.icons.wheel
+ #progress-bar
+ #progress
+ #countdown
+ .span2
+ #volume.relative
+ .span8
+ .page-header
+ .icons.logo #{slogan}
+ #total-tracks
+ span
+ | tracks.
+ #summary.row
+ .span2
+ .title Rank
+ .rank
+ .span4
+ .title Points
+ .points
+ .span2
+ .title Track
+ .track
+ p#feedback Waiting for connection...
+ input#guess.span8(type="text", tabindex="1",
+ placeholder="guess the artist and/or title here")
+ section.relative
+ .row
+ #users-wrapper.span5.offset2
+ ul#users.unstyled
+ .span8
+ a#toggle-chat Hide chat
+ #chat-outer-wrapper
+ #chat-wrapper.bordered
+ ul#chat.unstyled
+ #message-wrapper
+ span#recipient
+ input#message.span8(type="text", tabindex="2")
+ ul#tracks.unstyled
+ #disclaimer
+ div I do not own any right on the songs that are played here.
+ div Tracks are played using iTunes api preview.
block media
- #modal.modal.fade
- #player
+ #modal.modal.fade
+ #player
append scripts
- script(src="/static/js/jquery.jplayer.min.js")
- script(src="/socket.io/socket.io.js")
- script(src="/static/js/app.js")
+ script(src="/static/js/jquery.jplayer.min.js")
+ script(src="/socket.io/socket.io.js")
+ script(src="/static/js/app.js")
extends layout
block title
- title binb :: sign up
+ title binb :: sign up
block nav
- ul.nav.pull-right
- li
- a(href="/") Home
- li.active
- a(href="/signup?followup=#{followup}") Sign up
- li
- a(href="/login?followup=#{followup}") Login
+ ul.nav.pull-right
+ li
+ a(href="/") Home
+ li.active
+ a(href="/signup?followup=#{followup}") Sign up
+ li
+ a(href="/login?followup=#{followup}") Login
block sections
- section
- .row
- .span3
- h3 Not a new user?
- a(href="/login?followup=#{followup}") Click here to log in.
- .span13
- h3 Why sign up?
- p Registration is optional, but if you are a regular user consider creating
- | an account. This will provide the following advantages:
- ul
- li You will be the one and only owner of your nickname (no one can use
- | your nickname in your place).
- li Some simple stats related to your account will be collected.
- - if (locals.errors && errors.alert)
- .alert.alert-error
- a.close(data-dismiss="alert") ×
- strong Oh snap!
- | #{errors.alert}
- form.form-horizontal.well(method="post",action="/signup?followup=#{followup}")
- fieldset
- - if (locals.errors)
- - if (errors.username)
- .control-group.error
- label.control-label(for="username") Name
- .controls
- input#username(type="text", name="username",
- maxlength="15", value=oldvalues.username)
- span.help-inline #{errors.username}
- - else
- .control-group
- label.control-label(for="username") Name
- .controls
- input#username(type="text", name="username",
- maxlength="15", value=oldvalues.username)
- - if (errors.email)
- .control-group.error
- label.control-label(for="email") Email
- .controls
- input#email(type="text", name="email",
- value=oldvalues.email)
- span.help-inline #{errors.email}
- - else
- .control-group
- label.control-label(for="email") Email
- .controls
- input#email(type="text", name="email",
- value=oldvalues.email)
- - if (errors.password)
- .control-group.error
- label.control-label(for="password") Password
- .controls
- input#password(type="password", name="password")
- span.help-inline #{errors.password}
- - else
- .control-group
- label.control-label(for="password") Password
- .controls
- input#password(type="password", name="password",
- placeholder="enter a password...")
- - if (errors.captcha)
- .control-group.error
- label.control-label(for="captcha-input") Are you human?
- .controls
- img#captcha(src=captchaurl)
- input#captcha-input(type="text", name="captcha",
- maxlength="4")
- span.help-inline #{errors.captcha}
- - else
- .control-group
- label.control-label(for="captcha-input") Are you human?
- .controls
- img#captcha(src=captchaurl)
- input#captcha-input(type="text", name="captcha",
- maxlength="4", placeholder="type what you see...")
- - else
- .control-group
- label.control-label(for="username") Name
- .controls
- input#username(type="text", name="username",
- maxlength="15", placeholder="enter a nickname...")
- .control-group
- label.control-label(for="email") Email
- .controls
- input#email(type="text", name="email",
- placeholder="enter a valid email...")
- .control-group
- label.control-label(for="password") Password
- .controls
- input#password(type="password", name="password",
- placeholder="enter a password...")
- .control-group
- label.control-label(for="captcha-input") Are you human?
- .controls
- img#captcha(src=captchaurl)
- input#captcha-input(type="text", name="captcha",
- maxlength="4", placeholder="type what you see...")
- button.submit-button.btn.btn-success(type="submit")
- i.icon-user.icon-white
- | Sign up!
+ section
+ .row
+ .span3
+ h3 Not a new user?
+ a(href="/login?followup=#{followup}") Click here to log in.
+ .span13
+ h3 Why sign up?
+ p Registration is optional, but if you are a regular user consider creating
+ | an account. This will provide the following advantages:
+ ul
+ li You will be the one and only owner of your nickname (no one can use
+ | your nickname in your place).
+ li Some simple stats related to your account will be collected.
+ - if (locals.errors && errors.alert)
+ .alert.alert-error
+ a.close(data-dismiss="alert") ×
+ strong Oh snap!
+ | #{errors.alert}
+ form.form-horizontal.well(method="post",action="/signup?followup=#{followup}")
+ fieldset
+ - if (locals.errors)
+ - if (errors.username)
+ .control-group.error
+ label.control-label(for="username") Name
+ .controls
+ input#username(type="text", name="username",
+ maxlength="15", value=oldvalues.username)
+ span.help-inline #{errors.username}
+ - else
+ .control-group
+ label.control-label(for="username") Name
+ .controls
+ input#username(type="text", name="username",
+ maxlength="15", value=oldvalues.username)
+ - if (errors.email)
+ .control-group.error
+ label.control-label(for="email") Email
+ .controls
+ input#email(type="text", name="email",
+ value=oldvalues.email)
+ span.help-inline #{errors.email}
+ - else
+ .control-group
+ label.control-label(for="email") Email
+ .controls
+ input#email(type="text", name="email",
+ value=oldvalues.email)
+ - if (errors.password)
+ .control-group.error
+ label.control-label(for="password") Password
+ .controls
+ input#password(type="password", name="password")
+ span.help-inline #{errors.password}
+ - else
+ .control-group
+ label.control-label(for="password") Password
+ .controls
+ input#password(type="password", name="password",
+ placeholder="enter a password...")
+ - if (errors.captcha)
+ .control-group.error
+ label.control-label(for="captcha-input") Are you human?
+ .controls
+ img#captcha(src=captchaurl)
+ input#captcha-input(type="text", name="captcha",
+ maxlength="4")
+ span.help-inline #{errors.captcha}
+ - else
+ .control-group
+ label.control-label(for="captcha-input") Are you human?
+ .controls
+ img#captcha(src=captchaurl)
+ input#captcha-input(type="text", name="captcha",
+ maxlength="4", placeholder="type what you see...")
+ - else
+ .control-group
+ label.control-label(for="username") Name
+ .controls
+ input#username(type="text", name="username",
+ maxlength="15", placeholder="enter a nickname...")
+ .control-group
+ label.control-label(for="email") Email
+ .controls
+ input#email(type="text", name="email",
+ placeholder="enter a valid email...")
+ .control-group
+ label.control-label(for="password") Password
+ .controls
+ input#password(type="password", name="password",
+ placeholder="enter a password...")
+ .control-group
+ label.control-label(for="captcha-input") Are you human?
+ .controls
+ img#captcha(src=captchaurl)
+ input#captcha-input(type="text", name="captcha",
+ maxlength="4", placeholder="type what you see...")
+ button.submit-button.btn.btn-success(type="submit")
+ i.icon-user.icon-white
+ | Sign up!
extends layout
block title
- title binb :: #{username} info
-
+ title binb :: #{username} info
+
block brand
- a.brand(href="#")
- .icons.logo #{slogan}
+ a.brand(href="#")
+ .icons.logo #{slogan}
block sections
- section
- .row
- .span7.offset1
- .profile #{username}
- .icons.img
- div member since #{joindate}
- section
- .row
- .span7.offset1
- h4 Points
- table.table.table-striped.table-bordered.stats
- tbody
- tr
- td Total
- td #{totpoints}
- tr
- td Best score
- td #{bestscore}
- tr
- td Guessed songs
- td #{guessed}
- h4 Times
- table.table.table-striped.table-bordered.stats
- tbody
- tr
- td Best guess time
- - if (bestguesstime !== "30.0")
- td #{bestguesstime} sec
- - else
- td N/A
- tr
- td Worst guess time
- - if (worstguesstime !== "0.0")
- td #{worstguesstime} sec
- - else
- td N/A
- tr
- td Mean guess time
- - if (typeof meanguesstime !== 'undefined')
- td #{meanguesstime} sec
- - else
- td N/A
- .span7
- h4 Awards
- table.table.table-striped.table-bordered.stats
- tbody
- tr
- td Gold cups
- td
- .icons.cups.stand1
- td #{golds}
- tr
- td Silver cups
- td
- .icons.cups.stand2
- td #{silvers}
- tr
- td Bronze cups
- td
- .icons.cups.stand3
- td #{bronzes}
- tr
- td Victories
- td
- .icons.medals.rank1
- td #{victories}
- tr
- td Second places
- td
- .icons.medals.rank2
- td #{secondplaces}
- tr
- td Third places
- td
- .icons.medals.rank3
- td #{thirdplaces}
+ section
+ .row
+ .span7.offset1
+ .profile #{username}
+ .icons.img
+ div member since #{joindate}
+ section
+ .row
+ .span7.offset1
+ h4 Points
+ table.table.table-striped.table-bordered.stats
+ tbody
+ tr
+ td Total
+ td #{totpoints}
+ tr
+ td Best score
+ td #{bestscore}
+ tr
+ td Guessed songs
+ td #{guessed}
+ h4 Times
+ table.table.table-striped.table-bordered.stats
+ tbody
+ tr
+ td Best guess time
+ - if (bestguesstime !== "30.0")
+ td #{bestguesstime} sec
+ - else
+ td N/A
+ tr
+ td Worst guess time
+ - if (worstguesstime !== "0.0")
+ td #{worstguesstime} sec
+ - else
+ td N/A
+ tr
+ td Mean guess time
+ - if (typeof meanguesstime !== 'undefined')
+ td #{meanguesstime} sec
+ - else
+ td N/A
+ .span7
+ h4 Awards
+ table.table.table-striped.table-bordered.stats
+ tbody
+ tr
+ td Gold cups
+ td
+ .icons.cups.stand1
+ td #{golds}
+ tr
+ td Silver cups
+ td
+ .icons.cups.stand2
+ td #{silvers}
+ tr
+ td Bronze cups
+ td
+ .icons.cups.stand3
+ td #{bronzes}
+ tr
+ td Victories
+ td
+ .icons.medals.rank1
+ td #{victories}
+ tr
+ td Second places
+ td
+ .icons.medals.rank2
+ td #{secondplaces}
+ tr
+ td Third places
+ td
+ .icons.medals.rank3
+ td #{thirdplaces}
block scripts