Initial commit
Still a lot to do here, such as better error handling and handling multiple teams matching the name typed in, but it's a start.
This commit is contained in:
61
.gitignore
vendored
Normal file
61
.gitignore
vendored
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
# Logs
|
||||||
|
logs
|
||||||
|
*.log
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
|
||||||
|
# Runtime data
|
||||||
|
pids
|
||||||
|
*.pid
|
||||||
|
*.seed
|
||||||
|
*.pid.lock
|
||||||
|
|
||||||
|
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||||
|
lib-cov
|
||||||
|
|
||||||
|
# Coverage directory used by tools like istanbul
|
||||||
|
coverage
|
||||||
|
|
||||||
|
# nyc test coverage
|
||||||
|
.nyc_output
|
||||||
|
|
||||||
|
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
|
.grunt
|
||||||
|
|
||||||
|
# Bower dependency directory (https://bower.io/)
|
||||||
|
bower_components
|
||||||
|
|
||||||
|
# node-waf configuration
|
||||||
|
.lock-wscript
|
||||||
|
|
||||||
|
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||||
|
build/Release
|
||||||
|
|
||||||
|
# Dependency directories
|
||||||
|
node_modules/
|
||||||
|
jspm_packages/
|
||||||
|
|
||||||
|
# Typescript v1 declaration files
|
||||||
|
typings/
|
||||||
|
|
||||||
|
# Optional npm cache directory
|
||||||
|
.npm
|
||||||
|
|
||||||
|
# Optional eslint cache
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
|
# Optional REPL history
|
||||||
|
.node_repl_history
|
||||||
|
|
||||||
|
# Output of 'npm pack'
|
||||||
|
*.tgz
|
||||||
|
|
||||||
|
# Yarn Integrity file
|
||||||
|
.yarn-integrity
|
||||||
|
|
||||||
|
# dotenv environment variables file
|
||||||
|
.env
|
||||||
|
|
||||||
|
# package lock
|
||||||
|
package-lock.json
|
21
LICENSE
Normal file
21
LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2018
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
166
MMM-ShiftStats.js
Normal file
166
MMM-ShiftStats.js
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
shiftStats = {};
|
||||||
|
|
||||||
|
Module.register("MMM-ShiftStats",{
|
||||||
|
defaults: {
|
||||||
|
apiKey: null,
|
||||||
|
type: 'Regular Season',
|
||||||
|
teamName: null,
|
||||||
|
sport: null,
|
||||||
|
mode: 'standings',
|
||||||
|
maxGames: 6,
|
||||||
|
teamNameClass: "light",
|
||||||
|
updateInterval: 12 * 60 * 60 * 1000
|
||||||
|
},
|
||||||
|
// search for team name, look for newest team, pick playoffs if there are games, otherwise reg season, otherwise exhibition?
|
||||||
|
// teamSearch response comes with references.season which should get you the info you need. season has multiple season.stats
|
||||||
|
// which has .Exhibition and etc. which contains games_played.
|
||||||
|
start: function() {
|
||||||
|
this.sendSocketNotification('SHIFTSTATS_CONFIG', this.config);
|
||||||
|
this.sendSocketNotification('SHIFTSTATS_UPDATE');
|
||||||
|
},
|
||||||
|
|
||||||
|
getStyles: function() {
|
||||||
|
return ["shiftstats.css"];
|
||||||
|
},
|
||||||
|
|
||||||
|
getDom: function() {
|
||||||
|
if (!shiftStats.standings || !shiftStats.games) {
|
||||||
|
let wrapper = document.createElement("div");
|
||||||
|
wrapper.innerHTML = 'Loading...';
|
||||||
|
wrapper.className += "dimmed light small";
|
||||||
|
|
||||||
|
return wrapper;
|
||||||
|
} else {
|
||||||
|
let table = document.createElement('table');
|
||||||
|
table.className = "small";
|
||||||
|
if (this.config.colored) {
|
||||||
|
table.className += " colored";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.config.mode == 'games') {
|
||||||
|
table = showGames(table, this.config)
|
||||||
|
} else {
|
||||||
|
table = showStandings(table)
|
||||||
|
}
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
socketNotificationReceived: function(notification, payload) {
|
||||||
|
if (notification === 'SHIFTSTATS_STANDINGS') {
|
||||||
|
shiftStats = payload;
|
||||||
|
this.updateDom();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function showGames(table, config) {
|
||||||
|
let now = new Date()
|
||||||
|
let mostRecent = []
|
||||||
|
shiftStats.games.games.forEach((game) => {
|
||||||
|
if (new Date(game.datetime) < now) {
|
||||||
|
mostRecent.push({
|
||||||
|
game: game,
|
||||||
|
home_team: shiftStats.games.references.team.find(team => team.id == game.home_team_id),
|
||||||
|
away_team: shiftStats.games.references.team.find(team => team.id == game.away_team_id),
|
||||||
|
})
|
||||||
|
if (mostRecent.length > config.maxGames) {
|
||||||
|
mostRecent.shift()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
let row
|
||||||
|
let cell
|
||||||
|
mostRecent.forEach((game) => {
|
||||||
|
row = document.createElement('tr')
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = game.home_team.name
|
||||||
|
cell.className = config.teamNameClass
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = game.game.stats.home_score
|
||||||
|
cell.className = 'center'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = game.game.stats.away_score
|
||||||
|
cell.className = 'center'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = game.away_team.name
|
||||||
|
cell.className = `left ${config.teamNameClass}`
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
table.appendChild(row)
|
||||||
|
})
|
||||||
|
|
||||||
|
return table
|
||||||
|
}
|
||||||
|
|
||||||
|
function showStandings(table) {
|
||||||
|
let row = document.createElement('tr')
|
||||||
|
|
||||||
|
let cell = document.createElement('th')
|
||||||
|
cell.innerHTML = 'Team'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('th')
|
||||||
|
cell.className = 'center'
|
||||||
|
cell.innerHTML = 'W'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('th')
|
||||||
|
cell.className = 'center'
|
||||||
|
cell.innerHTML = 'L'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('th')
|
||||||
|
cell.className = 'center'
|
||||||
|
cell.innerHTML = 'OTW'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('th')
|
||||||
|
cell.className = 'center'
|
||||||
|
cell.innerHTML = 'OTL'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
table.appendChild(row)
|
||||||
|
|
||||||
|
shiftStats.standings.teams.forEach((team) => {
|
||||||
|
row = document.createElement('tr')
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = team.name
|
||||||
|
cell.className = 'light'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = team.stats['Regular Season'].wins
|
||||||
|
cell.className = 'center'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = team.stats['Regular Season'].losses
|
||||||
|
cell.className = 'center'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = team.stats['Regular Season'].otw
|
||||||
|
cell.className = 'center'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
cell = document.createElement('td')
|
||||||
|
cell.innerHTML = team.stats['Regular Season'].otl
|
||||||
|
cell.className = 'center'
|
||||||
|
row.appendChild(cell)
|
||||||
|
|
||||||
|
table.appendChild(row)
|
||||||
|
})
|
||||||
|
|
||||||
|
return table
|
||||||
|
}
|
41
README.md
Normal file
41
README.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
# MMM-ShiftStats
|
||||||
|
A [MagicMirror²](https://github.com/MichMich/MagicMirror) module used to display stats from any DigitalShift site ([HockeyShift](https://hockeyshift.com), [SoccerShift](https://soccershift.com), [LacrosseShift](https://lacrosseshift.com), [FootballShift](http://footballshift.com), [BasketballShift](https://basketballshift.com), and [BaseballShift](http://baseballshift.com)).
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
1. Navigate into your MagicMirror's `modules` folder and execute `git clone https://github.com/parnic/MMM-ShiftStats.git`.
|
||||||
|
2. `cd MMM-ShiftStats`
|
||||||
|
3. Execute `npm install` to install the node dependencies.
|
||||||
|
4. Add the module inside `config.js` placing it where you prefer.
|
||||||
|
|
||||||
|
## Config
|
||||||
|
|Option|Type|Description|Default|
|
||||||
|
|---|---|---|---|
|
||||||
|
|apiKey|`string`|Your API key. If not supplied, the HockeyShift Android app's key is used by default.||
|
||||||
|
|teamName|`string`|(REQUIRED) The name of the team you want to track.||
|
||||||
|
|sport|`string`|(REQUIRED) The name of the sport you want to track (e.g. `'hockey'`, `'soccer'`).||
|
||||||
|
|mode|`string`|What mode the module should run in. Valid values: `'standings'`, `'games'`|`'standings'`|
|
||||||
|
|maxGames|`number`|When in `games` mode, how many games should be shown (it will show this many most recent games).|`6`|
|
||||||
|
|teamNameClass|`string`|CSS class to apply to displayed team names.|`'light'`|
|
||||||
|
|updateInterval|`number`|How frequently, in milliseconds, to update the info.|`12 * 60 * 60 * 1000` (every 12 hours)|
|
||||||
|
|
||||||
|
Here is an example of an entry in config.js
|
||||||
|
```
|
||||||
|
{
|
||||||
|
module: 'MMM-ShiftStats',
|
||||||
|
header: 'Standings',
|
||||||
|
position: 'top_left',
|
||||||
|
config: {
|
||||||
|
teamName: 'Bears',
|
||||||
|
sport: 'Hockey'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
```
|
||||||
|
|
||||||
|
## Screenshot
|
||||||
|

|
||||||
|
|
||||||
|
## Notes
|
||||||
|
Pull requests are very welcome! If you'd like to see any additional functionality, don't hesitate to let me know.
|
||||||
|
|
||||||
|
## Dependencies
|
||||||
|
This uses a Node.JS library I created for interfacing with DigitalShift sites: [node-shiftstats](https://github.com/parnic/node-shiftstats), so feel free to check that out for more information.
|
59
node_helper.js
Normal file
59
node_helper.js
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
let NodeHelper = require('node_helper')
|
||||||
|
let ShiftStats = require('node-shiftstats')
|
||||||
|
|
||||||
|
module.exports = NodeHelper.create({
|
||||||
|
start: function() {
|
||||||
|
this.setTimer(12 * 60 * 60 * 1000)
|
||||||
|
},
|
||||||
|
|
||||||
|
doUpdate: async function() {
|
||||||
|
console.log("doupdate")
|
||||||
|
if (!this.config) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const s = new ShiftStats(this.config.apiKey)
|
||||||
|
await s.login()
|
||||||
|
let teams = await s.teamSearch(this.config.sport, this.config.teamName)
|
||||||
|
// standings will be sorted in the order of the type we requested (regular season, playoffs, ...) but also includes
|
||||||
|
// stats for other types. consider sorting by the type we want first. see property division_rank
|
||||||
|
let standings = await s.divisionStandings(teams.references.division[0].id, this.config.type)
|
||||||
|
let games = sortGames(await s.divisionGamesList(teams.references.division[0].id), this.config.type)
|
||||||
|
this.sendSocketNotification('SHIFTSTATS_STANDINGS', {standings: standings, games: games})
|
||||||
|
},
|
||||||
|
|
||||||
|
setTimer: function(updateInterval) {
|
||||||
|
var update = true
|
||||||
|
update = typeof this.updateInterval === 'undefined' || this.updateInterval != updateInterval
|
||||||
|
this.updateInterval = updateInterval
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
if (typeof this.timer !== 'undefined') {
|
||||||
|
clearInterval(this.timer)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.timer = setInterval(() => {
|
||||||
|
this.doUpdate()
|
||||||
|
}, this.updateInterval)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
socketNotificationReceived: function(notification, payload) {
|
||||||
|
if (notification === 'SHIFTSTATS_CONFIG') {
|
||||||
|
this.config = payload
|
||||||
|
this.setTimer(this.config.updateInterval)
|
||||||
|
}
|
||||||
|
if (notification === 'SHIFTSTATS_UPDATE') {
|
||||||
|
this.doUpdate()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function sortGames(games, type) {
|
||||||
|
games.games = games.games.filter(game => game.type == type)
|
||||||
|
games.games.sort((a, b) => {
|
||||||
|
return new Date(a.datetime) - new Date(b.datetime)
|
||||||
|
})
|
||||||
|
|
||||||
|
return games
|
||||||
|
}
|
12
package.json
Normal file
12
package.json
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"name": "magic-mirror-module-shiftstate",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "Show data from DigitalShift sites",
|
||||||
|
"main": "MMM-ShiftStats.js",
|
||||||
|
"author": "Chris Pickett",
|
||||||
|
"repository": "https://github.com/parnic/MMM-ShiftStats.git",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"node-shiftstats": "^1.0.0"
|
||||||
|
}
|
||||||
|
}
|
BIN
screenshot.png
Normal file
BIN
screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 185 KiB |
11
shiftstats.css
Normal file
11
shiftstats.css
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
.MMM-ShiftStats td {
|
||||||
|
padding: 2px 5px 2px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MMM-ShiftStats td.center, th.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.MMM-ShiftStats td.left {
|
||||||
|
text-align: left;
|
||||||
|
}
|
Reference in New Issue
Block a user