Compare commits
merge into: barry:master
barry:bob
barry:master
pull from: barry:bob
barry:bob
barry:master
No commits in common. 'master' and 'bob' have entirely different histories.
44 changed files with 1861 additions and 2259 deletions
Split View
Diff Options
-
38.gitignore
-
124app.js
-
93bin/www
-
104config.js
-
38index.js
-
77njs-bobinoscope
-
1333package-lock.json
-
45package.json
-
6pm2.json
-
0public/css/bootstrap.min.css
-
0public/css/cover.css
-
0public/css/style.css
-
0public/css/view.css
-
0public/img/common/294.GIF
-
0public/img/footer/cloclo.jpg
-
0public/img/footer/m-cloclo.jpg
-
BINpublic/img/footer/m-cloclo.xcf
-
0public/img/footer/m-clotilde60.jpg
-
BINpublic/img/footer/m-clotilde60.xcf
-
0public/img/template/default.jpg
-
0public/js/bootstrap.min.js
-
0public/js/jquery-1.11.2.min.js
-
0public/js/socket.io-1.3.4.js
-
206routes/index.js
-
9routes/users.js
-
131server/booth.js
-
693server/dnsmasq.conf
-
11server/hosts
-
63server/index.js
-
8server/public/js/socket.io.js
-
1server/public/js/socket.io.js.map
-
BINserver/public/rsc/footer/m-30ansv2.jpg
-
BINserver/public/waiting.gif
-
BINserver/public/waiting2.gif
-
251server/views/scope.ejs
-
62server/views/test.ejs
-
258tools/tools-gphoto2.js
-
192tools/tools-photobooth.js
-
5tools/tools-test.js
-
3views/error.ejs
-
19views/fixdate.ejs
-
248views/index.ejs
-
72views/index_back.ejs
-
30views/view.ejs
@ -1,2 +1,36 @@ |
|||
*node_modules* |
|||
output/ |
|||
# Logs |
|||
logs |
|||
*.log |
|||
|
|||
# Runtime data |
|||
pids |
|||
*.pid |
|||
*.seed |
|||
|
|||
# Directory for instrumented libs generated by jscoverage/JSCover |
|||
lib-cov |
|||
|
|||
# Coverage directory used by tools like istanbul |
|||
coverage |
|||
|
|||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) |
|||
.grunt |
|||
|
|||
# node-waf configuration |
|||
.lock-wscript |
|||
|
|||
# Compiled binary addons (http://nodejs.org/api/addons.html) |
|||
build/Release |
|||
|
|||
# Dependency directory |
|||
# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- |
|||
node_modules |
|||
public/img/final_ld/* |
|||
public/img/final/* |
|||
public/img/final_ld/* |
|||
public/img/original/* |
|||
public/img/prebuilt/* |
|||
|
|||
|
|||
# Debug log from npm |
|||
npm-debug.log |
|||
@ -0,0 +1,124 @@ |
|||
var BOB_mod_path = require('path'); |
|||
var BOB_mod_mkdirp = require('mkdirp'); |
|||
var express = require('express'); |
|||
var path = require('path'); |
|||
var favicon = require('serve-favicon'); |
|||
var logger = require('morgan'); |
|||
var cookieParser = require('cookie-parser'); |
|||
var bodyParser = require('body-parser'); |
|||
|
|||
var BOB_cfg_config = BOB_initConfig(); |
|||
|
|||
var routes = require('./routes/index')(BOB_cfg_config); |
|||
var users = require('./routes/users'); |
|||
|
|||
var app = express(); |
|||
|
|||
// view engine setup
|
|||
app.set('views', path.join(__dirname, 'views')); |
|||
app.set('view engine', 'ejs'); |
|||
|
|||
// uncomment after placing your favicon in /public
|
|||
//app.use(favicon(__dirname + '/public/favicon.ico'));
|
|||
app.use(logger('dev')); |
|||
app.use(bodyParser.json()); |
|||
app.use(bodyParser.urlencoded({ extended: false })); |
|||
app.use(cookieParser()); |
|||
app.use(express.static(path.join(__dirname, 'public'))); |
|||
|
|||
app.use('/', routes); |
|||
app.use('/users', users); |
|||
|
|||
// catch 404 and forward to error handler
|
|||
app.use(function(req, res, next) { |
|||
var err = new Error('Not Found'); |
|||
err.status = 404; |
|||
next(err); |
|||
}); |
|||
|
|||
// error handlers
|
|||
|
|||
// development error handler
|
|||
// will print stacktrace
|
|||
if (app.get('env') === 'development') { |
|||
app.use(function(err, req, res, next) { |
|||
res.status(err.status || 500); |
|||
res.render('error', { |
|||
message: err.message, |
|||
error: err |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
// production error handler
|
|||
// no stacktraces leaked to user
|
|||
app.use(function(err, req, res, next) { |
|||
res.status(err.status || 500); |
|||
res.render('error', { |
|||
message: err.message, |
|||
error: {} |
|||
}); |
|||
}); |
|||
|
|||
app.setSocketIo = function(pSocketIo) { |
|||
BOB_cfg_config.io = pSocketIo; |
|||
|
|||
pSocketIo.on('connection', function(socket){ |
|||
console.log('New client connected', socket.id); |
|||
|
|||
socket.on('event', function(data){ |
|||
console.log("event"); |
|||
}); |
|||
socket.on('disconnect', function(){ |
|||
console.log("disconnect"); |
|||
}); |
|||
}); |
|||
} |
|||
|
|||
module.exports = app; |
|||
|
|||
|
|||
|
|||
function BOB_initConfig() { |
|||
// Config
|
|||
var cfgConfig = { |
|||
background : '#ffffff', |
|||
margins : 0.005, |
|||
style : 'default', |
|||
nbPicture : 4, |
|||
cropSize : { |
|||
width : 900, |
|||
height : 1200 |
|||
}, |
|||
pictNames : [], |
|||
layout : [], |
|||
booths : {}, |
|||
paths : { |
|||
final : "", |
|||
template : "", |
|||
prebuilt : "", |
|||
original : "" |
|||
}, |
|||
footer : BOB_mod_path.resolve(__dirname, './public/img/footer', 'm-default.jpg') |
|||
}; |
|||
// Init PATH
|
|||
cfgConfig.paths.final = BOB_mod_path.resolve(__dirname, './public/img/final'); |
|||
cfgConfig.paths.final_ld = BOB_mod_path.resolve(__dirname, './public/img/final_ld'); |
|||
cfgConfig.paths.prebuilt = BOB_mod_path.resolve(__dirname, './public/img/prebuilt'); |
|||
cfgConfig.paths.template = BOB_mod_path.resolve(__dirname, './public/img/template'); |
|||
cfgConfig.paths.original = BOB_mod_path.resolve(__dirname, './public/img/original'); |
|||
|
|||
BOB_mod_mkdirp.sync(cfgConfig.paths.final); |
|||
BOB_mod_mkdirp.sync(cfgConfig.paths.final_ld); |
|||
BOB_mod_mkdirp.sync(cfgConfig.paths.prebuilt); |
|||
BOB_mod_mkdirp.sync(cfgConfig.paths.original); |
|||
|
|||
// Init pinctures names
|
|||
for( var index = 0; index < cfgConfig.nbPicture; index ++ ) { |
|||
(function(pId) { |
|||
cfgConfig.pictNames.push('pict_'+pId+'.jpg'); |
|||
})(index); |
|||
} |
|||
|
|||
return cfgConfig; |
|||
} |
|||
@ -0,0 +1,93 @@ |
|||
#!/usr/bin/env node |
|||
|
|||
/** |
|||
* Module dependencies. |
|||
*/ |
|||
|
|||
var app = require('../app'); |
|||
var debug = require('debug')('bobinoscope:server'); |
|||
var http = require('http'); |
|||
|
|||
/** |
|||
* Get port from environment and store in Express. |
|||
*/ |
|||
|
|||
var port = normalizePort(process.env.PORT || '3000'); |
|||
app.set('port', port); |
|||
|
|||
/** |
|||
* Create HTTP server. |
|||
*/ |
|||
|
|||
var server = http.createServer(app); |
|||
var io = require('socket.io')(server); |
|||
|
|||
app.setSocketIo(io); |
|||
|
|||
/** |
|||
* Listen on provided port, on all network interfaces. |
|||
*/ |
|||
|
|||
server.listen(port); |
|||
server.on('error', onError); |
|||
server.on('listening', onListening); |
|||
|
|||
/** |
|||
* Normalize a port into a number, string, or false. |
|||
*/ |
|||
|
|||
function normalizePort(val) { |
|||
var port = parseInt(val, 10); |
|||
|
|||
if (isNaN(port)) { |
|||
// named pipe |
|||
return val; |
|||
} |
|||
|
|||
if (port >= 0) { |
|||
// port number |
|||
return port; |
|||
} |
|||
|
|||
return false; |
|||
} |
|||
|
|||
/** |
|||
* Event listener for HTTP server "error" event. |
|||
*/ |
|||
|
|||
function onError(error) { |
|||
if (error.syscall !== 'listen') { |
|||
throw error; |
|||
} |
|||
|
|||
var bind = typeof port === 'string' |
|||
? 'Pipe ' + port |
|||
: 'Port ' + port; |
|||
|
|||
// handle specific listen errors with friendly messages |
|||
switch (error.code) { |
|||
case 'EACCES': |
|||
console.error(bind + ' requires elevated privileges'); |
|||
process.exit(1); |
|||
break; |
|||
case 'EADDRINUSE': |
|||
console.error(bind + ' is already in use'); |
|||
process.exit(1); |
|||
break; |
|||
default: |
|||
throw error; |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Event listener for HTTP server "listening" event. |
|||
*/ |
|||
|
|||
function onListening() { |
|||
var addr = server.address(); |
|||
var bind = typeof addr === 'string' |
|||
? 'pipe ' + addr |
|||
: 'port ' + addr.port; |
|||
debug('Listening on ' + bind); |
|||
} |
|||
@ -1,104 +0,0 @@ |
|||
const os = require('os') |
|||
const path = require('path') |
|||
const mkdirp = require('mkdirp') |
|||
const fs = require('fs-extra') |
|||
|
|||
const config = { |
|||
background: '#ffffff', |
|||
margins: 0.005, |
|||
style: 'default', |
|||
nbPicture: 4, |
|||
cropSize: { |
|||
width: 900, |
|||
height: 1200 |
|||
}, |
|||
pictNames: [], |
|||
layout: [], |
|||
booths: {}, |
|||
paths: { |
|||
final: '', |
|||
template: '', |
|||
prebuilt: '', |
|||
original: '', |
|||
toprint: '' |
|||
}, |
|||
output: path.resolve('/media/share/'), |
|||
footer: 'm-30ansv2.jpg' |
|||
} |
|||
|
|||
config.server = { |
|||
ipAddress: getIpAddress(), |
|||
port: 3111 |
|||
} |
|||
|
|||
config.killZone = { |
|||
top: 2, |
|||
bottom: 2, |
|||
left: 25, |
|||
right: 25 |
|||
} |
|||
|
|||
config.output = path.join(config.output, 'bobinoscope') |
|||
|
|||
try { |
|||
fs.ensureDirSync(config.output) |
|||
console.log('[!] Bobinogrammes will be available in: ' + config.output) |
|||
} catch (e) { |
|||
console.log('[!] Failed to create folders: ' + config.output) |
|||
try { |
|||
config.output = process.cwd() |
|||
config.output = path.join(config.output, 'bobinoscope') |
|||
console.log('[!] Bobinogrammes will be available in: ' + config.output) |
|||
} catch (e) { |
|||
console.log('[!] Failed to create folders: ' + config.output) |
|||
process.exit(1) |
|||
} |
|||
} |
|||
|
|||
// Init PATH
|
|||
config.paths.template = path.resolve(__dirname, './server/public/rsc/template') |
|||
config.footer = path.resolve(__dirname, './server/public/rsc/footer', config.footer) |
|||
config.paths.final = path.resolve(config.output, './final') |
|||
config.paths.final_ld = path.resolve(config.output, './final_ld') |
|||
config.paths.prebuilt = path.resolve(config.output, './cache') |
|||
config.paths.original = path.resolve(config.output, './original') |
|||
config.paths.toprint = path.resolve(config.output, './toprint') |
|||
|
|||
mkdirp.sync(config.paths.final) |
|||
mkdirp.sync(config.paths.final_ld) |
|||
mkdirp.sync(config.paths.prebuilt) |
|||
mkdirp.sync(config.paths.original) |
|||
mkdirp.sync(config.paths.toprint) |
|||
|
|||
// Init pinctures names
|
|||
for (let index = 0; index < config.nbPicture; index++) { |
|||
config.pictNames.push('pict_' + index + '.jpg') |
|||
} |
|||
|
|||
module.exports = config |
|||
|
|||
function getIpAddress () { |
|||
let ipAddress = 'localhost' |
|||
// Get local server ip address
|
|||
let ifaces = os.networkInterfaces() |
|||
Object.keys(ifaces).forEach(function (ifname) { |
|||
let alias = 0 |
|||
|
|||
ifaces[ifname].forEach(function (iface) { |
|||
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
|
|||
if (iface.family !== 'IPv4' || iface.internal !== false) return |
|||
if (/wlan/i.test(ifname)) ipAddress = iface.address |
|||
|
|||
if (alias >= 1) { |
|||
// this single interface has multiple ipv4 addresses
|
|||
// console.log(`[-] network: ${ifname} : ${alias} - ${iface.address}`)
|
|||
} else { |
|||
// this interface has only one ipv4 adress
|
|||
// console.log(`[-] network: ${ifname} - ${iface.address}`)
|
|||
// console.log(ifname, iface.address)
|
|||
} |
|||
}) |
|||
}) |
|||
|
|||
return ipAddress |
|||
} |
|||
@ -1,38 +0,0 @@ |
|||
#!/usr/bin/env node
|
|||
const gphoto2 = require('./tools/tools-gphoto2') |
|||
const server = require('./server') |
|||
|
|||
const args = require('args-parser')(process.argv) |
|||
|
|||
const PKG = require('./package') |
|||
|
|||
if (args.noinit) { |
|||
let app = server(args) |
|||
} else { |
|||
gphoto2.init(function () { |
|||
console.log('[>] Checking list done with success') |
|||
let app = server(args) |
|||
}) |
|||
} |
|||
|
|||
// killall gvfs-gphoto2-volume-monitor
|
|||
|
|||
// // Initialize the library
|
|||
// BOB_var_gamepad.init()
|
|||
// // List the state of all currently attached devices
|
|||
// for (var i = 0, l = BOB_var_gamepad.numDevices(); i < l; i++) {
|
|||
// console.log(i, BOB_var_gamepad.deviceAtIndex(i));
|
|||
// }
|
|||
// // Create a game loop and poll for events
|
|||
// setInterval(BOB_var_gamepad.processEvents, 16);
|
|||
// // Scan for new gamepads as a slower rate
|
|||
// setInterval(BOB_var_gamepad.detectDevices, 500);
|
|||
// // Listen for button down events on all gamepads
|
|||
// BOB_var_gamepad.on("down", function (pId, pNum) {
|
|||
// BOB_cfg_config.io.emit('boothClick', {
|
|||
// id : pId,
|
|||
// num : pNum
|
|||
// });
|
|||
// })
|
|||
|
|||
// bobinoscope admin: 63748543
|
|||
@ -0,0 +1,77 @@ |
|||
#!/bin/bash |
|||
### BEGIN INIT INFO |
|||
# Provides: /home/cocoon/workspace/bobinoscope/bin/www |
|||
# Required-Start: $remote_fs $syslog |
|||
# Required-Stop: $remote_fs $syslog |
|||
# Default-Start: 2 3 4 5 |
|||
# Default-Stop: 0 1 6 |
|||
# Short-Description: forever running /home/cocoon/workspace/bobinoscope/bin/www |
|||
# Description: /home/cocoon/workspace/bobinoscope/bin/www |
|||
### END INIT INFO |
|||
# |
|||
# initd a node app |
|||
# Based on a script posted by https://gist.github.com/jinze at https://gist.github.com/3748766 |
|||
# |
|||
|
|||
# Source function library. |
|||
. /lib/lsb/init-functions |
|||
|
|||
pidFile="/var/run/njs-bobinoscope.pid" |
|||
logFile="/var/log/njs-bobinoscope" |
|||
|
|||
command="/usr/local/bin/node" |
|||
nodeApp="/home/cocoon/workspace/bobinoscope/bin/www" |
|||
foreverApp="/usr/local/bin/forever" |
|||
|
|||
start() { |
|||
echo "Starting $nodeApp" |
|||
|
|||
# Notice that we change the PATH because on reboot |
|||
# the PATH does not include the path to node. |
|||
# Launching forever with a full path |
|||
# does not work unless we set the PATH. |
|||
PATH=/usr/local/bin:$PATH |
|||
export NODE_ENV=production |
|||
#PORT=80 |
|||
$foreverApp start --pidFile $pidFile -l $logFile -a -d -c "$command" $nodeApp |
|||
RETVAL=$? |
|||
} |
|||
|
|||
restart() { |
|||
echo -n "Restarting $nodeApp" |
|||
$foreverApp restart $nodeApp |
|||
RETVAL=$? |
|||
} |
|||
|
|||
stop() { |
|||
echo -n "Shutting down $nodeApp" |
|||
$foreverApp stop $nodeApp |
|||
RETVAL=$? |
|||
} |
|||
|
|||
status() { |
|||
echo -n "Status $nodeApp" |
|||
$foreverApp list |
|||
RETVAL=$? |
|||
} |
|||
|
|||
case "$1" in |
|||
start) |
|||
start |
|||
;; |
|||
stop) |
|||
stop |
|||
;; |
|||
status) |
|||
status |
|||
;; |
|||
restart) |
|||
restart |
|||
;; |
|||
*) |
|||
echo "Usage: {start|stop|status|restart}" |
|||
exit 1 |
|||
;; |
|||
esac |
|||
exit $RETVAL |
|||
|
|||
1333
package-lock.json
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,33 +1,24 @@ |
|||
{ |
|||
"name": "bobinoscope-v2", |
|||
"version": "1.0.0", |
|||
"description": "Code for bobinoscope", |
|||
"main": "index.js", |
|||
"name": "bobinoscope", |
|||
"version": "0.0.0", |
|||
"private": true, |
|||
"scripts": { |
|||
"test": "echo \"Error: no test specified\" && exit 1" |
|||
"start": "node ./bin/www" |
|||
}, |
|||
"author": "P.BARRY", |
|||
"license": "ISC", |
|||
"dependencies": { |
|||
"args-parser": "^1.1.0", |
|||
"async": "^2.6.1", |
|||
"body-parser": "^1.18.3", |
|||
"colors": "^1.3.1", |
|||
"cookie-parser": "^1.4.3", |
|||
"ejs": "^2.6.1", |
|||
"express": "^4.16.3", |
|||
"fs-extra": "^7.0.0", |
|||
"gamepad": "^1.6.0", |
|||
"gm": "^1.23.1", |
|||
"mkdirp": "^0.5.1", |
|||
"morgan": "^1.9.0", |
|||
"opn": "^5.3.0", |
|||
"socket.io": "^2.1.1", |
|||
"split-lines": "^2.0.0" |
|||
}, |
|||
"nodemonConfig": { |
|||
"ignore": [ |
|||
"webapp/*" |
|||
] |
|||
"async": "~0.9.0", |
|||
"body-parser": "~1.12.0", |
|||
"cookie-parser": "~1.3.4", |
|||
"debug": "~2.1.1", |
|||
"ejs": "~2.3.1", |
|||
"es6-shim": "^0.35.0", |
|||
"express": "~4.12.2", |
|||
"gamepad": "^1.0.2", |
|||
"gm": "~1.17.0", |
|||
"mkdirp": "~0.5.0", |
|||
"morgan": "~1.5.1", |
|||
"odroid-gpio": "0.0.2", |
|||
"serve-favicon": "~2.2.0", |
|||
"socket.io": "~1.3.5" |
|||
} |
|||
} |
|||
@ -0,0 +1,206 @@ |
|||
var BOB_mod_express = require('express'); |
|||
var BOB_mod_router = BOB_mod_express.Router(); |
|||
var BOB_mod_path = require('path'); |
|||
var BOB_mod_mkdirp = require('mkdirp'); |
|||
var BOB_mod_os = require('os'); |
|||
var BOB_mod_fs = require('fs'); |
|||
|
|||
// var BOB_mod_fsExtra = require('fs-extra')
|
|||
|
|||
var BOB_tol_gphotos = null; |
|||
var BOB_tol_booth = null; |
|||
var BOB_cfg_config = null; |
|||
|
|||
var BOB_var_boothInProgress = 0; |
|||
//var BOB_var_gamepad = require("gamepad");
|
|||
var BOB_var_ipAddress = '127.0.0.1'; |
|||
|
|||
var BOB_var_path = "/home/odroid/workspace/bobinoscope"; |
|||
|
|||
var BOB_var_killZone = { |
|||
top : 2, |
|||
bottom : 2, |
|||
left : 25, |
|||
right : 25 |
|||
} |
|||
|
|||
BOB_mod_mkdirp.sync(BOB_var_path+"/public/printer/todo"); |
|||
BOB_mod_mkdirp.sync(BOB_var_path+"/public/printer/done"); |
|||
|
|||
/* GET home page. */ |
|||
BOB_mod_router.get('/bobinoscope', function(req, res, next) { |
|||
res.render('index', { |
|||
serverIpAddress: BOB_var_ipAddress, |
|||
killZone : BOB_var_killZone |
|||
}); |
|||
}); |
|||
/* GET view page. */ |
|||
BOB_mod_router.get('/', function(req, res, next) { |
|||
res.render('view', {serverIpAddress: BOB_var_ipAddress}); |
|||
}); |
|||
|
|||
BOB_mod_router.get('/booth/build/:boothId', function(req, res, next) { |
|||
BOB_var_boothInProgress += 1; |
|||
BOB_cfg_config.io.emit('boothState'); |
|||
BOB_tol_booth.buildBooth(req.params.boothId, function(pErr) { |
|||
BOB_cfg_config.io.emit('boothState'); |
|||
BOB_var_boothInProgress -= 1; |
|||
res.json({ error: pErr, data : null, boothId: req.params.boothId}); |
|||
}); |
|||
}) |
|||
|
|||
BOB_mod_router.get('/booth/list/:from', function(req, res, next) { |
|||
BOB_tol_booth.getBoothList(req.params.from, function(pErr, pList) { |
|||
res.json({error: pErr, booths: pList, inProgress : BOB_var_boothInProgress}); |
|||
}) |
|||
}) |
|||
|
|||
/* GET home page. */ |
|||
BOB_mod_router.get('/dslr/takepicture/:boothId/:pictId', function(req, res, next) { |
|||
// BOB_cfg_config.io.emit('boothState');
|
|||
BOB_tol_gphotos.takePicture(req.params.boothId, req.params.pictId, function(pErr) { |
|||
res.json({ error: pErr, data : null}); |
|||
}) |
|||
}); |
|||
|
|||
/* GET view page. */ |
|||
BOB_mod_router.get('/download/final/hd/:pictId', function(req, res, next) { |
|||
res.download(BOB_var_path+'/public/img/final/'+req.params.pictId); |
|||
}); |
|||
|
|||
|
|||
/* GET view page. */ |
|||
BOB_mod_router.get('/print/bobinogramme/:pictId', function(req, res, next) { |
|||
var srcPath = BOB_mod_path.join(BOB_var_path, '/public/img/final/'+req.params.pictId); |
|||
var dstPath = BOB_mod_path.join(BOB_var_path, '/public/printer/todo/'+req.params.pictId); |
|||
copyFile(srcPath, dstPath, function(pErr) { |
|||
res.json({error: pErr}) |
|||
}) |
|||
}); |
|||
|
|||
BOB_mod_router.get('/print/list/todo', function(req, res, next) { |
|||
var todoPath = BOB_mod_path.join(BOB_var_path, '/public/printer/todo'); |
|||
BOB_mod_fs.readdir(todoPath, function(pErr, pList) { |
|||
res.json({error: pErr, todos: pList}) |
|||
}) |
|||
}) |
|||
|
|||
BOB_mod_router.get('/fixdate', function (req, res, next) { |
|||
res.render('fixdate', {serverIpAddress: BOB_var_ipAddress}); |
|||
}) |
|||
|
|||
BOB_mod_router.get('/fixdate/:timestamp', function(req, res, next) { |
|||
var spawn = require('child_process').spawn; |
|||
|
|||
var date = spawn('date', ['-s', '@'+(req.params.timestamp/1000)]); |
|||
|
|||
var error = ''; |
|||
|
|||
date.stdout.on('data', function(data) {console.log(data.toString())}); |
|||
|
|||
date.stderr.on('data', function(data) {error += data; console.log(data.toString())}); |
|||
|
|||
date.on('close', function(code) { |
|||
res.json({error : code !== 0 ? error : ''}) |
|||
}) |
|||
}) |
|||
|
|||
|
|||
|
|||
|
|||
function copyFile(source, target, cb) { |
|||
var cbCalled = false; |
|||
|
|||
var rd = BOB_mod_fs.createReadStream(source); |
|||
rd.on("error", function(err) { |
|||
done(err); |
|||
}); |
|||
var wr = BOB_mod_fs.createWriteStream(target); |
|||
wr.on("error", function(err) { |
|||
done(err); |
|||
}); |
|||
wr.on("close", function(ex) { |
|||
done(); |
|||
}); |
|||
rd.pipe(wr); |
|||
|
|||
function done(err) { |
|||
if (!cbCalled) { |
|||
cb(err); |
|||
cbCalled = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
|
|||
var gpio = require("odroid-gpio"); |
|||
var previous = 1; |
|||
gpio.open(7, "input pullup", function(err) { // Open pin 16 for output
|
|||
console.log(err) |
|||
|
|||
setInterval(function() { |
|||
gpio.read(7, function(err, value) { |
|||
if(err) console.log(err); |
|||
// console.log(value); // The current state of the pini
|
|||
if (value === 0 && value !== previous) { |
|||
console.log('click') |
|||
BOB_cfg_config.io.emit('boothClick', { |
|||
id : 0, |
|||
num : 0 |
|||
}); |
|||
} |
|||
previous = value; |
|||
}); |
|||
}, 200) |
|||
}); |
|||
|
|||
|
|||
|
|||
// Initialize the library
|
|||
//BOB_var_gamepad.init()
|
|||
// List the state of all currently attached devices
|
|||
//for (var i = 0, l = BOB_var_gamepad.numDevices(); i < l; i++) {
|
|||
// console.log(i, BOB_var_gamepad.deviceAtIndex(i));
|
|||
//}
|
|||
// Create a game loop and poll for events
|
|||
//setInterval(BOB_var_gamepad.processEvents, 16);
|
|||
// Scan for new gamepads as a slower rate
|
|||
//setInterval(BOB_var_gamepad.detectDevices, 500);
|
|||
// Listen for button down events on all gamepads
|
|||
//BOB_var_gamepad.on("down", function (pId, pNum) {
|
|||
// BOB_cfg_config.io.emit('boothClick', {
|
|||
// id : pId,
|
|||
// num : pNum
|
|||
// });
|
|||
//})
|
|||
|
|||
// Get local server ip address
|
|||
var ifaces = BOB_mod_os.networkInterfaces(); |
|||
Object.keys(ifaces).forEach(function (ifname) { |
|||
var alias = 0; |
|||
|
|||
ifaces[ifname].forEach(function (iface) { |
|||
if ('IPv4' !== iface.family || iface.internal !== false) { |
|||
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
|
|||
return; |
|||
} |
|||
|
|||
BOB_var_ipAddress = iface.address; |
|||
|
|||
if (alias >= 1) { |
|||
// this single interface has multiple ipv4 addresses
|
|||
console.log(ifname + ':' + alias, iface.address); |
|||
} else { |
|||
// this interface has only one ipv4 adress
|
|||
console.log(ifname, iface.address); |
|||
} |
|||
}); |
|||
}); |
|||
|
|||
|
|||
module.exports = function(pConfig) { |
|||
BOB_cfg_config = pConfig; |
|||
BOB_tol_gphotos = require('../tools/tools-gphoto2')(pConfig); |
|||
BOB_tol_booth = require('../tools/tools-photobooth')(pConfig); |
|||
return BOB_mod_router; |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
var express = require('express'); |
|||
var router = express.Router(); |
|||
|
|||
/* GET users listing. */ |
|||
router.get('/', function(req, res, next) { |
|||
res.send('respond with a resource'); |
|||
}); |
|||
|
|||
module.exports = router; |
|||
@ -1,131 +0,0 @@ |
|||
const express = require('express') |
|||
const router = express.Router() |
|||
const fs = require('fs-extra') |
|||
const gm = require('gm').subClass({ imageMagick: true }) |
|||
const path = require('path') |
|||
const gamepad = require('gamepad') |
|||
require('colors') |
|||
|
|||
const gphoto2 = require('../tools/tools-gphoto2') |
|||
const booth = require('../tools/tools-photobooth') |
|||
|
|||
const CFG = require('../config') |
|||
const CTX = { |
|||
__io: null, |
|||
io: function () { |
|||
return CTX.__io |
|||
}, |
|||
inProgress: 0, |
|||
testPath: path.join(CFG.output, 'bobinoscope-test.jpg') |
|||
} |
|||
|
|||
booth.init() |
|||
setGamepad() |
|||
|
|||
// router.use(function (req, res, next) {
|
|||
// console.log(req.url)
|
|||
// next()
|
|||
// })
|
|||
|
|||
// ////////////////////////////////////////////////////////////////////////////
|
|||
// DSLR
|
|||
router.get('/dslr/takepicture/:boothId/:pictId', function (req, res, next) { |
|||
// return res.json({})
|
|||
gphoto2.takeOnePicture(req.params.boothId, req.params.pictId, function (pErr) { |
|||
let error = typeof pErr === 'string' ? pErr : JSON.stringify(pErr) |
|||
if (pErr) console.error(pErr) |
|||
res.json({ error: error, data: null }) |
|||
}) |
|||
}) |
|||
|
|||
router.get('/build/:boothId', function (req, res, next) { |
|||
console.log('Building') |
|||
// res.json({ok: 1})
|
|||
CTX.inProgress += 1 |
|||
CTX.io().emit('boothState') |
|||
booth.buildBooth(req.params.boothId, function (pErr) { |
|||
CTX.io().emit('boothState') |
|||
CTX.inProgress -= 1 |
|||
res.json({ error: pErr, data: null, boothId: req.params.boothId }) |
|||
}) |
|||
}) |
|||
|
|||
router.use('/build/result/low', express.static(CFG.paths.final_ld)) |
|||
router.use('/build/result', express.static(CFG.paths.final)) |
|||
|
|||
// ////////////////////////////////////////////////////////////////////////////
|
|||
// PRINTER
|
|||
router.get('/list/:from', function (req, res, next) { |
|||
booth.getBoothList(req.params.from, function (pErr, pList) { |
|||
res.json({error: pErr, booths: pList, inProgress: CTX.inProgress}) |
|||
}) |
|||
}) |
|||
|
|||
router.get('/toprint', function (req, res, next) { |
|||
var todoPath = path.join(CFG.paths.toprint) |
|||
fs.readdir(todoPath, function (pErr, pList) { |
|||
res.json({error: pErr, todos: pList}) |
|||
}) |
|||
}) |
|||
|
|||
router.get('/print/:pictId', function (req, res, next) { |
|||
let srcPath = path.join(CFG.paths.final, req.params.pictId) |
|||
let dstPath = path.join(CFG.paths.toprint, req.params.pictId) |
|||
fs.copy(srcPath, dstPath, function (pErr) { |
|||
res.json({error: pErr}) |
|||
}) |
|||
}) |
|||
|
|||
// ////////////////////////////////////////////////////////////////////////////
|
|||
// TEST
|
|||
|
|||
router.get('/test/takepicture', function (req, res, next) { |
|||
let tmpPict = path.join(CFG.output, 'bobinoscope-test.tmp.jpg') |
|||
gphoto2.__takeOnePicture(tmpPict, function (pErr) { |
|||
if (pErr) return res.status(500).send(pErr) |
|||
gm(tmpPict) |
|||
.autoOrient() |
|||
.gravity('Center') |
|||
.write(CTX.testPath, function (pErr) { |
|||
if (pErr) console.log('Failed to resize picture', pErr) |
|||
res.json({ok: 1}) |
|||
}) |
|||
}) |
|||
}) |
|||
|
|||
router.get('/test/takepicture/result', function (req, res, next) { |
|||
res.sendFile(path.join(CFG.output, 'bobinoscope-test.jpg')) |
|||
}) |
|||
|
|||
router.setSocketIo = function (pIo) { |
|||
CTX.__io = pIo |
|||
} |
|||
|
|||
function setGamepad () { |
|||
// Initialize the library
|
|||
gamepad.init() |
|||
// List the state of all currently attached devices
|
|||
// for (var i = 0, l = gamepad.numDevices(); i < l; i++) {
|
|||
// console.log(i, gamepad.deviceAtIndex(i))
|
|||
// }
|
|||
|
|||
if (!gamepad.numDevices()) { |
|||
console.log('[!] No gamepad found'.yellow) |
|||
} else { |
|||
console.log(`[!] ${gamepad.numDevices()} gamepad(s) found`.bgBlue) |
|||
// Create a game loop and poll for events
|
|||
setInterval(gamepad.processEvents, 16) |
|||
// Scan for new gamepads as a slower rate
|
|||
setInterval(gamepad.detectDevices, 500) |
|||
// Listen for button down events on all gamepads
|
|||
gamepad.on('down', function (pId, pNum) { |
|||
console.log(`[!] gamepad action received | ${pId}:${pNum}`.bgBlue) |
|||
CTX.io().emit('boothClick', { |
|||
id: pId, |
|||
num: pNum |
|||
}) |
|||
}) |
|||
} |
|||
} |
|||
|
|||
module.exports = router |
|||
@ -0,0 +1,693 @@ |
|||
# Configuration file for dnsmasq. |
|||
# |
|||
# Format is one option per line, legal options are the same |
|||
# as the long options legal on the command line. See |
|||
# "/usr/sbin/dnsmasq --help" or "man 8 dnsmasq" for details. |
|||
|
|||
# Listen on this specific port instead of the standard DNS port |
|||
# (53). Setting this to zero completely disables DNS function, |
|||
# leaving only DHCP and/or TFTP. |
|||
#port=5353 |
|||
|
|||
# The following two options make you a better netizen, since they |
|||
# tell dnsmasq to filter out queries which the public DNS cannot |
|||
# answer, and which load the servers (especially the root servers) |
|||
# unnecessarily. If you have a dial-on-demand link they also stop |
|||
# these requests from bringing up the link unnecessarily. |
|||
|
|||
# Never forward plain names (without a dot or domain part) |
|||
#domain-needed |
|||
# Never forward addresses in the non-routed address spaces. |
|||
#bogus-priv |
|||
|
|||
# Uncomment these to enable DNSSEC validation and caching: |
|||
# (Requires dnsmasq to be built with DNSSEC option.) |
|||
#conf-file=%%PREFIX%%/share/dnsmasq/trust-anchors.conf |
|||
#dnssec |
|||
|
|||
# Replies which are not DNSSEC signed may be legitimate, because the domain |
|||
# is unsigned, or may be forgeries. Setting this option tells dnsmasq to |
|||
# check that an unsigned reply is OK, by finding a secure proof that a DS |
|||
# record somewhere between the root and the domain does not exist. |
|||
# The cost of setting this is that even queries in unsigned domains will need |
|||
# one or more extra DNS queries to verify. |
|||
#dnssec-check-unsigned |
|||
|
|||
# Uncomment this to filter useless windows-originated DNS requests |
|||
# which can trigger dial-on-demand links needlessly. |
|||
# Note that (amongst other things) this blocks all SRV requests, |
|||
# so don't use it if you use eg Kerberos, SIP, XMMP or Google-talk. |
|||
# This option only affects forwarding, SRV records originating for |
|||
# dnsmasq (via srv-host= lines) are not suppressed by it. |
|||
#filterwin2k |
|||
|
|||
# Change this line if you want dns to get its upstream servers from |
|||
# somewhere other that /etc/resolv.conf |
|||
#resolv-file= |
|||
|
|||
# By default, dnsmasq will send queries to any of the upstream |
|||
# servers it knows about and tries to favour servers to are known |
|||
# to be up. Uncommenting this forces dnsmasq to try each query |
|||
# with each server strictly in the order they appear in |
|||
# /etc/resolv.conf |
|||
#strict-order |
|||
|
|||
# If you don't want dnsmasq to read /etc/resolv.conf or any other |
|||
# file, getting its servers from this file instead (see below), then |
|||
# uncomment this. |
|||
#no-resolv |
|||
|
|||
# If you don't want dnsmasq to poll /etc/resolv.conf or other resolv |
|||
# files for changes and re-read them then uncomment this. |
|||
#no-poll |
|||
|
|||
# Add other name servers here, with domain specs if they are for |
|||
# non-public domains. |
|||
#server=/localnet/192.168.0.1 |
|||
|
|||
# Example of routing PTR queries to nameservers: this will send all |
|||
# address->name queries for 192.168.3/24 to nameserver 10.1.2.3 |
|||
#server=/3.168.192.in-addr.arpa/10.1.2.3 |
|||
|
|||
# Add local-only domains here, queries in these domains are answered |
|||
# from /etc/hosts or DHCP only. |
|||
#local=/localnet/ |
|||
|
|||
# Add domains which you want to force to an IP address here. |
|||
# The example below send any host in double-click.net to a local |
|||
# web-server. |
|||
address=/double-click.net/127.0.0.1 |
|||
|
|||
# --address (and --server) work with IPv6 addresses too. |
|||
#address=/www.thekelleys.org.uk/fe80::20d:60ff:fe36:f83 |
|||
|
|||
# Add the IPs of all queries to yahoo.com, google.com, and their |
|||
# subdomains to the vpn and search ipsets: |
|||
#ipset=/yahoo.com/google.com/vpn,search |
|||
|
|||
# You can control how dnsmasq talks to a server: this forces |
|||
# queries to 10.1.2.3 to be routed via eth1 |
|||
# server=10.1.2.3@eth1 |
|||
|
|||
# and this sets the source (ie local) address used to talk to |
|||
# 10.1.2.3 to 192.168.1.1 port 55 (there must be a interface with that |
|||
# IP on the machine, obviously). |
|||
# server=10.1.2.3@192.168.1.1#55 |
|||
|
|||
# If you want dnsmasq to change uid and gid to something other |
|||
# than the default, edit the following lines. |
|||
#user= |
|||
#group= |
|||
|
|||
# If you want dnsmasq to listen for DHCP and DNS requests only on |
|||
# specified interfaces (and the loopback) give the name of the |
|||
# interface (eg eth0) here. |
|||
# Repeat the line for more than one interface. |
|||
#interface= |
|||
# Or you can specify which interface _not_ to listen on |
|||
#except-interface= |
|||
# Or which to listen on by address (remember to include 127.0.0.1 if |
|||
# you use this.) |
|||
#listen-address= |
|||
# If you want dnsmasq to provide only DNS service on an interface, |
|||
# configure it as shown above, and then use the following line to |
|||
# disable DHCP and TFTP on it. |
|||
#no-dhcp-interface= |
|||
|
|||
# On systems which support it, dnsmasq binds the wildcard address, |
|||
# even when it is listening on only some interfaces. It then discards |
|||
# requests that it shouldn't reply to. This has the advantage of |
|||
# working even when interfaces come and go and change address. If you |
|||
# want dnsmasq to really bind only the interfaces it is listening on, |
|||
# uncomment this option. About the only time you may need this is when |
|||
# running another nameserver on the same machine. |
|||
#bind-interfaces |
|||
|
|||
# If you don't want dnsmasq to read /etc/hosts, uncomment the |
|||
# following line. |
|||
#no-hosts |
|||
# or if you want it to read another file, as well as /etc/hosts, use |
|||
# this. |
|||
#addn-hosts=/etc/banner_add_hosts |
|||
|
|||
# Set this (and domain: see below) if you want to have a domain |
|||
# automatically added to simple names in a hosts-file. |
|||
#expand-hosts |
|||
|
|||
# Set the domain for dnsmasq. this is optional, but if it is set, it |
|||
# does the following things. |
|||
# 1) Allows DHCP hosts to have fully qualified domain names, as long |
|||
# as the domain part matches this setting. |
|||
# 2) Sets the "domain" DHCP option thereby potentially setting the |
|||
# domain of all systems configured by DHCP |
|||
# 3) Provides the domain part for "expand-hosts" |
|||
domain=bobine.lol |
|||
|
|||
# Set a different domain for a particular subnet |
|||
#domain=wireless.thekelleys.org.uk,192.168.2.0/24 |
|||
|
|||
# Same idea, but range rather then subnet |
|||
#domain=reserved.thekelleys.org.uk,192.68.3.100,192.168.3.200 |
|||
|
|||
# Uncomment this to enable the integrated DHCP server, you need |
|||
# to supply the range of addresses available for lease and optionally |
|||
# a lease time. If you have more than one network, you will need to |
|||
# repeat this for each network on which you want to supply DHCP |
|||
# service. |
|||
#dhcp-range=192.168.0.50,192.168.0.150,12h |
|||
|
|||
# This is an example of a DHCP range where the netmask is given. This |
|||
# is needed for networks we reach the dnsmasq DHCP server via a relay |
|||
# agent. If you don't know what a DHCP relay agent is, you probably |
|||
# don't need to worry about this. |
|||
#dhcp-range=192.168.0.50,192.168.0.150,255.255.255.0,12h |
|||
|
|||
# This is an example of a DHCP range which sets a tag, so that |
|||
# some DHCP options may be set only for this network. |
|||
#dhcp-range=set:red,192.168.0.50,192.168.0.150 |
|||
|
|||
# Use this DHCP range only when the tag "green" is set. |
|||
#dhcp-range=tag:green,192.168.0.50,192.168.0.150,12h |
|||
|
|||
# Specify a subnet which can't be used for dynamic address allocation, |
|||
# is available for hosts with matching --dhcp-host lines. Note that |
|||
# dhcp-host declarations will be ignored unless there is a dhcp-range |
|||
# of some type for the subnet in question. |
|||
# In this case the netmask is implied (it comes from the network |
|||
# configuration on the machine running dnsmasq) it is possible to give |
|||
# an explicit netmask instead. |
|||
#dhcp-range=192.168.0.0,static |
|||
|
|||
# Enable DHCPv6. Note that the prefix-length does not need to be specified |
|||
# and defaults to 64 if missing/ |
|||
#dhcp-range=1234::2, 1234::500, 64, 12h |
|||
|
|||
# Do Router Advertisements, BUT NOT DHCP for this subnet. |
|||
#dhcp-range=1234::, ra-only |
|||
|
|||
# Do Router Advertisements, BUT NOT DHCP for this subnet, also try and |
|||
# add names to the DNS for the IPv6 address of SLAAC-configured dual-stack |
|||
# hosts. Use the DHCPv4 lease to derive the name, network segment and |
|||
# MAC address and assume that the host will also have an |
|||
# IPv6 address calculated using the SLAAC alogrithm. |
|||
#dhcp-range=1234::, ra-names |
|||
|
|||
# Do Router Advertisements, BUT NOT DHCP for this subnet. |
|||
# Set the lifetime to 46 hours. (Note: minimum lifetime is 2 hours.) |
|||
#dhcp-range=1234::, ra-only, 48h |
|||
|
|||
# Do DHCP and Router Advertisements for this subnet. Set the A bit in the RA |
|||
# so that clients can use SLAAC addresses as well as DHCP ones. |
|||
#dhcp-range=1234::2, 1234::500, slaac |
|||
|
|||
# Do Router Advertisements and stateless DHCP for this subnet. Clients will |
|||
# not get addresses from DHCP, but they will get other configuration information. |
|||
# They will use SLAAC for addresses. |
|||
#dhcp-range=1234::, ra-stateless |
|||
|
|||
# Do stateless DHCP, SLAAC, and generate DNS names for SLAAC addresses |
|||
# from DHCPv4 leases. |
|||
#dhcp-range=1234::, ra-stateless, ra-names |
|||
|
|||
# Do router advertisements for all subnets where we're doing DHCPv6 |
|||
# Unless overriden by ra-stateless, ra-names, et al, the router |
|||
# advertisements will have the M and O bits set, so that the clients |
|||
# get addresses and configuration from DHCPv6, and the A bit reset, so the |
|||
# clients don't use SLAAC addresses. |
|||
#enable-ra |
|||
|
|||
# Supply parameters for specified hosts using DHCP. There are lots |
|||
# of valid alternatives, so we will give examples of each. Note that |
|||
# IP addresses DO NOT have to be in the range given above, they just |
|||
# need to be on the same network. The order of the parameters in these |
|||
# do not matter, it's permissible to give name, address and MAC in any |
|||
# order. |
|||
|
|||
# Always allocate the host with Ethernet address 11:22:33:44:55:66 |
|||
# The IP address 192.168.0.60 |
|||
#dhcp-host=11:22:33:44:55:66,192.168.0.60 |
|||
|
|||
# Always set the name of the host with hardware address |
|||
# 11:22:33:44:55:66 to be "fred" |
|||
#dhcp-host=11:22:33:44:55:66,fred |
|||
|
|||
# Always give the host with Ethernet address 11:22:33:44:55:66 |
|||
# the name fred and IP address 192.168.0.60 and lease time 45 minutes |
|||
#dhcp-host=11:22:33:44:55:66,fred,192.168.0.60,45m |
|||
|
|||
# Give a host with Ethernet address 11:22:33:44:55:66 or |
|||
# 12:34:56:78:90:12 the IP address 192.168.0.60. Dnsmasq will assume |
|||
# that these two Ethernet interfaces will never be in use at the same |
|||
# time, and give the IP address to the second, even if it is already |
|||
# in use by the first. Useful for laptops with wired and wireless |
|||
# addresses. |
|||
#dhcp-host=11:22:33:44:55:66,12:34:56:78:90:12,192.168.0.60 |
|||
|
|||
# Give the machine which says its name is "bert" IP address |
|||
# 192.168.0.70 and an infinite lease |
|||
#dhcp-host=bert,192.168.0.70,infinite |
|||
|
|||
# Always give the host with client identifier 01:02:02:04 |
|||
# the IP address 192.168.0.60 |
|||
#dhcp-host=id:01:02:02:04,192.168.0.60 |
|||
|
|||
# Always give the host with client identifier "marjorie" |
|||
# the IP address 192.168.0.60 |
|||
#dhcp-host=id:marjorie,192.168.0.60 |
|||
|
|||
# Enable the address given for "judge" in /etc/hosts |
|||
# to be given to a machine presenting the name "judge" when |
|||
# it asks for a DHCP lease. |
|||
#dhcp-host=judge |
|||
|
|||
# Never offer DHCP service to a machine whose Ethernet |
|||
# address is 11:22:33:44:55:66 |
|||
#dhcp-host=11:22:33:44:55:66,ignore |
|||
|
|||
# Ignore any client-id presented by the machine with Ethernet |
|||
# address 11:22:33:44:55:66. This is useful to prevent a machine |
|||
# being treated differently when running under different OS's or |
|||
# between PXE boot and OS boot. |
|||
#dhcp-host=11:22:33:44:55:66,id:* |
|||
|
|||
# Send extra options which are tagged as "red" to |
|||
# the machine with Ethernet address 11:22:33:44:55:66 |
|||
#dhcp-host=11:22:33:44:55:66,set:red |
|||
|
|||
# Send extra options which are tagged as "red" to |
|||
# any machine with Ethernet address starting 11:22:33: |
|||
#dhcp-host=11:22:33:*:*:*,set:red |
|||
|
|||
# Give a fixed IPv6 address and name to client with |
|||
# DUID 00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2 |
|||
# Note the MAC addresses CANNOT be used to identify DHCPv6 clients. |
|||
# Note also the they [] around the IPv6 address are obilgatory. |
|||
#dhcp-host=id:00:01:00:01:16:d2:83:fc:92:d4:19:e2:d8:b2, fred, [1234::5] |
|||
|
|||
# Ignore any clients which are not specified in dhcp-host lines |
|||
# or /etc/ethers. Equivalent to ISC "deny unknown-clients". |
|||
# This relies on the special "known" tag which is set when |
|||
# a host is matched. |
|||
#dhcp-ignore=tag:!known |
|||
|
|||
# Send extra options which are tagged as "red" to any machine whose |
|||
# DHCP vendorclass string includes the substring "Linux" |
|||
#dhcp-vendorclass=set:red,Linux |
|||
|
|||
# Send extra options which are tagged as "red" to any machine one |
|||
# of whose DHCP userclass strings includes the substring "accounts" |
|||
#dhcp-userclass=set:red,accounts |
|||
|
|||
# Send extra options which are tagged as "red" to any machine whose |
|||
# MAC address matches the pattern. |
|||
#dhcp-mac=set:red,00:60:8C:*:*:* |
|||
|
|||
# If this line is uncommented, dnsmasq will read /etc/ethers and act |
|||
# on the ethernet-address/IP pairs found there just as if they had |
|||
# been given as --dhcp-host options. Useful if you keep |
|||
# MAC-address/host mappings there for other purposes. |
|||
#read-ethers |
|||
|
|||
# Send options to hosts which ask for a DHCP lease. |
|||
# See RFC 2132 for details of available options. |
|||
# Common options can be given to dnsmasq by name: |
|||
# run "dnsmasq --help dhcp" to get a list. |
|||
# Note that all the common settings, such as netmask and |
|||
# broadcast address, DNS server and default route, are given |
|||
# sane defaults by dnsmasq. You very likely will not need |
|||
# any dhcp-options. If you use Windows clients and Samba, there |
|||
# are some options which are recommended, they are detailed at the |
|||
# end of this section. |
|||
|
|||
# Override the default route supplied by dnsmasq, which assumes the |
|||
# router is the same machine as the one running dnsmasq. |
|||
#dhcp-option=3,1.2.3.4 |
|||
|
|||
# Do the same thing, but using the option name |
|||
#dhcp-option=option:router,1.2.3.4 |
|||
|
|||
# Override the default route supplied by dnsmasq and send no default |
|||
# route at all. Note that this only works for the options sent by |
|||
# default (1, 3, 6, 12, 28) the same line will send a zero-length option |
|||
# for all other option numbers. |
|||
#dhcp-option=3 |
|||
|
|||
# Set the NTP time server addresses to 192.168.0.4 and 10.10.0.5 |
|||
#dhcp-option=option:ntp-server,192.168.0.4,10.10.0.5 |
|||
|
|||
# Send DHCPv6 option. Note [] around IPv6 addresses. |
|||
#dhcp-option=option6:dns-server,[1234::77],[1234::88] |
|||
|
|||
# Send DHCPv6 option for namservers as the machine running |
|||
# dnsmasq and another. |
|||
#dhcp-option=option6:dns-server,[::],[1234::88] |
|||
|
|||
# Ask client to poll for option changes every six hours. (RFC4242) |
|||
#dhcp-option=option6:information-refresh-time,6h |
|||
|
|||
# Set the NTP time server address to be the same machine as |
|||
# is running dnsmasq |
|||
#dhcp-option=42,0.0.0.0 |
|||
|
|||
# Set the NIS domain name to "welly" |
|||
#dhcp-option=40,welly |
|||
|
|||
# Set the default time-to-live to 50 |
|||
#dhcp-option=23,50 |
|||
|
|||
# Set the "all subnets are local" flag |
|||
#dhcp-option=27,1 |
|||
|
|||
# Send the etherboot magic flag and then etherboot options (a string). |
|||
#dhcp-option=128,e4:45:74:68:00:00 |
|||
#dhcp-option=129,NIC=eepro100 |
|||
|
|||
# Specify an option which will only be sent to the "red" network |
|||
# (see dhcp-range for the declaration of the "red" network) |
|||
# Note that the tag: part must precede the option: part. |
|||
#dhcp-option = tag:red, option:ntp-server, 192.168.1.1 |
|||
|
|||
# The following DHCP options set up dnsmasq in the same way as is specified |
|||
# for the ISC dhcpcd in |
|||
# http://www.samba.org/samba/ftp/docs/textdocs/DHCP-Server-Configuration.txt |
|||
# adapted for a typical dnsmasq installation where the host running |
|||
# dnsmasq is also the host running samba. |
|||
# you may want to uncomment some or all of them if you use |
|||
# Windows clients and Samba. |
|||
#dhcp-option=19,0 # option ip-forwarding off |
|||
#dhcp-option=44,0.0.0.0 # set netbios-over-TCP/IP nameserver(s) aka WINS server(s) |
|||
#dhcp-option=45,0.0.0.0 # netbios datagram distribution server |
|||
#dhcp-option=46,8 # netbios node type |
|||
|
|||
# Send an empty WPAD option. This may be REQUIRED to get windows 7 to behave. |
|||
#dhcp-option=252,"\n" |
|||
|
|||
# Send RFC-3397 DNS domain search DHCP option. WARNING: Your DHCP client |
|||
# probably doesn't support this...... |
|||
#dhcp-option=option:domain-search,eng.apple.com,marketing.apple.com |
|||
|
|||
# Send RFC-3442 classless static routes (note the netmask encoding) |
|||
#dhcp-option=121,192.168.1.0/24,1.2.3.4,10.0.0.0/8,5.6.7.8 |
|||
|
|||
# Send vendor-class specific options encapsulated in DHCP option 43. |
|||
# The meaning of the options is defined by the vendor-class so |
|||
# options are sent only when the client supplied vendor class |
|||
# matches the class given here. (A substring match is OK, so "MSFT" |
|||
# matches "MSFT" and "MSFT 5.0"). This example sets the |
|||
# mtftp address to 0.0.0.0 for PXEClients. |
|||
#dhcp-option=vendor:PXEClient,1,0.0.0.0 |
|||
|
|||
# Send microsoft-specific option to tell windows to release the DHCP lease |
|||
# when it shuts down. Note the "i" flag, to tell dnsmasq to send the |
|||
# value as a four-byte integer - that's what microsoft wants. See |
|||
# http://technet2.microsoft.com/WindowsServer/en/library/a70f1bb7-d2d4-49f0-96d6-4b7414ecfaae1033.mspx?mfr=true |
|||
#dhcp-option=vendor:MSFT,2,1i |
|||
|
|||
# Send the Encapsulated-vendor-class ID needed by some configurations of |
|||
# Etherboot to allow is to recognise the DHCP server. |
|||
#dhcp-option=vendor:Etherboot,60,"Etherboot" |
|||
|
|||
# Send options to PXELinux. Note that we need to send the options even |
|||
# though they don't appear in the parameter request list, so we need |
|||
# to use dhcp-option-force here. |
|||
# See http://syslinux.zytor.com/pxe.php#special for details. |
|||
# Magic number - needed before anything else is recognised |
|||
#dhcp-option-force=208,f1:00:74:7e |
|||
# Configuration file name |
|||
#dhcp-option-force=209,configs/common |
|||
# Path prefix |
|||
#dhcp-option-force=210,/tftpboot/pxelinux/files/ |
|||
# Reboot time. (Note 'i' to send 32-bit value) |
|||
#dhcp-option-force=211,30i |
|||
|
|||
# Set the boot filename for netboot/PXE. You will only need |
|||
# this is you want to boot machines over the network and you will need |
|||
# a TFTP server; either dnsmasq's built in TFTP server or an |
|||
# external one. (See below for how to enable the TFTP server.) |
|||
#dhcp-boot=pxelinux.0 |
|||
|
|||
# The same as above, but use custom tftp-server instead machine running dnsmasq |
|||
#dhcp-boot=pxelinux,server.name,192.168.1.100 |
|||
|
|||
# Boot for Etherboot gPXE. The idea is to send two different |
|||
# filenames, the first loads gPXE, and the second tells gPXE what to |
|||
# load. The dhcp-match sets the gpxe tag for requests from gPXE. |
|||
#dhcp-match=set:gpxe,175 # gPXE sends a 175 option. |
|||
#dhcp-boot=tag:!gpxe,undionly.kpxe |
|||
#dhcp-boot=mybootimage |
|||
|
|||
# Encapsulated options for Etherboot gPXE. All the options are |
|||
# encapsulated within option 175 |
|||
#dhcp-option=encap:175, 1, 5b # priority code |
|||
#dhcp-option=encap:175, 176, 1b # no-proxydhcp |
|||
#dhcp-option=encap:175, 177, string # bus-id |
|||
#dhcp-option=encap:175, 189, 1b # BIOS drive code |
|||
#dhcp-option=encap:175, 190, user # iSCSI username |
|||
#dhcp-option=encap:175, 191, pass # iSCSI password |
|||
|
|||
# Test for the architecture of a netboot client. PXE clients are |
|||
# supposed to send their architecture as option 93. (See RFC 4578) |
|||
#dhcp-match=peecees, option:client-arch, 0 #x86-32 |
|||
#dhcp-match=itanics, option:client-arch, 2 #IA64 |
|||
#dhcp-match=hammers, option:client-arch, 6 #x86-64 |
|||
#dhcp-match=mactels, option:client-arch, 7 #EFI x86-64 |
|||
|
|||
# Do real PXE, rather than just booting a single file, this is an |
|||
# alternative to dhcp-boot. |
|||
#pxe-prompt="What system shall I netboot?" |
|||
# or with timeout before first available action is taken: |
|||
#pxe-prompt="Press F8 for menu.", 60 |
|||
|
|||
# Available boot services. for PXE. |
|||
#pxe-service=x86PC, "Boot from local disk" |
|||
|
|||
# Loads <tftp-root>/pxelinux.0 from dnsmasq TFTP server. |
|||
#pxe-service=x86PC, "Install Linux", pxelinux |
|||
|
|||
# Loads <tftp-root>/pxelinux.0 from TFTP server at 1.2.3.4. |
|||
# Beware this fails on old PXE ROMS. |
|||
#pxe-service=x86PC, "Install Linux", pxelinux, 1.2.3.4 |
|||
|
|||
# Use bootserver on network, found my multicast or broadcast. |
|||
#pxe-service=x86PC, "Install windows from RIS server", 1 |
|||
|
|||
# Use bootserver at a known IP address. |
|||
#pxe-service=x86PC, "Install windows from RIS server", 1, 1.2.3.4 |
|||
|
|||
# If you have multicast-FTP available, |
|||
# information for that can be passed in a similar way using options 1 |
|||
# to 5. See page 19 of |
|||
# http://download.intel.com/design/archives/wfm/downloads/pxespec.pdf |
|||
|
|||
|
|||
# Enable dnsmasq's built-in TFTP server |
|||
#enable-tftp |
|||
|
|||
# Set the root directory for files available via FTP. |
|||
#tftp-root=/var/ftpd |
|||
|
|||
# Make the TFTP server more secure: with this set, only files owned by |
|||
# the user dnsmasq is running as will be send over the net. |
|||
#tftp-secure |
|||
|
|||
# This option stops dnsmasq from negotiating a larger blocksize for TFTP |
|||
# transfers. It will slow things down, but may rescue some broken TFTP |
|||
# clients. |
|||
#tftp-no-blocksize |
|||
|
|||
# Set the boot file name only when the "red" tag is set. |
|||
#dhcp-boot=tag:red,pxelinux.red-net |
|||
|
|||
# An example of dhcp-boot with an external TFTP server: the name and IP |
|||
# address of the server are given after the filename. |
|||
# Can fail with old PXE ROMS. Overridden by --pxe-service. |
|||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,192.168.0.3 |
|||
|
|||
# If there are multiple external tftp servers having a same name |
|||
# (using /etc/hosts) then that name can be specified as the |
|||
# tftp_servername (the third option to dhcp-boot) and in that |
|||
# case dnsmasq resolves this name and returns the resultant IP |
|||
# addresses in round robin fasion. This facility can be used to |
|||
# load balance the tftp load among a set of servers. |
|||
#dhcp-boot=/var/ftpd/pxelinux.0,boothost,tftp_server_name |
|||
|
|||
# Set the limit on DHCP leases, the default is 150 |
|||
#dhcp-lease-max=150 |
|||
|
|||
# The DHCP server needs somewhere on disk to keep its lease database. |
|||
# This defaults to a sane location, but if you want to change it, use |
|||
# the line below. |
|||
#dhcp-leasefile=/var/lib/misc/dnsmasq.leases |
|||
|
|||
# Set the DHCP server to authoritative mode. In this mode it will barge in |
|||
# and take over the lease for any client which broadcasts on the network, |
|||
# whether it has a record of the lease or not. This avoids long timeouts |
|||
# when a machine wakes up on a new network. DO NOT enable this if there's |
|||
# the slightest chance that you might end up accidentally configuring a DHCP |
|||
# server for your campus/company accidentally. The ISC server uses |
|||
# the same option, and this URL provides more information: |
|||
# http://www.isc.org/files/auth.html |
|||
#dhcp-authoritative |
|||
|
|||
# Run an executable when a DHCP lease is created or destroyed. |
|||
# The arguments sent to the script are "add" or "del", |
|||
# then the MAC address, the IP address and finally the hostname |
|||
# if there is one. |
|||
#dhcp-script=/bin/echo |
|||
|
|||
# Set the cachesize here. |
|||
#cache-size=150 |
|||
|
|||
# If you want to disable negative caching, uncomment this. |
|||
#no-negcache |
|||
|
|||
# Normally responses which come from /etc/hosts and the DHCP lease |
|||
# file have Time-To-Live set as zero, which conventionally means |
|||
# do not cache further. If you are happy to trade lower load on the |
|||
# server for potentially stale date, you can set a time-to-live (in |
|||
# seconds) here. |
|||
#local-ttl= |
|||
|
|||
# If you want dnsmasq to detect attempts by Verisign to send queries |
|||
# to unregistered .com and .net hosts to its sitefinder service and |
|||
# have dnsmasq instead return the correct NXDOMAIN response, uncomment |
|||
# this line. You can add similar lines to do the same for other |
|||
# registries which have implemented wildcard A records. |
|||
#bogus-nxdomain=64.94.110.11 |
|||
|
|||
# If you want to fix up DNS results from upstream servers, use the |
|||
# alias option. This only works for IPv4. |
|||
# This alias makes a result of 1.2.3.4 appear as 5.6.7.8 |
|||
#alias=1.2.3.4,5.6.7.8 |
|||
# and this maps 1.2.3.x to 5.6.7.x |
|||
#alias=1.2.3.0,5.6.7.0,255.255.255.0 |
|||
# and this maps 192.168.0.10->192.168.0.40 to 10.0.0.10->10.0.0.40 |
|||
#alias=192.168.0.10-192.168.0.40,10.0.0.0,255.255.255.0 |
|||
|
|||
# Change these lines if you want dnsmasq to serve MX records. |
|||
|
|||
# Return an MX record named "maildomain.com" with target |
|||
# servermachine.com and preference 50 |
|||
#mx-host=maildomain.com,servermachine.com,50 |
|||
|
|||
# Set the default target for MX records created using the localmx option. |
|||
#mx-target=servermachine.com |
|||
|
|||
# Return an MX record pointing to the mx-target for all local |
|||
# machines. |
|||
#localmx |
|||
|
|||
# Return an MX record pointing to itself for all local machines. |
|||
#selfmx |
|||
|
|||
# Change the following lines if you want dnsmasq to serve SRV |
|||
# records. These are useful if you want to serve ldap requests for |
|||
# Active Directory and other windows-originated DNS requests. |
|||
# See RFC 2782. |
|||
# You may add multiple srv-host lines. |
|||
# The fields are <name>,<target>,<port>,<priority>,<weight> |
|||
# If the domain part if missing from the name (so that is just has the |
|||
# service and protocol sections) then the domain given by the domain= |
|||
# config option is used. (Note that expand-hosts does not need to be |
|||
# set for this to work.) |
|||
|
|||
# A SRV record sending LDAP for the example.com domain to |
|||
# ldapserver.example.com port 389 |
|||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389 |
|||
|
|||
# A SRV record sending LDAP for the example.com domain to |
|||
# ldapserver.example.com port 389 (using domain=) |
|||
#domain=example.com |
|||
#srv-host=_ldap._tcp,ldapserver.example.com,389 |
|||
|
|||
# Two SRV records for LDAP, each with different priorities |
|||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,1 |
|||
#srv-host=_ldap._tcp.example.com,ldapserver.example.com,389,2 |
|||
|
|||
# A SRV record indicating that there is no LDAP server for the domain |
|||
# example.com |
|||
#srv-host=_ldap._tcp.example.com |
|||
|
|||
# The following line shows how to make dnsmasq serve an arbitrary PTR |
|||
# record. This is useful for DNS-SD. (Note that the |
|||
# domain-name expansion done for SRV records _does_not |
|||
# occur for PTR records.) |
|||
#ptr-record=_http._tcp.dns-sd-services,"New Employee Page._http._tcp.dns-sd-services" |
|||
|
|||
# Change the following lines to enable dnsmasq to serve TXT records. |
|||
# These are used for things like SPF and zeroconf. (Note that the |
|||
# domain-name expansion done for SRV records _does_not |
|||
# occur for TXT records.) |
|||
|
|||
#Example SPF. |
|||
#txt-record=example.com,"v=spf1 a -all" |
|||
|
|||
#Example zeroconf |
|||
#txt-record=_http._tcp.example.com,name=value,paper=A4 |
|||
|
|||
# Provide an alias for a "local" DNS name. Note that this _only_ works |
|||
# for targets which are names from DHCP or /etc/hosts. Give host |
|||
# "bert" another name, bertrand |
|||
#cname=bertand,bert |
|||
|
|||
# For debugging purposes, log each DNS query as it passes through |
|||
# dnsmasq. |
|||
#log-queries |
|||
|
|||
# Log lots of extra information about DHCP transactions. |
|||
#log-dhcp |
|||
|
|||
# Include another lot of configuration options. |
|||
#conf-file=/etc/dnsmasq.more.conf |
|||
#conf-dir=/etc/dnsmasq.d |
|||
|
|||
# Include all the files in a directory except those ending in .bak |
|||
#conf-dir=/etc/dnsmasq.d,.bak |
|||
|
|||
# Include all files in a directory which end in .conf |
|||
#conf-dir=/etc/dnsmasq.d/*.conf |
|||
|
|||
|
|||
domain-needed |
|||
bogus-priv |
|||
filterwin2k |
|||
|
|||
localise-queries |
|||
local=/bobine.lol/ |
|||
domain=bobine.lol |
|||
expand-hosts |
|||
no-negcache |
|||
# Fichier contenant la définition des serveurs en amont |
|||
# (au lieu de /etc/resolv.conf) |
|||
resolv-file=/etc/resolv.dnsmasq |
|||
|
|||
dhcp-authoritative |
|||
dhcp-leasefile=/tmp/dhcp.leases |
|||
|
|||
# use /etc/ethers for static hosts; same format as --dhcp-host |
|||
read-ethers |
|||
|
|||
# Add domains which you want to force to an IP address here. |
|||
# The example below send any host in double-click.net to a local |
|||
# web-server. |
|||
# address=/in.bobine.lol/192.168.1.2 |
|||
|
|||
|
|||
# Plage DHCP |
|||
dhcp-range=192.168.1.5,192.168.1.250,1m |
|||
# Netmask |
|||
dhcp-option=1,255.255.255.0 |
|||
# Route |
|||
dhcp-option=3,192.168.1.1 |
|||
# DNS |
|||
#dhcp-option=6,192.168.1.2,8.8.8.8 |
|||
dhcp-option=6,192.168.1.2,192.168.1.2 |
|||
|
|||
# Ajouter une directive de journalisation, non incluse par défaut |
|||
log-facility=/var/log/dnsmasq.log |
|||
|
|||
# Pour le débogage, journaliser chaque requête DNS qui passe par Dnsmasq. |
|||
log-queries |
|||
|
|||
# Journaliser beaucoup d'informations supplémentaires sur les transactions DHCP. |
|||
log-dhcp |
|||
@ -0,0 +1,11 @@ |
|||
127.0.0.1 localhost |
|||
192.168.1.2 bobinoscope |
|||
|
|||
192.168.1.2 ma.bobine.lol |
|||
192.168.1.2 box.bobine.lol |
|||
|
|||
|
|||
# The following lines are desirable for IPv6 capable hosts |
|||
::1 localhost ip6-localhost ip6-loopback |
|||
ff02::1 ip6-allnodes |
|||
ff02::2 ip6-allrouters |
|||
@ -1,63 +0,0 @@ |
|||
const path = require('path') |
|||
const express = require('express') |
|||
const app = express() |
|||
const logger = require('morgan') |
|||
const cookieParser = require('cookie-parser') |
|||
const bodyParser = require('body-parser') |
|||
const opn = require('opn') |
|||
|
|||
const booth = require('./booth') |
|||
|
|||
const CFG = require('../config') |
|||
const PKG = require('../package') |
|||
|
|||
// view engine setup
|
|||
app.set('views', path.join(__dirname, 'views')) |
|||
app.set('view engine', 'ejs') |
|||
app.use(logger('dev')) |
|||
app.use(bodyParser.json()) |
|||
app.use(bodyParser.urlencoded({ extended: false })) |
|||
app.use(cookieParser()) |
|||
app.use(express.static(path.join(__dirname, 'public'))) |
|||
|
|||
app.use('/booth', booth) |
|||
|
|||
app.get('/', (req, res) => { |
|||
res.render('index', { |
|||
serverIpAddress: CFG.server.ipAddress, |
|||
serverPort: CFG.server.port |
|||
}) |
|||
}) |
|||
|
|||
app.get('/test', (req, res) => { |
|||
res.render('test', { |
|||
serverIpAddress: CFG.server.ipAddress, |
|||
serverPort: CFG.server.port |
|||
}) |
|||
}) |
|||
|
|||
app.get('/bobinoscope', (req, res) => { |
|||
res.render('scope', { |
|||
serverIpAddress: CFG.server.ipAddress, |
|||
serverPort: CFG.server.port, |
|||
killZone: CFG.killZone, |
|||
renderingTime: 5000 |
|||
}) |
|||
}) |
|||
|
|||
module.exports = function (pArgs) { |
|||
let server = app.listen(CFG.server.port, () => { |
|||
console.log(`[-] Server running on: ${CFG.server.ipAddress}:${CFG.server.port}`) |
|||
}) |
|||
// Socket Io
|
|||
app.locals.io = require('socket.io')(server) |
|||
booth.setSocketIo(app.locals.io) |
|||
|
|||
if (!pArgs.noc) { |
|||
console.log(`[-] Starting chromium...`) |
|||
opn('http://localhost:3111/bobinoscope', { |
|||
app: ['chromium-browser', '--app=http://localhost:3111/bobinoscope', '--start-fullscreen', '--password-store=basic'] |
|||
}) |
|||
} |
|||
return app |
|||
} |
|||
8
server/public/js/socket.io.js
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1
server/public/js/socket.io.js.map
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -1,251 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<title>Studio</title> |
|||
<!-- Latest compiled and minified CSS --> |
|||
<link rel="stylesheet" href="/css/bootstrap.min.css"> |
|||
<link rel="stylesheet" href="/css/cover.css"/> |
|||
</head> |
|||
<body> |
|||
<div class="site-wrapper"> |
|||
<div class="site-wrapper-inner"> |
|||
<div class="cover-container"> |
|||
<div class="inner cover" style="height:900px;position:relative"> |
|||
|
|||
<div id="idBoothPanel" style="position:absolute;width:100%"> |
|||
<div style="padding-top:1em"> |
|||
<div id="idViewCountdown" style="font-size:20em; display:none"></div> |
|||
<div id="idViewTrigger" style="display:block"> |
|||
<h1 class="cover-heading">Prends ta bobine !</h1> |
|||
<br/><br/> |
|||
<div style="width:800px;height:600px;position:relative;display:none"> |
|||
<video id="player" autoplay="true" style="height:100%;width:100%;position:absolute;left:0;top:0"></video> |
|||
<div style="position:absolute;background:#3C0000;top:0;left:0;width:<%= killZone.left%>%;height:100%;opacity:0.9"></div> |
|||
<div style="position:absolute;background:#3C0000;top:0;right:0;width:<%= killZone.right%>%;height:100%;opacity:0.9"></div> |
|||
<div style="position:absolute;background:#3C0000;top:0;left:<%= killZone.left%>%;right:<%= killZone.right%>%;height:<%= killZone.top%>%;opacity:0.9"></div> |
|||
<div style="position:absolute;background:#3C0000;bottom:0;left:<%= killZone.left%>%;right:<%= killZone.right%>%;height:<%= killZone.bottom%>%;opacity:0.9"></div> |
|||
</div> |
|||
</div> |
|||
<div id="idViewGenerating" style="display:none"> |
|||
<h1 class="cover-heading">Bobinogramme <i>en cours de génération...</i></h1> |
|||
<br/><br/> |
|||
<h3>Merci de bien vouloir patienter<br/>quelques secondes</h3> |
|||
<br/> |
|||
<br/> |
|||
<div style="position:relative;width:100%;height:2px;background:#444"> |
|||
<div id="idProgressBar" style="background:#fff;height:2px; width:0%;transition: all 200ms ease"></div> |
|||
</div> |
|||
</div> |
|||
<div id="idViewBobinogramme" style="display:none"> |
|||
<img src="" height="600px"/> |
|||
<!-- <h3 class="cover-heading">Retrouve ton <b>bobinogramme</b> sur <br/>http://<%= serverIpAddress %>:<%= serverPort %></h3> --> |
|||
</div> |
|||
</div> |
|||
<div id="idViewDoIt" style="font-size:8em; height:600px; display:none"> |
|||
Faites<br/> |
|||
<span id="idViewDoIt-theme" style="font-size:2em">le chat</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="idPictPreview" style="position:absolute;display:none;width:100%"> |
|||
<img src="" height="900px"> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mastfoot"> |
|||
<div class="inner"> |
|||
<p>BW Bros.</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</body> |
|||
<!-- Latest compiled and minified JQuery --> |
|||
<script src="/js/jquery-1.11.2.min.js"></script> |
|||
<!-- Latest compiled and minified javaScript bootstrap--> |
|||
<script src="/js/bootstrap.min.js"></script> |
|||
<!-- Getting the Socket.IO Client --> |
|||
<script src="/js/socket.io.js"></script> |
|||
</html> |
|||
|
|||
<style type="text/css"> |
|||
* { |
|||
-webkit-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
} |
|||
</style> |
|||
|
|||
<script type="text/javascript"> |
|||
|
|||
var socket = io('/'); |
|||
|
|||
socket.on('connect', function() { |
|||
console.log("connect") |
|||
}) |
|||
|
|||
socket.on('boothClick', function(pData) { |
|||
BOB_runBooth(); |
|||
}); |
|||
|
|||
var BOB_var_context = { |
|||
boothOnGoing : false, |
|||
initTimer : 3, |
|||
onGoingTimer : 0, |
|||
boothId : null, |
|||
nbError : 0, |
|||
pictureId : 0 |
|||
} |
|||
|
|||
var BOB_var_themes = { |
|||
selectedId : 0, |
|||
list : [ |
|||
"le chat", |
|||
"le cuir moustache", |
|||
"le roi", |
|||
"le bouffon", |
|||
"le moussailon", |
|||
"le geek", |
|||
"l'amoureux", |
|||
] |
|||
} |
|||
|
|||
$(document).ready(function() { |
|||
$(document).keypress(function (e) { |
|||
if (e.which === 32) BOB_runBooth() |
|||
}) |
|||
}) |
|||
|
|||
function BOB_runBooth() { |
|||
if( BOB_var_context.boothOnGoing === false ) { |
|||
var currentDate = new Date(); |
|||
BOB_var_context.boothOnGoing = true; |
|||
BOB_var_context.boothId = currentDate.getTime(); |
|||
BOB_var_context.pictureId = 0; |
|||
BOB_var_context.onGoingTimer = BOB_var_context.initTimer; |
|||
|
|||
$('#idViewTrigger').fadeOut(500, function() { |
|||
BOB_countdown(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function BOB_countdown() { |
|||
$('#idViewCountdown').fadeIn(); |
|||
$('#idViewCountdown').css('fontSize', '20em') |
|||
$('#idViewCountdown').html(BOB_var_context.onGoingTimer); |
|||
// |
|||
if( BOB_var_context.onGoingTimer > 5 ) { |
|||
// $('#idViewDoIt').show(); |
|||
// $('#idViewDoIt-theme').hide(); |
|||
} else if( BOB_var_context.onGoingTimer > 2 ) { |
|||
// $('#idViewDoIt-theme').html( BOB_var_themes.list[BOB_var_themes.selectedId] ); |
|||
// $('#idViewDoIt-theme').show(); |
|||
} |
|||
|
|||
if( BOB_var_context.onGoingTimer > 0 ) { |
|||
setTimeout(function() { |
|||
BOB_var_context.onGoingTimer -= 1; |
|||
BOB_countdown(); |
|||
}, 1000) |
|||
} else { |
|||
$('#idViewCountdown').html("Souriez"); |
|||
$('#idViewCountdown').css('fontSize', '14em') |
|||
BOB_takeThe1Pictures(); |
|||
} |
|||
} |
|||
|
|||
function BOB_displayPictPreview(pBoothId, pPictureId, pCallback) { |
|||
$('#idViewCountdown').html(""); |
|||
$('#idPictPreview > img').attr('src', '/img/prebuilt/'+pBoothId+'/pict_'+pPictureId+'.jpg'); |
|||
$('#idBoothPanel').fadeOut(50, function() { |
|||
$('#idPictPreview').show(); |
|||
setTimeout(function() { |
|||
$('#idPictPreview').hide(); |
|||
$('#idBoothPanel').fadeIn(50, function() { |
|||
pCallback() |
|||
}) |
|||
}, 4000) |
|||
}) |
|||
} |
|||
|
|||
var BOB_var_progressTimer = new Date(); |
|||
|
|||
function BOB_lauchFakeProgressBar() { |
|||
setTimeout(function() { |
|||
var progress = (new Date() - BOB_var_progressTimer) / <%= renderingTime %> * 100; |
|||
$('#idProgressBar').css('width', progress+'%'); |
|||
if( progress < 100 ) { |
|||
BOB_lauchFakeProgressBar(); |
|||
} |
|||
}, 500) |
|||
} |
|||
|
|||
function BOB_showError () { |
|||
BOB_var_context.nbError += 1 |
|||
$('#idViewCountdown').fadeIn() |
|||
$('#idViewCountdown').css('fontSize', '3em') |
|||
if (BOB_var_context.nbError >= 3) { |
|||
BOB_var_context.nbError = 0 |
|||
$('#idViewCountdown').html("Oulala, le bobinoscope se sent pas<br/>très bien<br/>Revenez plus tard !") |
|||
setTimeout(function () { |
|||
$('#idViewCountdown').fadeOut(500, function() { |
|||
$('#idViewTrigger').fadeIn(); |
|||
}) |
|||
}, 5000) |
|||
} else { |
|||
$('#idViewCountdown').html("Oops ! Un problème de pellicule ...<br/>On recommence") |
|||
BOB_var_context.onGoingTimer = BOB_var_context.initTimer |
|||
setTimeout(BOB_countdown, 4000) |
|||
} |
|||
} |
|||
|
|||
function BOB_takeThe1Pictures() { |
|||
$.get('/booth/dslr/takepicture/'+BOB_var_context.boothId+'/'+BOB_var_context.pictureId, function(pResponse) { |
|||
if( pResponse.error ) { |
|||
// if( confirm(pResponse.error) ) { |
|||
// BOB_var_context.boothOnGoing = false; |
|||
// $('#idViewCountdown').fadeOut(500, function() { |
|||
// $('#idViewTrigger').fadeIn(); |
|||
// }); |
|||
// return; |
|||
// } |
|||
BOB_showError() |
|||
return |
|||
} |
|||
|
|||
BOB_var_context.pictureId += 1 |
|||
BOB_var_context.nbError = 0 |
|||
|
|||
if( BOB_var_context.pictureId < 4 ) { |
|||
BOB_var_context.onGoingTimer = BOB_var_context.initTimer |
|||
BOB_countdown(); |
|||
} else { |
|||
$('#idViewCountdown').fadeOut(500, function() { |
|||
BOB_var_progressTimer = new Date(); |
|||
$('#idProgressBar').css('width', '0'); |
|||
$('#idViewGenerating').fadeIn(); |
|||
BOB_lauchFakeProgressBar() |
|||
}) |
|||
$.get('/booth/build/'+BOB_var_context.boothId, function(pResponse) { |
|||
$('#idViewBobinogramme > img').attr('src', '/booth/build/result/low/'+pResponse.boothId+'.jpg'); |
|||
$('#idViewGenerating').fadeOut(500, function() { |
|||
$('#idViewBobinogramme').fadeIn(500, function() { |
|||
setTimeout(function(){ |
|||
BOB_var_context.boothOnGoing = false; |
|||
$('#idViewBobinogramme').fadeOut(500, function() { |
|||
$('#idViewTrigger').fadeIn(); |
|||
}); |
|||
}, 10000) |
|||
}) |
|||
}) |
|||
}); |
|||
} |
|||
}) |
|||
} |
|||
|
|||
</script> |
|||
@ -1,62 +0,0 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<title>Bobinoscope</title> |
|||
<!-- Latest compiled and minified CSS --> |
|||
<link rel="stylesheet" href="/css/view.css"/> |
|||
</head> |
|||
<body> |
|||
<div id="idMain" style="margin: auto"> |
|||
<p> |
|||
<button onclick="takePicture()">Prendre une photo</button> |
|||
</p> |
|||
<div id="idViewLoading"> |
|||
<img src='/waiting2.gif'/> |
|||
</div> |
|||
<div id="idViewContainer"> |
|||
|
|||
</div> |
|||
</div> |
|||
</body> |
|||
<!-- Latest compiled and minified JQuery --> |
|||
<script src="/js/jquery-1.11.2.min.js"></script> |
|||
</html> |
|||
|
|||
<style type="text/css"> |
|||
#idViewContainer { |
|||
background-size: contain; |
|||
background-repeat: no-repeat; |
|||
background-position: center; |
|||
/* background-origin: */ |
|||
} |
|||
</style> |
|||
|
|||
<script type="text/javascript"> |
|||
|
|||
// var socket = io('http://<%= serverIpAddress %>:<%= serverPort %>'); |
|||
// socket.on('connect', function() { |
|||
// console.log("connect") |
|||
// }) |
|||
// socket.on('boothState', function (data) { |
|||
// BOB_getBooths(); |
|||
// }) |
|||
|
|||
$(document).ready(function() { |
|||
$('#idViewLoading').hide() |
|||
$('#idViewContainer').css('height', 90 * $(document).height() / 100) |
|||
// console.log() |
|||
}) |
|||
|
|||
function takePicture () { |
|||
$('#idViewLoading').fadeIn() |
|||
|
|||
$.get('/booth/test/takepicture', function (pResponse) { |
|||
$('#idViewLoading').fadeOut() |
|||
$('#idViewContainer').css('backgroundImage', 'url("/booth/test/takepicture/result?time='+(new Date()).getTime()+'")') |
|||
}) |
|||
} |
|||
|
|||
</script> |
|||
@ -1,144 +1,154 @@ |
|||
const exec = require('child_process').exec |
|||
const path = require('path') |
|||
const async = require('async') |
|||
const splitLines = require('split-lines') |
|||
const mkdirp = require('mkdirp') |
|||
const fs = require('fs-extra') |
|||
|
|||
require('colors') |
|||
|
|||
var CFG = require('../config') |
|||
|
|||
let tools = {} |
|||
|
|||
function execGphoto2 (pArgs, pMore, pCallback) { |
|||
let args, more, callback |
|||
if (pCallback) { |
|||
args = pArgs |
|||
more = pMore |
|||
callback = pCallback |
|||
} else { |
|||
args = pArgs |
|||
more = {} |
|||
callback = pMore |
|||
} |
|||
exec(`gphoto2 ${args}`, more, function (pErr, pStdout, pStderr) { |
|||
if (pErr) { |
|||
// console.log(`[!] Please install gphoto2`.red)
|
|||
// console.log(`sudo apt-get install gphoto2`.bgMagenta)
|
|||
// console.log(`[-] Bobinoscope will close in 10 seconds...`)
|
|||
// console.log('[!]', pErr)
|
|||
callback(pErr) |
|||
// setTimeout(function () {
|
|||
// process.exit(1)
|
|||
// }, 10000)
|
|||
return |
|||
} |
|||
let error = null |
|||
let outInLines = [] |
|||
if (/Error/i.test(pStderr)) { |
|||
error = pStderr |
|||
} |
|||
if (pStdout) { |
|||
outInLines = splitLines(pStdout) |
|||
} |
|||
callback(error, outInLines) |
|||
}) |
|||
} |
|||
var BOB_mod_gm = require('gm').subClass({ imageMagick: true }); |
|||
// var BOB_mod_gphoto2 = require('gphoto2');
|
|||
// var BOB_var_gphoto = new BOB_mod_gphoto2.GPhoto2();
|
|||
var BOB_mod_fs = require('fs'); |
|||
var BOB_mod_path = require('path'); |
|||
var BOB_mod_mkdirp = require('mkdirp'); |
|||
|
|||
tools.checkVersion = function (pCb) { |
|||
console.log('[-] Checking gphoto2 installation...'.bgBlue) |
|||
execGphoto2('--version', function (pErr, pStdout) { |
|||
if (pErr) { |
|||
console.log(`KO`.red) |
|||
} else { |
|||
console.log(`OK: ${pStdout[0]}`.green) |
|||
} |
|||
pCb(pErr) |
|||
var BOB_mod_exec = require('child_process').exec; |
|||
|
|||
var BOB_cfg_config = null; |
|||
|
|||
var BOB_var_camera = null; |
|||
|
|||
var BOB_module = {}; |
|||
|
|||
var BOB_tmpPict = "/home/odroid/bobine-tmp.jpg" |
|||
|
|||
BOB_upCameraReference(function() {}); |
|||
|
|||
function BOB_takePicture(pCallback) { |
|||
BOB_mod_exec("gphoto2 --capture-image-and-download --filename="+BOB_tmpPict+" --force-overwrite", function(pErr, pStdout, pStderr) { |
|||
console.log("takePicture", pErr || pStdout || pStderr) |
|||
console.log(pErr, pStdout, pStderr) |
|||
return pCallback(pErr) |
|||
}) |
|||
} |
|||
|
|||
tools.checkCameraConnection = function (pCb) { |
|||
console.log('[-] Checking camera connection...'.bgBlue) |
|||
execGphoto2('--auto-detect', function (pErr, pStdout) { |
|||
let device = pStdout && pStdout.length ? pStdout[2] : null |
|||
if (pErr || !device) { |
|||
console.log(`[!] Camera not connected`.red) |
|||
console.log('1. Connect camera via USB'.bgMagenta) |
|||
console.log('2. Turn on the camera'.bgMagenta) |
|||
console.log('3. Maybe - Force manual focus on camera'.bgMagenta) |
|||
pCb(pErr || 'CameraNotFound') |
|||
// console.log(`\n\n[-] Bobinoscope will close in 10 seconds...`)
|
|||
// setTimeout(function () {
|
|||
// process.exit(1)
|
|||
// }, 10000)
|
|||
// return
|
|||
} else { |
|||
console.log(`OK: ${device}`.green) |
|||
pCb() |
|||
} |
|||
}) |
|||
function BOB_upCameraReference(pCallback) { |
|||
// List cameras / assign list item to variable to use below options
|
|||
//if( BOB_var_camera === null ) {
|
|||
// BOB_var_gphoto.list(function (list) {
|
|||
// if (list.length === 0) {
|
|||
// return pCallback();
|
|||
// } else {
|
|||
// console.log(list)
|
|||
// BOB_var_camera = list[0];
|
|||
// console.log(BOB_var_camera.model);
|
|||
// return pCallback();
|
|||
// }
|
|||
// })
|
|||
//} else {
|
|||
return pCallback(); |
|||
//}
|
|||
} |
|||
|
|||
tools.__takeOnePicture = function (pPath, pCb) { |
|||
let lPath = path.parse(pPath) |
|||
execGphoto2(`--capture-image-and-download --filename=${lPath.base} --force-overwrite`, {cwd: lPath.dir}, pCb) |
|||
BOB_module.getConfig = function(pCallback) { |
|||
BOB_var_camera.getConfig(pCallback); |
|||
} |
|||
|
|||
tools.takeOnePicture = function (pBoothId, pPictId, pCallback) { |
|||
let destPict = '/tmp/bobine.jpg' |
|||
var destPath = path.join(CFG.paths.original, pBoothId) |
|||
var pictOrig = path.join(destPath, CFG.pictNames[pPictId]) |
|||
BOB_module.takePicture = function(pBoothId, pPictId, pCallback) { |
|||
var destPath = BOB_mod_path.join(BOB_cfg_config.paths.original, pBoothId); |
|||
var pbltPath = BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId); |
|||
var pictOrig = BOB_mod_path.join(destPath, BOB_cfg_config.pictNames[pPictId]); |
|||
var pictPblt = BOB_mod_path.join(destPath, BOB_cfg_config.pictNames[pPictId]); |
|||
|
|||
BOB_mod_mkdirp.sync(BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId)); |
|||
|
|||
mkdirp.sync(path.join(CFG.paths.prebuilt, pBoothId)) |
|||
console.log("new") |
|||
|
|||
tools.__takeOnePicture(destPict, function (pErr) { |
|||
BOB_takePicture(function (pErr) { |
|||
// If error occurs
|
|||
if (pErr) return pCallback(pErr) |
|||
mkdirp(destPath, function () { |
|||
fs.copy(destPict, pictOrig, function (pErr) { |
|||
return pCallback(pErr, pictOrig) |
|||
if( pErr ) { |
|||
return pCallback(pErr) |
|||
// Else write file on ddisk
|
|||
} else { |
|||
BOB_mod_mkdirp(destPath, function() { |
|||
copyFile(BOB_tmpPict, pictOrig, function(pErr) { |
|||
return pCallback(pErr, pictOrig) |
|||
}); |
|||
}) |
|||
}) |
|||
}) |
|||
} |
|||
}); |
|||
} |
|||
|
|||
tools.init = function (pCb) { |
|||
let tasks = [] |
|||
tasks.push(tools.checkVersion) |
|||
tasks.push(tools.checkCameraConnection) |
|||
tasks.push(function (pCb) { |
|||
let output = '/tmp/bobine-dummy.jpg' |
|||
console.log('[-] Taking dummy photo...'.bgBlue) |
|||
tools.__takeOnePicture(output, function (pErr) { |
|||
if (pErr) { |
|||
console.log(`[!] Failed to take picture`.red) |
|||
console.log(pErr.grey) |
|||
console.log('1. Add one SDCard into the device') |
|||
console.log('2. Take one picture manually') |
|||
} else { |
|||
console.log(`OK: ${output}`.green) |
|||
} |
|||
pCb(pErr) |
|||
}) |
|||
|
|||
// opn(output)
|
|||
// .then(function () {
|
|||
// console.log('OK'.green)
|
|||
// pCb()
|
|||
// })
|
|||
}) |
|||
|
|||
async.waterfall(tasks, function (pErr) { |
|||
if (pErr) { |
|||
console.log('[!] Bobinoscope init failed... Retry in 10 seconds'.red) |
|||
setTimeout(function () { |
|||
tools.init(pCb) |
|||
}, 10000) |
|||
function copyFile(source, target, cb) { |
|||
var cbCalled = false; |
|||
|
|||
var rd = BOB_mod_fs.createReadStream(source); |
|||
rd.on("error", function(err) { |
|||
done(err); |
|||
}); |
|||
var wr = BOB_mod_fs.createWriteStream(target); |
|||
wr.on("error", function(err) { |
|||
done(err); |
|||
}); |
|||
wr.on("close", function(ex) { |
|||
done(); |
|||
}); |
|||
rd.pipe(wr); |
|||
|
|||
function done(err) { |
|||
if (!cbCalled) { |
|||
cb(err); |
|||
cbCalled = true; |
|||
} |
|||
} |
|||
} |
|||
|
|||
BOB_module.takePictureNpm = function(pBoothId, pPictId, pCallback) { |
|||
var destPath = BOB_mod_path.join(BOB_cfg_config.paths.original, pBoothId); |
|||
var pbltPath = BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId); |
|||
var pictOrig = BOB_mod_path.join(destPath, BOB_cfg_config.pictNames[pPictId]); |
|||
var pictPblt = BOB_mod_path.join(destPath, BOB_cfg_config.pictNames[pPictId]); |
|||
|
|||
console.log("1"); |
|||
BOB_mod_mkdirp.sync(BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId)); |
|||
console.log("2"); |
|||
|
|||
BOB_upCameraReference(function() { |
|||
console.log("3"); |
|||
|
|||
if( BOB_var_camera === null ) { |
|||
return pCallback("No camera found"); |
|||
} else { |
|||
pCb() |
|||
console.log("4"); |
|||
|
|||
BOB_var_camera.takePicture({download: true}, function (pErr, pData) { |
|||
// If error occurs
|
|||
if( pErr ) { |
|||
return pCallback(pErr) |
|||
// Else write file on ddisk
|
|||
} else { |
|||
console.log("5"); |
|||
|
|||
BOB_mod_mkdirp(destPath, function() { |
|||
console.log("6"); |
|||
|
|||
BOB_mod_fs.writeFile(pictOrig, pData, function(pErr) { |
|||
console.log("7"); |
|||
|
|||
// BOB_mod_gm(pictOrig)
|
|||
// .autoOrient()
|
|||
// .gravity('Center')
|
|||
// // .resize(BOB_cfg_config.cropSize.width, BOB_cfg_config.cropSize.height, "^")
|
|||
// // .crop(BOB_cfg_config.cropSize.width, BOB_cfg_config.cropSize.height)
|
|||
// // .modulate(100, 0)
|
|||
// // .contrast(+2)
|
|||
// .write(pictOrig, function(pErr) {
|
|||
// return pCallback(pErr, pictPblt)
|
|||
// })
|
|||
return pCallback(pErr, pictOrig) |
|||
}); |
|||
}) |
|||
} |
|||
}); |
|||
} |
|||
}) |
|||
} |
|||
|
|||
module.exports = tools |
|||
module.exports = function(pConfig) { |
|||
BOB_cfg_config = pConfig; |
|||
return BOB_module; |
|||
} |
|||
@ -1,155 +1,153 @@ |
|||
var gm = require('gm').subClass({ imageMagick: true }) |
|||
var async = require('async') |
|||
var path = require('path') |
|||
var fs = require('fs') |
|||
var mkdirp = require('mkdirp') |
|||
var BOB_mod_gm = require('gm').subClass({ imageMagick: true }); |
|||
var BOB_mod_async = require('async'); |
|||
var BOB_mod_path = require('path'); |
|||
var BOB_mod_fs = require('fs'); |
|||
var BOB_mod_mkdirp = require('mkdirp'); |
|||
|
|||
var CFG = require('../config') |
|||
var BOB_cfg_config = null; |
|||
|
|||
var tools = {} |
|||
var BOB_module = {}; |
|||
|
|||
tools.getBoothList = function (pFrom, pCallback) { |
|||
fs.readdir(CFG.paths.final, function (pErr, pBoothList) { |
|||
var boothList = pBoothList ? pBoothList.sort() : [] |
|||
boothList = boothList.splice(boothList.indexOf(pFrom) + 1) |
|||
pCallback(pErr, boothList) |
|||
BOB_module.getBoothList = function(pFrom, pCallback) { |
|||
BOB_mod_fs.readdir(BOB_cfg_config.paths.final, function(pErr, pBoothList) { |
|||
var boothList = pBoothList ? pBoothList.sort() : []; |
|||
|
|||
boothList = boothList.splice(boothList.indexOf(pFrom) + 1); |
|||
|
|||
pCallback(pErr, boothList); |
|||
}) |
|||
} |
|||
|
|||
tools.buildBooth = function (pBoothId, pCallback) { |
|||
BOB_module.buildBooth = function(pBoothId, pCallback) { |
|||
// Create output prebuild directory
|
|||
mkdirp.sync(path.join(CFG.paths.prebuilt, pBoothId)) |
|||
BOB_mod_mkdirp.sync(BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId)); |
|||
// Resize pictures
|
|||
async.mapSeries(CFG.pictNames, |
|||
function (pPictName, pCb) { |
|||
var srcPict = path.join(CFG.paths.original, pBoothId, pPictName) |
|||
var dstPict = path.join(CFG.paths.prebuilt, pBoothId, pPictName) |
|||
BOB_mod_async.mapSeries(BOB_cfg_config.pictNames, |
|||
function(pPictName, pCb) { |
|||
var srcPict = BOB_mod_path.join(BOB_cfg_config.paths.original, pBoothId, pPictName); |
|||
var dstPict = BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId, pPictName); |
|||
|
|||
console.log('Resizing ' + dstPict) |
|||
console.log("Resizing "+dstPict); |
|||
|
|||
gm(srcPict) |
|||
BOB_mod_gm(srcPict) |
|||
.autoOrient() |
|||
.gravity('Center') |
|||
.resize(CFG.cropSize.width, CFG.cropSize.height, '^') |
|||
.crop(CFG.cropSize.width, CFG.cropSize.height) |
|||
.write(dstPict, function (pErr) { |
|||
if (pErr) console.log('Failed to resize picture', pErr) |
|||
.resize(BOB_cfg_config.cropSize.width, BOB_cfg_config.cropSize.height, "^") |
|||
.crop(BOB_cfg_config.cropSize.width, BOB_cfg_config.cropSize.height) |
|||
.write(dstPict, function(pErr) { |
|||
if(pErr) console.log("Failed to resize picture", pErr) |
|||
pCb() |
|||
}) |
|||
}, |
|||
function (pErr) { |
|||
console.log('Building booth') |
|||
switch (CFG.style) { |
|||
function(pErr) { |
|||
console.log("Building booth") |
|||
switch(BOB_cfg_config.style) { |
|||
default : |
|||
BOB_generateBooth(pBoothId, 'default', pCallback) |
|||
BOB_generateBooth(pBoothId, 'default', pCallback); |
|||
} |
|||
}) |
|||
} |
|||
|
|||
function BOB_generateBooth (pBoothId, pType, pCallback) { |
|||
var prebuiltPath = path.join(CFG.paths.prebuilt, pBoothId) |
|||
var finalPict = path.join(CFG.paths.final, pBoothId + '.jpg') |
|||
var finalLdPict = path.join(CFG.paths.final_ld, pBoothId + '.jpg') |
|||
var outPict = gm(CFG.booths[pType].template) |
|||
function BOB_generateBooth(pBoothId, pType, pCallback) { |
|||
var prebuiltPath = BOB_mod_path.join(BOB_cfg_config.paths.prebuilt, pBoothId); |
|||
var finalPict = BOB_mod_path.join(BOB_cfg_config.paths.final, pBoothId+".jpg"); |
|||
var finalLdPict = BOB_mod_path.join(BOB_cfg_config.paths.final_ld, pBoothId+".jpg"); |
|||
var outPict = BOB_mod_gm(BOB_cfg_config.booths[pType].template); |
|||
|
|||
var printedDate = new Date(parseInt(pBoothId)) |
|||
var printedDate = new Date(parseInt(pBoothId)); |
|||
|
|||
outPict.fill(CFG.background) |
|||
outPict.drawRectangle(0, 0, CFG.booths[pType].resolution.width, CFG.booths[pType].resolution.height) |
|||
outPict.fill(BOB_cfg_config.background); |
|||
outPict.drawRectangle(0, 0, BOB_cfg_config.booths[pType].resolution.width, BOB_cfg_config.booths[pType].resolution.height); |
|||
// Draw footer
|
|||
outPict.draw('image Over 0,2100 1600,250 \'' + CFG.footer + '\'') |
|||
outPict.draw('image Over 0,2100 1600,250 \''+BOB_cfg_config.footer+'\''); |
|||
|
|||
CFG.pictNames.forEach(function (pPictName, pIndex) { |
|||
var cmdDraw = 'image Over' |
|||
cmdDraw += ' ' + CFG.booths[pType].layout[pIndex].x |
|||
cmdDraw += ',' + CFG.booths[pType].layout[pIndex].y |
|||
cmdDraw += ' ' + CFG.booths[pType].layout[pIndex].width |
|||
cmdDraw += ',' + CFG.booths[pType].layout[pIndex].height |
|||
cmdDraw += ' \'' + path.join(prebuiltPath, pPictName) + '\'' |
|||
BOB_cfg_config.pictNames.forEach(function(pPictName, pIndex) { |
|||
var cmdDraw = 'image Over'; |
|||
cmdDraw += ' '+BOB_cfg_config.booths[pType].layout[pIndex].x; |
|||
cmdDraw += ','+BOB_cfg_config.booths[pType].layout[pIndex].y; |
|||
cmdDraw += ' '+BOB_cfg_config.booths[pType].layout[pIndex].width; |
|||
cmdDraw += ','+BOB_cfg_config.booths[pType].layout[pIndex].height; |
|||
cmdDraw += ' \''+BOB_mod_path.join(prebuiltPath, pPictName)+'\''; |
|||
|
|||
// console.log(cmdDraw);
|
|||
outPict.draw(cmdDraw) |
|||
}) |
|||
outPict.draw(cmdDraw); |
|||
}) |
|||
|
|||
outPict.fill('#666') |
|||
outPict.pointSize(20) |
|||
outPict.draw('text 1250,2350 "' + printedDate.toUTCString() + '"') |
|||
outPict.fill("#666"); |
|||
outPict.pointSize(20); |
|||
outPict.draw('text 1250,2350 "'+printedDate.toUTCString()+'"'); |
|||
|
|||
outPict.write(finalPict, function (pErr) { |
|||
if (pErr) { |
|||
console.log('Write outfile') |
|||
if( pErr ) { |
|||
console.log("Write outfile") |
|||
console.log(pErr) |
|||
pCallback(pErr) |
|||
pCallback(pErr); |
|||
} else { |
|||
gm(finalPict) |
|||
BOB_mod_gm(finalPict) |
|||
.resize(400, null) |
|||
.write(finalLdPict, function (pErr) { |
|||
pCallback(pErr) |
|||
.write(finalLdPict, function(pErr) { |
|||
pCallback(pErr); |
|||
}) |
|||
} |
|||
}) |
|||
}); |
|||
} |
|||
|
|||
module.exports = tools |
|||
|
|||
tools.init = function () { |
|||
BOB_updateConfig() |
|||
module.exports = function(pConfig) { |
|||
BOB_cfg_config = pConfig; |
|||
BOB_updateConfig(); |
|||
return BOB_module; |
|||
} |
|||
|
|||
// function (pConfig) {
|
|||
// CFG = pConfig
|
|||
// return tools
|
|||
// }
|
|||
|
|||
function BOB_updateConfig () { |
|||
fs.readdir(CFG.paths.template, function (pErr, pFiles) { |
|||
if (pErr) { |
|||
console.log('BOB_updateConfig', 'Path:', CFG.paths.template, pErr) |
|||
function BOB_updateConfig() { |
|||
BOB_mod_fs.readdir(BOB_cfg_config.paths.template, function(pErr, pFiles) { |
|||
if( pErr ) { |
|||
console.log("BOB_updateConfig", "Path:", BOB_cfg_config.paths.template, pErr); |
|||
} else { |
|||
async.map(pFiles, |
|||
function (pFile, pCb) { |
|||
BOB_mod_async.map(pFiles, |
|||
function(pFile, pCb) { |
|||
// Get name of template
|
|||
var boothName = pFile.split('.')[0] |
|||
var boothName = pFile.split('.')[0]; |
|||
// Init layouts object for the template
|
|||
CFG.booths[boothName] = { |
|||
name: boothName, |
|||
template: path.join(CFG.paths.template, pFile), |
|||
resolution: { width: 0, height: 0 }, |
|||
layout: [] |
|||
} |
|||
BOB_cfg_config.booths[boothName] = { |
|||
name : boothName, |
|||
template : BOB_mod_path.join(BOB_cfg_config.paths.template, pFile), |
|||
resolution : { width : 0, height : 0 }, |
|||
layout : [] |
|||
}; |
|||
// Get reslution of current template
|
|||
gm(CFG.booths[boothName].template).size(function (pErr, pValue) { |
|||
if (pErr) { |
|||
console.log('[ERROR] Get template size', pErr) |
|||
BOB_mod_gm(BOB_cfg_config.booths[boothName].template).size(function(pErr, pValue){ |
|||
if( pErr ) { |
|||
console.log("[ERROR] Get template size", pErr); |
|||
} else { |
|||
CFG.booths[boothName].resolution = pValue |
|||
BOB_generatePictLayout(boothName) |
|||
BOB_cfg_config.booths[boothName].resolution = pValue; |
|||
BOB_generatePictLayout(boothName); |
|||
} |
|||
pCb() |
|||
pCb(); |
|||
}) |
|||
}, |
|||
function (pErr) { |
|||
function(pErr) { |
|||
}) |
|||
} |
|||
}) |
|||
} |
|||
|
|||
function BOB_generatePictLayout (pBoothName) { |
|||
var index = 0 |
|||
var marginX = 20 |
|||
var marginY = 20 |
|||
function BOB_generatePictLayout(pBoothName) { |
|||
var index = 0; |
|||
var marginX = 20; |
|||
var marginY = 20; |
|||
|
|||
var pictWidth = (CFG.booths[pBoothName].resolution.width - 3 * marginX) / 2 |
|||
var pictHeight = parseInt(pictWidth * CFG.cropSize.height / CFG.cropSize.width) |
|||
var pictWidth = ( BOB_cfg_config.booths[pBoothName].resolution.width - 3 * marginX ) / 2; |
|||
var pictHeight = parseInt(pictWidth * BOB_cfg_config.cropSize.height / BOB_cfg_config.cropSize.width); |
|||
|
|||
CFG.pictNames.forEach(function (pPictName, pIndex) { |
|||
CFG.booths[pBoothName].layout.push({ |
|||
x: marginX + (marginX + pictWidth) * (pIndex % 2), |
|||
y: marginY + (marginY + pictHeight) * parseInt(pIndex / 2), |
|||
width: pictWidth, |
|||
height: pictHeight |
|||
BOB_cfg_config.pictNames.forEach(function(pPictName, pIndex) { |
|||
BOB_cfg_config.booths[pBoothName].layout.push({ |
|||
x : marginX + (marginX + pictWidth) * ( pIndex % 2 ), |
|||
y : marginY + (marginY + pictHeight) * parseInt( pIndex / 2 ), |
|||
width : pictWidth, |
|||
height : pictHeight |
|||
}) |
|||
}) |
|||
|
|||
// console.log('INIT DONE')
|
|||
console.log("INIT DONE"); |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
|
|||
|
|||
module.exports = function(pConfig) { |
|||
console.log("TOOL TEST", pConfig); |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
<h1><%= message %></h1> |
|||
<h2><%= error.status %></h2> |
|||
<pre><%= error.stack %></pre> |
|||
@ -0,0 +1,19 @@ |
|||
<html> |
|||
<body style="text-align:center"> |
|||
<h2>Click to force Bobinoscope date from your phone.</h2> |
|||
<br/> |
|||
<button class="fixdate">Fix Date</button> |
|||
</body> |
|||
<!-- Latest compiled and minified JQuery --> |
|||
<script src="/js/jquery-1.11.2.min.js"></script> |
|||
<script> |
|||
$(document).ready(function() { |
|||
$('.fixdate').click(function() { |
|||
$.get('/fixdate/'+((new Date()).getTime()), function(pResponse) { |
|||
console.log('DONE', pResponse); |
|||
alert('done', pResponse.error); |
|||
}) |
|||
}) |
|||
}) |
|||
</script> |
|||
</html> |
|||
@ -0,0 +1,248 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<title>Studio</title> |
|||
<!-- Latest compiled and minified CSS --> |
|||
<link rel="stylesheet" href="/css/bootstrap.min.css"> |
|||
<link rel="stylesheet" href="/css/cover.css"/> |
|||
</head> |
|||
<body> |
|||
<div class="site-wrapper"> |
|||
<div class="site-wrapper-inner"> |
|||
<div class="cover-container"> |
|||
<div class="inner cover" style="height:900px;position:relative"> |
|||
|
|||
<div id="idBoothPanel" style="position:absolute;width:100%"> |
|||
<div style="padding-top:1em"> |
|||
<div id="idViewCountdown" style="font-size:20em; display:none"></div> |
|||
<div id="idViewTrigger" style="display:block"> |
|||
<h1 class="cover-heading">Prends ta bobine !</h1> |
|||
<br/><br/> |
|||
<div style="width:800px;height:600px;position:relative;display:none"> |
|||
<video id="player" autoplay="true" style="height:100%;width:100%;position:absolute;left:0;top:0"></video> |
|||
<div style="position:absolute;background:#3C0000;top:0;left:0;width:<%= killZone.left%>%;height:100%;opacity:0.9"></div> |
|||
<div style="position:absolute;background:#3C0000;top:0;right:0;width:<%= killZone.right%>%;height:100%;opacity:0.9"></div> |
|||
<div style="position:absolute;background:#3C0000;top:0;left:<%= killZone.left%>%;right:<%= killZone.right%>%;height:<%= killZone.top%>%;opacity:0.9"></div> |
|||
<div style="position:absolute;background:#3C0000;bottom:0;left:<%= killZone.left%>%;right:<%= killZone.right%>%;height:<%= killZone.bottom%>%;opacity:0.9"></div> |
|||
</div> |
|||
</div> |
|||
<div id="idViewGenerating" style="display:none"> |
|||
<h1 class="cover-heading">Bobinogramme <i>en cours de génération...</i></h1> |
|||
<br/><br/> |
|||
<h3>Merci de bien vouloir patienter<br/>une quinzaine de secondes</h3> |
|||
<br/> |
|||
<br/> |
|||
<div style="position:relative;width:100%;height:2px;background:#444"> |
|||
<div id="idProgressBar" style="background:#fff;height:2px; width:0%;transition: all 200ms ease"></div> |
|||
</div> |
|||
</div> |
|||
<div id="idViewBobinogramme" style="display:none"> |
|||
<img src="/img/final_ld/1438098902994.jpg" height="600px"/> |
|||
<h3 class="cover-heading">Retrouve ton <b>bobinogramme</b> sur <br/>http://192.168.1.2</h3> |
|||
</div> |
|||
</div> |
|||
<div id="idViewDoIt" style="font-size:8em; height:600px; display:none"> |
|||
Faites<br/> |
|||
<span id="idViewDoIt-theme" style="font-size:2em">le chat</span> |
|||
</div> |
|||
</div> |
|||
|
|||
<div id="idPictPreview" style="position:absolute;display:none;width:100%"> |
|||
<img src="/img/test.jpgautoOrient.jpg" height="900px"> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="mastfoot"> |
|||
<div class="inner"> |
|||
<p>BW Bros.</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</body> |
|||
<!-- Latest compiled and minified JQuery --> |
|||
<script src="/js/jquery-1.11.2.min.js"></script> |
|||
<!-- Latest compiled and minified javaScript bootstrap--> |
|||
<script src="/js/bootstrap.min.js"></script> |
|||
<!-- Getting the Socket.IO Client --> |
|||
<script src="/js/socket.io-1.3.4.js"></script> |
|||
</html> |
|||
|
|||
<style type="text/css"> |
|||
* { |
|||
-webkit-box-sizing: border-box; |
|||
box-sizing: border-box; |
|||
} |
|||
</style> |
|||
|
|||
<script type="text/javascript"> |
|||
|
|||
var socket = io('http://<%= serverIpAddress %>:3000'); |
|||
|
|||
socket.on('connect', function() { |
|||
console.log("connect") |
|||
}) |
|||
|
|||
socket.on('boothClick', function(pData) { |
|||
BOB_runBooth(); |
|||
}); |
|||
|
|||
var BOB_var_context = { |
|||
boothOnGoing : false, |
|||
initTimer : 3, |
|||
onGoingTimer : 0, |
|||
boothId : null, |
|||
pictureId : 0 |
|||
} |
|||
|
|||
var BOB_var_themes = { |
|||
selectedId : 0, |
|||
list : [ |
|||
"le chat", |
|||
"le cuir moustache", |
|||
"le roi", |
|||
"le bouffon", |
|||
"le moussailon", |
|||
"le geek", |
|||
"l'amoureux", |
|||
] |
|||
} |
|||
|
|||
$(document).ready(function() { |
|||
$('#idBtnClick').click(function() { |
|||
//BOB_runBooth(); |
|||
}) |
|||
}) |
|||
|
|||
function BOB_runBooth() { |
|||
if( BOB_var_context.boothOnGoing === false ) { |
|||
var currentDate = new Date(); |
|||
BOB_var_context.boothOnGoing = true; |
|||
BOB_var_context.boothId = currentDate.getTime(); |
|||
BOB_var_context.pictureId = 0; |
|||
BOB_var_context.onGoingTimer = BOB_var_context.initTimer; |
|||
|
|||
$('#idViewTrigger').fadeOut(500, function() { |
|||
BOB_countdown(); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
function BOB_countdown() { |
|||
$('#idViewCountdown').fadeIn(); |
|||
$('#idViewCountdown').html(BOB_var_context.onGoingTimer); |
|||
// |
|||
if( BOB_var_context.onGoingTimer > 5 ) { |
|||
// $('#idViewDoIt').show(); |
|||
// $('#idViewDoIt-theme').hide(); |
|||
} else if( BOB_var_context.onGoingTimer > 2 ) { |
|||
// $('#idViewDoIt-theme').html( BOB_var_themes.list[BOB_var_themes.selectedId] ); |
|||
// $('#idViewDoIt-theme').show(); |
|||
} |
|||
|
|||
if( BOB_var_context.onGoingTimer > 0 ) { |
|||
setTimeout(function() { |
|||
BOB_var_context.onGoingTimer -= 1; |
|||
BOB_countdown(); |
|||
}, 1000) |
|||
} else { |
|||
$('#idViewCountdown').html("Smile"); |
|||
BOB_takeThe1Pictures(); |
|||
} |
|||
} |
|||
|
|||
function BOB_displayPictPreview(pBoothId, pPictureId, pCallback) { |
|||
$('#idViewCountdown').html(""); |
|||
$('#idPictPreview > img').attr('src', '/img/prebuilt/'+pBoothId+'/pict_'+pPictureId+'.jpg'); |
|||
$('#idBoothPanel').fadeOut(50, function() { |
|||
$('#idPictPreview').show(); |
|||
setTimeout(function() { |
|||
$('#idPictPreview').hide(); |
|||
$('#idBoothPanel').fadeIn(50, function() { |
|||
pCallback() |
|||
}) |
|||
}, 4000) |
|||
}) |
|||
} |
|||
|
|||
var BOB_var_progressTimer = new Date(); |
|||
|
|||
function BOB_lauchFakeProgressBar() { |
|||
setTimeout(function() { |
|||
var progress = (new Date() - BOB_var_progressTimer) / 15000 * 100; |
|||
$('#idProgressBar').css('width', progress+'%'); |
|||
if( progress < 100 ) { |
|||
BOB_lauchFakeProgressBar(); |
|||
} |
|||
}, 500) |
|||
} |
|||
|
|||
|
|||
function BOB_takeThe1Pictures() { |
|||
$.get('/dslr/takepicture/'+BOB_var_context.boothId+'/'+BOB_var_context.pictureId, function(pResponse) { |
|||
if( pResponse.error ) { |
|||
if( confirm(pResponse.error) ) { |
|||
BOB_var_context.boothOnGoing = false; |
|||
$('#idViewCountdown').fadeOut(500, function() { |
|||
$('#idViewTrigger').fadeIn(); |
|||
}); |
|||
return; |
|||
} |
|||
} |
|||
|
|||
BOB_var_context.pictureId += 1; |
|||
if( BOB_var_context.pictureId < 4 ) { |
|||
BOB_var_context.onGoingTimer = BOB_var_context.initTimer; |
|||
BOB_countdown(); |
|||
} else { |
|||
$('#idViewCountdown').fadeOut(500, function() { |
|||
BOB_var_progressTimer = new Date(); |
|||
$('#idProgressBar').css('width', '0'); |
|||
$('#idViewGenerating').fadeIn(); |
|||
BOB_lauchFakeProgressBar() |
|||
}) |
|||
$.get('/booth/build/'+BOB_var_context.boothId, function(pResponse) { |
|||
$('#idViewBobinogramme > img').attr('src', '/img/final_ld/'+pResponse.boothId+'.jpg'); |
|||
$('#idViewGenerating').fadeOut(500, function() { |
|||
$('#idViewBobinogramme').fadeIn(500, function() { |
|||
setTimeout(function(){ |
|||
BOB_var_context.boothOnGoing = false; |
|||
$('#idViewBobinogramme').fadeOut(500, function() { |
|||
$('#idViewTrigger').fadeIn(); |
|||
}); |
|||
}, 10000) |
|||
}) |
|||
}) |
|||
}); |
|||
} |
|||
}) |
|||
} |
|||
|
|||
/* |
|||
(function(){ |
|||
var mediaOptions = { audio: false, video: true }; |
|||
|
|||
if (!navigator.getUserMedia) { |
|||
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; |
|||
} |
|||
|
|||
if (!navigator.getUserMedia){ |
|||
return alert('getUserMedia not supported in this browser.'); |
|||
} |
|||
|
|||
navigator.getUserMedia(mediaOptions, success, function(e) { |
|||
console.log(e); |
|||
}); |
|||
|
|||
function success(stream){ |
|||
var video = document.querySelector("#player"); |
|||
video.src = window.URL.createObjectURL(stream); |
|||
} |
|||
})(); |
|||
*/ |
|||
</script> |
|||
@ -0,0 +1,72 @@ |
|||
<!DOCTYPE html> |
|||
<html> |
|||
<head> |
|||
<meta charset="utf-8"> |
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge"> |
|||
<meta name="viewport" content="width=device-width, initial-scale=1"> |
|||
<title><%= title %></title> |
|||
<!-- Latest compiled and minified CSS --> |
|||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css"> |
|||
<link rel="stylesheet" href="/css/cover.css"/> |
|||
</head> |
|||
<body> |
|||
|
|||
<body> |
|||
|
|||
<div class="site-wrapper"> |
|||
<div class="site-wrapper-inner"> |
|||
<div class="cover-container"> |
|||
<div class="masthead clearfix"> |
|||
<div class="inner"> |
|||
<h3 class="masthead-brand">Bobinoscope</h3> |
|||
</div> |
|||
</div> |
|||
|
|||
<div class="inner cover"> |
|||
<h1 class="cover-heading">Prends ta face !</h1> |
|||
<p class="lead"> |
|||
<a href="#" class="btn btn-lg btn-default" id="idBtnClick">Clic</a> |
|||
</p> |
|||
<img id="idDisplayImg" width="640px"/> |
|||
</div> |
|||
|
|||
<div class="mastfoot"> |
|||
<div class="inner"> |
|||
<p>BW Bros.</p> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
|
|||
</body> |
|||
<!-- Latest compiled and minified JQuery --> |
|||
<script src="//code.jquery.com/jquery-1.11.2.min.js"></script> |
|||
<!-- Latest compiled and minified javaScript bootstrap--> |
|||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script> |
|||
</html> |
|||
|
|||
<script type="text/javascript"> |
|||
$(document).ready(function() { |
|||
$('#idBtnClick').click(function() { |
|||
BOB_takeThe4Pictures(); |
|||
}) |
|||
}) |
|||
|
|||
function BOB_takeThe4Pictures() { |
|||
var currentDate = new Date(); |
|||
var pictId = 0; |
|||
var boothId = currentDate.getTime(); |
|||
|
|||
|
|||
|
|||
} |
|||
|
|||
function BOB_takeOnePicture(pBoothId, pPictId) { |
|||
$.get('/dslr/takepicture', function(pResponse) { |
|||
$('#idDisplayImg').attr('src', pResponse.data); |
|||
}) |
|||
} |
|||
|
|||
|
|||
</script> |
|||
Write
Preview
Loading…
Cancel
Save