Skip to content

Commit

Permalink
Merge pull request MagicMirrorOrg#6 from fewieden/feature/voice-control
Browse files Browse the repository at this point in the history
Feature/voice control
  • Loading branch information
fewieden authored Oct 7, 2016
2 parents 9214489 + e361561 commit a22b940
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 8 deletions.
Binary file added .github/example_help.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/example_statistic.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions MMM-NFL.css
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,20 @@

.MMM-NFL .ball-away {
margin-left: 10px;
}

.MMM-NFL-blur {
-webkit-filter: blur(2px) brightness(50%);
}

.MMM-NFL .modal {
position: fixed;
text-align: left;
left: 50%;
top: 50%;
-webkit-transform: translate(-50%, -50%);
}

.MMM-NFL .modal ul {
margin: 0px;
}
211 changes: 207 additions & 4 deletions MMM-NFL.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,30 @@ Module.register("MMM-NFL", {
reloadInterval: 30 * 60 * 1000 // every 30 minutes
},

statistics: false,
help: false,

voice: {
mode: "FOOTBALL",
sentences: [
"OPEN HELP",
"CLOSE HELP",
"SHOW HELMETS",
"SHOW LOGOS",
"COLOR ON",
"COLOR OFF",
"NETWORK ON",
"NETWORK OFF",
"SHOW PASSING YARDS STATISTIC",
"SHOW RUSHING YARDS STATISTIC",
"SHOW RECEIVING YARDS STATISTIC",
"SHOW TACKLES STATISTIC",
"SHOW SACKS STATISTIC",
"SHOW INTERCEPTIONS STATISTIC",
"HIDE STATISTIC"
]
},

getTranslations: function () {
return {
en: "translations/en.json",
Expand All @@ -61,26 +85,87 @@ Module.register("MMM-NFL", {
moment.locale(config.language);
},

notificationReceived: function (notification, payload, sender) {
if(notification === "ALL_MODULES_STARTED"){
this.sendNotification("REGISTER_VOICE_MODULE", this.voice);
} else if(notification === "VOICE_FOOTBALL" && sender.name === "MMM-voice"){
this.checkCommands(payload);
} else if(notification === "VOICE_MODE_CHANGED" && sender.name === "MMM-voice" && payload.old === this.voice.mode){
this.help = false;
this.statistics = false;
this.updateDom(300);
}
},

socketNotificationReceived: function (notification, payload) {
if (notification === "SCORES") {
this.scores = payload.scores;
this.details = payload.details;
this.updateDom(1000);
this.updateDom(300);
} else if(notification === "STATISTICS"){
this.help = false;
this.statistics = payload;
this.updateDom(300);
}
},

checkCommands: function(data){
if(/(HELP)/g.test(data)){
if(/(CLOSE)/g.test(data) || this.help && !/(OPEN)/g.test(data)){
this.help = false;
} else if(/(OPEN)/g.test(data) || !this.help && !/(CLOSE)/g.test(data)){
this.statistics = false;
this.help = true;
}
} else if(/(HELMETS)/g.test(data)){
this.config.helmets = true;
} else if(/(LOGOS)/g.test(data)){
this.config.helmets = false;
} else if(/(COLOR)/g.test(data)){
if(/(OFF)/g.test(data) || this.config.colored && !/(ON)/g.test(data)){
this.config.colored = false;
} else if(/(ON)/g.test(data) || !this.config.colored && !/(OFF)/g.test(data)){
this.config.colored = true;
}
} else if(/(NETWORK)/g.test(data)){
if(/(OFF)/g.test(data) || this.config.network && !/(ON)/g.test(data)){
this.config.network = false;
} else if(/(ON)/g.test(data) || !this.config.network && !/(OFF)/g.test(data)){
this.config.network = true;
}
} else if(/(STATISTIC)/g.test(data)){
if(/(HIDE)/g.test(data)){
this.statistics = false;
} else if(/(PASSING)/g.test(data)){
this.sendSocketNotification("GET_STATISTICS", "Passing Yards");
} else if(/(RUSHING)/g.test(data)){
this.sendSocketNotification("GET_STATISTICS", "Rushing Yards");
} else if(/(RECEIVING)/g.test(data)){
this.sendSocketNotification("GET_STATISTICS", "Receiving Yards");
} else if(/(TACKLES)/g.test(data)){
this.sendSocketNotification("GET_STATISTICS", "Tackles");
} else if(/(SACKS)/g.test(data)){
this.sendSocketNotification("GET_STATISTICS", "Sacks");
} else if(/(INTERCEPTIONS)/g.test(data)){
this.sendSocketNotification("GET_STATISTICS", "Interceptions");
}
}
this.updateDom(300);
},

getDom: function () {

var wrapper = document.createElement("div");
var scores = document.createElement("div");
var header = document.createElement("header");
header.innerHTML = "NFL " + this.modes[this.details.t] + " " + this.details.y;
wrapper.appendChild(header);
scores.appendChild(header);

if (!this.scores) {
var text = document.createElement("div");
text.innerHTML = this.translate("LOADING");
text.classList.add("dimmed", "light");
wrapper.appendChild(text);
scores.appendChild(text);
} else {
var table = document.createElement("table");
table.classList.add("small", "table");
Expand All @@ -91,9 +176,34 @@ Module.register("MMM-NFL", {
this.appendDataRow(this.scores[i].$, table);
}

wrapper.appendChild(table);
scores.appendChild(table);

var modules = document.querySelectorAll(".module");
for (var i = 0; i < modules.length; i++) {
if(!modules[i].classList.contains("MMM-NFL")){
if(this.statistics || this.help){
modules[i].classList.add("MMM-NFL-blur");
} else {
modules[i].classList.remove("MMM-NFL-blur");
}
}
}

if(this.statistics || this.help){
scores.classList.add("MMM-NFL-blur");
var modal = document.createElement("div");
modal.classList.add("modal");
if(this.statistics){
this.appendStatistics(modal);
} else {
this.appendHelp(modal);
}
wrapper.appendChild(modal);
}
}

wrapper.appendChild(scores);

return wrapper;
},

Expand Down Expand Up @@ -233,5 +343,98 @@ Module.register("MMM-NFL", {
}
appendTo.appendChild(ballIcon);
}
},

appendStatistics: function(appendTo){
var type = document.createElement("div");
type.classList.add("large");
type.innerHTML = this.statistics.type;
appendTo.appendChild(type);

var table = document.createElement("table");
table.classList.add("medium", "table");

var labelRow = document.createElement("tr");

var posLabel = document.createElement("th");
posLabel.innerHTML = "#";
labelRow.appendChild(posLabel);

var playerLabel = document.createElement("th");
playerLabel.innerHTML = this.translate("PLAYER");
labelRow.appendChild(playerLabel);

var teamLabel = document.createElement("th");
teamLabel.setAttribute("colspan", 2);
teamLabel.innerHTML = this.translate("TEAM");
labelRow.appendChild(teamLabel);

var unitLabel = document.createElement("th");
unitLabel.innerHTML = this.statistics.data.unit;
labelRow.appendChild(unitLabel);

table.appendChild(labelRow);

for (var i = 0; i < this.statistics.data.players.length; i++) {
var row = document.createElement("tr");
row.classList.add("row");

var position = document.createElement("td");
position.innerHTML = this.statistics.data.players[i].position;
row.appendChild(position);

var player = document.createElement("td");
player.classList.add("align-left");
player.innerHTML = this.statistics.data.players[i].player;
row.appendChild(player);

if(this.config.focus_on && this.config.focus_on.indexOf(this.statistics.data.players[i].team) !== -1){
row.classList.add("bright");
}

var teamName = document.createElement("td");
teamName.innerHTML = this.statistics.data.players[i].team;
row.appendChild(teamName);

var team = document.createElement("td");
var teamIcon = document.createElement("img");
teamIcon.src = this.file("icons/" + this.statistics.data.players[i].team + (this.config.helmets ? "_helmet" : "") + ".png");
if (!this.config.colored) {
teamIcon.classList.add("icon");
}
team.appendChild(teamIcon);
row.appendChild(team);

var value = document.createElement("td");
value.innerHTML = this.statistics.data.players[i].value;
row.appendChild(value);

table.appendChild(row);
}

appendTo.appendChild(table);
},

appendHelp: function(appendTo){
var title = document.createElement("h1");
title.classList.add("medium");
title.innerHTML = this.name + " - " + this.translate("COMMAND_LIST");
appendTo.appendChild(title);

var mode = document.createElement("div");
mode.innerHTML = this.translate("MODE") + ": " + this.voice.mode;
appendTo.appendChild(mode);

var listLabel = document.createElement("div");
listLabel.innerHTML = this.translate("VOICE_COMMANDS") + ":";
appendTo.appendChild(listLabel);

var list = document.createElement("ul");
for(var i = 0; i < this.voice.sentences.length; i++){
var item = document.createElement("li");
item.innerHTML = this.voice.sentences[i];
list.appendChild(item);
}
appendTo.appendChild(list);
}
});
26 changes: 25 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ National Football League Module for MagicMirror<sup>2</sup>

## Example

![](.github/example.jpg) ![](.github/example2.jpg) ![](.github/example_focus.jpg)
![](.github/example.jpg) ![](.github/example2.jpg) ![](.github/example_focus.jpg) ![](.github/example_statistic.jpg) ![](.github/example_help.jpg)

## Dependencies
* An installation of [MagicMirror<sup>2</sup>](https://github.com/MichMich/MagicMirror)
* OPTIONAL: [Voice Control](https://github.com/fewieden/MMM-voice)
* npm
* [request](https://www.npmjs.com/package/request)
* [xml2js](https://www.npmjs.com/package/xml2js)
Expand Down Expand Up @@ -35,3 +36,26 @@ National Football League Module for MagicMirror<sup>2</sup>
| `focus_on` | `false` | Display only matches with teams of this array e.g. `['NYG', 'DAL', 'NE']`. |
| `format` | `'ddd h:mm'` | In which format the date should be displayed. [All Options](http://momentjs.com/docs/#/displaying/format/) |
| `reloadInterval` | `1800000` (30 mins) | How often should the data be fetched |
## OPTIONAL: Voice Control
This module supports voice control by [MMM-voice](https://github.com/fewieden/MMM-voice). In order to use this feature, it's required to install the voice module. There are no extra config options for voice control needed.
### Mode
The voice control mode for this module is `FOOTBALL`
### List of all Voice Commands
* OPEN HELP -> Shows the information from the readme here with mode and all commands.
* CLOSE HELP -> Hides the help information.
* SHOW HELMETS -> Switch team logos to helmets. (Effect stays until your mirror restarts, for permanent change you have to edit the config)
* SHOW LOGOS -> Switch team helmets to logos. (Effect stays until your mirror restarts, for permanent change you have to edit the config)
* COLOR ON -> Switch color for team logos/helmets on. (Effect stays until your mirror restarts, for permanent change you have to edit the config)
* COLOR OFF -> Switch color for team logos/helmets off. (Effect stays until your mirror restarts, for permanent change you have to edit the config)
* NETWORK ON -> Shows network information for US television. (Effect stays until your mirror restarts, for permanent change you have to edit the config)
* NETWORK OFF -> Hide network information. (Effect stays until your mirror restarts, for permanent change you have to edit the config)
* SHOW PASSING YARDS STATISTIC -> Shows statistic of Top 5 passing players.
* SHOW RUSHING YARDS STATISTIC -> Shows statistic of Top 5 rushing players.
* SHOW RECEIVING YARDS STATISTIC -> Shows statistic of Top 5 receiving players.
* SHOW TACKLES STATISTIC -> Shows statistic of Top 5 tackling players.
* SHOW SACKS STATISTIC -> Shows statistic of Top 5 sacking players.
* SHOW INTERCEPTIONS STATISTIC -> Shows statistic of Top 5 intercepting players.
* HIDE STATISTIC -> Hide statistic informations
73 changes: 73 additions & 0 deletions StatisticsAPI.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/* Magic Mirror
* Module: MMM-NFL
*
* By fewieden https://github.com/fewieden/MMM-NFL
* MIT Licensed.
*/
const jsdom = require("jsdom");

module.exports = {

URL: "http://www.espn.com/nfl/statistics",
CACHE_TIME: 2*60*1000, //2 minutes

statistics: {
timestamp: null,
data: {}
},

getStats: function(type, callback){
var time = Date.now();
if(!this.statistics.timestamp || this.statistics.timestamp < time - this.CACHE_TIME || !this.statistics.data.hasOwnProperty(type.toUpperCase())){
jsdom.env({
url: this.URL,
done: (err, window) => {
if(err){
callback(err, null);
} else {
var statistics = {};
var statisticsWrapper = window.document.querySelector("#my-players-table");
if(statisticsWrapper){
var teams = [statisticsWrapper.children[0], statisticsWrapper.children[1]];
for(var i = 0; i < teams.length; i++){
var types = teams[i].children;
for(var n = 0; n < types.length; n++){
var rows = types[n].querySelector("tbody").children;
if(rows){
statistics[rows[0].children[0].textContent] = {unit: rows[0].children[1].textContent, players: []};
for(var x = 1; x < rows.length - 1; x++){
var text = rows[x].children[rows[x].children.length -2].textContent;
statistics[rows[0].children[0].textContent].players.push({
position: text[0],
player: text.slice(3, text.lastIndexOf(",")),
team: text.slice(text.lastIndexOf(",") + 2) === "WSH" ? "WAS" : text.slice(text.lastIndexOf(",") + 2),
value: rows[x].children[rows[x].children.length - 1].textContent
});
}
}
}
}

window.close();

this.statistics = {
timestamp: time,
data: statistics
};

if(this.statistics.data.hasOwnProperty(type.toUpperCase())){
callback(null, {type: type, data: this.statistics.data[type.toUpperCase()]});
} else {
callback("Statistics for " + type + " not found!", null);
}
} else {
callback("Source changed site layout!", null);
}
}
}
});
} else {
callback(null, {type: type, data: this.statistics.data[type.toUpperCase()]});
}
}
};
Loading

0 comments on commit a22b940

Please sign in to comment.