Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v2.0 Milestone #38

Merged
merged 13 commits into from
Dec 31, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/lib/cleanObject.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module.exports = obj => {
let keys = Object.keys(obj)
keys.forEach(k => {
if (!obj[k]) delete obj[k]
})
return obj
}
26 changes: 19 additions & 7 deletions app/lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,16 +99,28 @@ let func = {
hasErrors: () => Object.keys(errors).length > 0,
getErrors: () => errors,
addError: (device, message) => {
if (!errors[device.deviceId])
errors[device.deviceId] = {
name: device.location,
// you can pass a tag directly instead of a device
let tag = typeof device === 'object' ? device.deviceId : device
if (!errors[tag])
errors[tag] = {
name: typeof device === 'object' ? device.location : device,
messages: []
}
if (errors[device.deviceId].messages.indexOf(message) == -1)
errors[device.deviceId].messages.push(message)
if (errors[tag].messages.indexOf(message) == -1)
errors[tag].messages.push(message)
},
clearErrors: device => delete errors[device.deviceId]
clearErrors: device =>
delete errors[typeof device === 'object' ? device.deviceId : device],
hasStatus: () => status.length > 0,
getStatus: () => status.map(s => s.message),
addStatus: (tag, message) =>
status.push({
tag: tag,
message: message
}),
clearStatus: tag => (status = status.filter(s => s.tag != tag))
},
errors = {}
errors = {},
status = []

module.exports = func
3 changes: 2 additions & 1 deletion app/lib/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ const findDevices = () => {
deviceId: id,
name: service.txtRecord.fn,
address: service.addresses[0],
port: service.port
port: service.port,
rotation: 'rot0'
})
}
})
Expand Down
4 changes: 4 additions & 0 deletions app/lib/sockets.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ const func = {
init: server => {
io = require('socket.io')(server)
io.on('connection', client => {
console.log(
'connected client with host:',
stripIPv6(client.handshake.address)
)
clients.push(client)
client.on('disconnect', () => {
console.log(
Expand Down
30 changes: 30 additions & 0 deletions app/lib/squashKeyedArrays.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module.exports = (obj, upgradeElementsToArrays) => {
let keys = Object.keys(obj),
arrays = []
keys.forEach(k => {
let key = /(.+)\[\d+\]$/.exec(k)
if (key && arrays.indexOf(key[1]) == -1) arrays.push(key[1])
})

arrays.forEach(a => {
let _arr = {},
arr = [],
highestIndex = 0
keys.forEach(k => {
let index = new RegExp(`${a}\\[(\\d+)\\]`).exec(k)
if (index) {
highestIndex = Math.max(highestIndex, index)
let item = obj[k]
if (upgradeElementsToArrays && !Array.isArray(item)) item = [item]
arr[index[1]] = item
delete obj[k]
}
})
for (let i = 0; i < highestIndex; i++) {
if (_arr.hasOwnProperty(i)) arr.push(_arr[i])
else arr.push(upgradeElementsToArrays ? [] : null)
}
obj[a] = arr
})
return obj
}
5 changes: 4 additions & 1 deletion app/lib/takeover.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const Channel = require('../models/Channel')
const devices = require('../lib/devices')
const sockets = require('../lib/sockets')
const connection = require('../lib/connection')

var takeover = null

Expand All @@ -14,14 +15,16 @@ const func = {
if (err) console.log(err)

takeover = channel
connection.addStatus('takeover', 'Takeover is currently active!')
devices.refreshAll(() => callback())
})
},
deactivate: callback => {
takeover = null
connection.clearStatus('takeover')
sockets.list().forEach(c => c.emit('refresh'))
callback()
}
}

module.exports = func
module.exports = func
4 changes: 3 additions & 1 deletion app/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
const express = require('express')
const app = express()
const server = require('http').createServer(app)
const cors = require('cors')
const mongoose = require('mongoose')
mongoose.Promise = require('bluebird')
const bodyParser = require('body-parser')
Expand Down Expand Up @@ -37,6 +38,7 @@ channels.init()
sockets.init(server)

/* Express Setup */
app.use(cors())
app.set('view engine', 'pug')
app.set('views', path.join(__dirname, 'views'))
app.use(bodyParser.urlencoded({ extended: false }))
Expand Down Expand Up @@ -90,7 +92,7 @@ app.use('/takeover', require('./routes/takeover'))
/* Server */
server.listen(port, () => {
console.log('MultiCast is live!')
console.log(`listening at port ${port}...`)
console.log(`Listening at port ${port}...`)

if (!serveOnly) {
/* poll for active devices */
Expand Down
11 changes: 6 additions & 5 deletions app/models/Channel.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
'use strict';
const mongoose = require('mongoose')
const Schema = mongoose.Schema
'use strict'
const mongoose = require('mongoose')
const Schema = mongoose.Schema

const ChannelSchema = new Schema({
name: String,
layout: String,
URLs: [String]
URLs: [[String]],
duration: Number
})

module.exports = mongoose.model('Channel', ChannelSchema)
module.exports = mongoose.model('Channel', ChannelSchema)
8 changes: 4 additions & 4 deletions app/models/Chromecast.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
'use strict';
'use strict'
const mongoose = require('mongoose')
const Schema = mongoose.Schema

const ChromecastSchema = new Schema({
deviceId: String, // hexadecimal identifier provided by Chromecast
// don't confuse this with _id provided by Mongo
location: String,
channel: { type: Schema.Types.ObjectId, ref: 'Channel' },
rotation: String,
channel: { type: Schema.Types.ObjectId, ref: 'Channel' }
})

module.exports = mongoose.model('Chromecast', ChromecastSchema)
module.exports = mongoose.model('Chromecast', ChromecastSchema)
14 changes: 11 additions & 3 deletions app/routes/channels.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ const Chromecast = require('../models/Chromecast')
const Channel = require('../models/Channel')

const port = require('../lib/config').port
const squashKeyedArrays = require('../lib/squashKeyedArrays')
const cleanObject = require('../lib/cleanObject')

router.use((req, res, next) => {
if (req.body.URLs) req.body.URLs = req.body.URLs.filter(u => u.trim() != '')
Expand Down Expand Up @@ -49,7 +51,13 @@ router
})
else res.render('index', {})
})
.post((req, res) => channels.update(req.params.channel_id, req.body, id => res.send(id)))
.delete((req, res) => channels.remove(req.params.channel_id, () => res.sendStatus(200)))
.post((req, res) => {
channels.update(req.params.channel_id, squashKeyedArrays(req.body), id =>
res.send(id)
)
})
.delete((req, res) =>
channels.remove(req.params.channel_id, () => res.sendStatus(200))
)

module.exports = router
module.exports = router
140 changes: 81 additions & 59 deletions app/routes/devices.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ const takeover = require('../lib/takeover')

const port = require('../lib/config').port

/* List of device rotations */
const rotations = [
{
value: 'rot0',
description: 'Landscape'
},
{
value: 'rot90',
description: 'Portrait'
},
{
value: 'rot180',
description: 'Landscape Reversed'
},
{
value: 'rot270',
description: 'Portrait Reversed'
}
]

router.get('/', (req, res) => {
res.render('index', { render: 'devices', devices: devices.list() })
})
Expand All @@ -22,7 +42,9 @@ router
res.render('index', {
render: 'device',
devices: devices.list().filter(d => d.unregistered),
channels: channels.list()
channels: channels.list(),
rotations: rotations,
rotation: 0
})
})
.post((req, res) => {
Expand All @@ -34,45 +56,6 @@ router
})
})

router.get('/:device_id', (req, res) => {
let d = devices.withId(req.params.device_id)
if (d && takeover.isActive()) {
res.render(`layouts/${takeover.channel().layout}`, {
deviceId: req.params.device_id,
channel: takeover.channel(),
casting: true
})
} else {
if (d) {
if (d.channel) {
/* device registered and channel set
display device page */
res.render(`layouts/${d.channel.layout}`, {
deviceId: req.params.device_id,
channel: d.channel,
casting: true
})
} else {
/* device registered but no channel set
display setup page */
res.render('setup-chromecast', {
device: d,
registered: true,
setupUrl: `${req.protocol}://${req.hostname}:${port}/`
})
}
} else {
/* device is not registered
display setup page */
res.render('setup-chromecast', {
device: d,
registered: false,
setupUrl: `${req.protocol}://${req.hostname}:${port}/`
})
}
}
})

router.get('/:device_id/connect', (req, res) => {
let d = devices.withId(req.params.device_id)
if (!devices.isOnline(req.params.device_id)) devices.reconnect(d.address)
Expand All @@ -93,31 +76,28 @@ router
res.render('index', {
render: 'device',
device: d,
channels: channels.list()
channels: channels.list(),
rotations: rotations,
rotation: d.rotation
})
} else render('index', {})
})
.post((req, res) => {
Chromecast.update(
{ deviceId: req.params.device_id },
req.body,
err => {
if (err) console.log(err)
Chromecast.update({ deviceId: req.params.device_id }, req.body, err => {
if (err) console.log(err)

let d = devices.withId(req.params.device_id)
d.location = req.body.location // update local info with location
console.log('host', d.address)
let c = sockets.withHost(d.address),
channel = null
if (req.body.channel) {
channel = channels.withId(req.body.channel)
d.channel = channel // update local info with channel
}
console.log('socket_client', c)
if (c) c.emit('change_channel', channel)
res.send(req.params.device_id)
let d = devices.withId(req.params.device_id)
d.location = req.body.location // update local info with location
d.rotation = req.body.rotation
let c = sockets.withHost(d.address),
channel = null
if (req.body.channel) {
channel = channels.withId(req.body.channel)
d.channel = channel // update local info with channel
}
)
if (c) c.emit('change_channel', channel)
res.send(req.params.device_id)
})
})
.delete((req, res) => {
Chromecast.remove({ deviceId: req.params.device_id }, () => {
Expand All @@ -126,8 +106,50 @@ router
d.unregistered = true
delete d.channel
delete d.location
delete d.rotation
res.sendStatus(200)
})
})

router.get('/:device_id/:preview*?', (req, res) => {
let d = devices.withId(req.params.device_id)
if (d && takeover.isActive()) {
res.render(`layouts/${takeover.channel().layout}`, {
deviceId: req.params.device_id,
channel: takeover.channel(),
rotation: d.rotation,
casting: !req.params.preview
})
} else {
if (d) {
if (d.channel) {
/* device registered and channel set
display device page */
res.render(`layouts/${d.channel.layout}`, {
deviceId: req.params.device_id,
channel: d.channel,
rotation: d.rotation,
casting: !req.params.preview
})
} else {
/* device registered but no channel set
display setup page */
res.render('setup-chromecast', {
device: d,
registered: true,
setupUrl: `${req.protocol}://${req.hostname}:${port}/`
})
}
} else {
/* device is not registered
display setup page */
res.render('setup-chromecast', {
device: d,
registered: false,
setupUrl: `${req.protocol}://${req.hostname}:${port}/`
})
}
}
})

module.exports = router
Loading