inclues game info on strikeout.co main page
当前为
// ==UserScript==
// @name strikeout.co scores
// @namespace http://your.homepage/
// @version 0.93
// @description inclues game info on strikeout.co main page
// @author muffleyd
// @match http://www.strikeout.co/
// @grant $
// ==/UserScript==
/** Copywrite David Muffley 2015-2016.
* Use however you like, with acknowledgement.
*/
(function () {
//_main() won't run through if tab is hidden, this stores when that occurs so on tab visibility it can run again
var SKIPPED = false
var addedClasses = ['_tmMLBFree', '_tmESPN']
var selectorParent = '#content h1[league="Major League Baseball"]'
function parseTime(time) {
//time can be in format of "10:35" or timezone like "-03:30" or "+9:30"
var mod = 1
if (time[0] == '-' || time[0] == '+') {
if (time[0] == '-') {
mod = -1
}
time = time.substring(1)
}
time = time.split(':')
return mod * ((parseInt(time[0]) * 60) + parseInt(time[1]))
}
//set "mlbgday" attr to match mlb.com's scoreboard since "gday" attribute may not match mlb's date, based on timezone
(function () {
var timezoneMod = parseTime(timezone) + 240 // + 240 makes this effectively eastern time, close enough
$(selectorParent + ' .matchtime').each(function (index, el) {
var val = el.getAttribute('gday')
//even at -12:00 it can't be behind by a day, it can only ever be ahead by a day all the way to +13:00
if (parseTime(el.innerText) - timezoneMod < 0) {
var dateObj = new Date(val)
dateObj.setTime(dateObj.getTime() - (86400 * 1000))
val = dateObj.toJSON().slice(0, 10)
}
el.setAttribute('mlbgday', val)
})
})()
//pass an optional delay in
// when waking up from sleep the network connection is not immediately active, this allows you to compensate for that
function main(delay) {
if (!delay) {
delay = 0
}
setTimeout(_main, delay * 1000)
}
// 5 hours in the past, for when it's after midnight, not sure if needed
function _main() {
//skip when tab is hidden or window is minimized, and set so event is later told to run main()
if (document.hidden) {
SKIPPED = true
return
}
var dateObj = new Date()
//offset the computer's timezone to get UTC, then go back 10 hours to guarantee you use the correct date for mlb.com
var date = new Date(dateObj.getTime() + (dateObj.getTimezoneOffset() * 60 * 1000) - (1000 * 60 * 60 * 10))
var year = date.getFullYear().toString()
//January is 0, etc, so add 1
var month = date.getMonth() + 1
if (month < 10) {
month = "0" + month.toString()
} else {
month = month.toString()
}
var day = date.getDate()
if (day < 10) {
day = "0" + day.toString()
} else {
day = day.toString()
}
$.getJSON('http://gd2.mlb.com/components/game/mlb/year_' + year + '/month_' + month + '/day_' + day + '/miniscoreboard.json', function (resp, type) {
if (type == 'success') {
$(document).ready(function () {
//clear previously added classes to elements
addedClasses.forEach(function (item) {
$(selectorParent).removeClass(item)
})
var info = resp.data.games.game
if (info.length === undefined) { //if only one game, it's not passed back as an array
info = [info]
}
var gameObj = {}
//on later runs, remove added text immediately
$(selectorParent + ' a ._tmInfo').remove()
//get all team names from today
$(selectorParent + ' a:has(span[mlbgday="' + year + '-' + month + '-' + day + '"])').each(function (index, el) {
var gameText = el.lastChild.textContent.trim()
//Find games missing the colon before "Game #" and add it in
gameText = gameText.replace(/([^:])(\s+[Gg]ame\s+[0-9]+)$/, '$1:$2')
//this match regex handles things like:
// Team vs Team
// Team vs Team: Game 2
// MLB Wildcard: Team vs Team
// ALDS: Team vs Team: Game 1
//regex split is for occasional non-space blank character (tab has been there)
var txt = gameText.match(/([^:]+:|^)(.*?vs[^:$]+)(.*)/)
if (txt === null) {
console.log('not a game', gameText)
//something like "MLB on Fox Sports 1 Pregame"
return
}
var texts = txt[2].split(/\s+vs\s+/)
texts.forEach(function (item) {
var splitItems = item.trim().split(/\s+/)
//strip out this special thing that has appeared during spring training
if (splitItems[splitItems.length-1] == '(ss)') {
splitItems.pop()
}
splitItems.forEach (function (item, index, arr) {
//combine all words after the first, getting smaller and smaller,
//because of things like "Chicago White Sox" while avoiding "Los Angeles Dodgers"
if (index == 0) {
return
}
var key = arr.slice(index).join(' ')
if (!gameObj.hasOwnProperty(key)) {
gameObj[key] = []
}
//place at the head since the (reversed) game array goes from the beginning of gameObj[key]
//include the original text so extra stuff can stay when rewriting it later
gameObj[key].unshift([el, txt])
})
})
})
//fix differences
if (gameObj.hasOwnProperty('Diamondbacks')) {
gameObj['D-backs'] = gameObj['Diamondbacks']
}
console.log(gameObj)
//sort handles out of order games in the info list which happens sometimes with resumed games or double headers
info.sort(function (a, b) {
//test for NaN because sometimes "time" is like "Game 2"
var t1 = a.time.split(':')
t1 = (t1[0] * 60) + (1*t1[1])
if (isNaN(t1)) {
return 0
}
var t2 = b.time.split(':')
t2 = (t2[0] * 60) + (1*t2[1])
if (isNaN(t2)) {
return 0
}
//note that mlb.com returns all times as ET
//some games start at 12:35pm, and rarely in the 11am hour, while never being 11pm or later
//since there's no 24 hour time these need to be set as being before 1pm
if (t1 >= 11*60) {
t1 -= (12*60)
}
if (t2 >= 11*60) {
t2 -= (12*60)
}
//
if (t1 < t2) {
return -1
}
if (t1 > t2) {
return 1
}
return 0
})
info.reverse()
info.forEach(function (item, index, arr) {
var unknownStatus = false
var delayed = false
var postponed = false
var stop = false
var media = true
if (item.status == 'Pre-Game' || item.status == 'Preview') {
//after removing the first item and managing media info this will return
stop = true
} else if (item.status == 'In Progress' || item.status == 'Review' || item.status == 'Manager Challenge') {
//good
} else if (item.status == 'Game Over' || item.status == 'Final') {
//good
media = false
} else if (item.status == 'Delayed Start' || item.status == 'Delayed') {
//delay, but good
delayed = true
} else if (item.status == 'Warmup') {
//good
} else if (item.status == 'Postponed' || item.status == 'Suspended') {
postponed = true
} else {
unknownStatus = true
console.log('other status:', item.status, item)
}
console.log(item.away_team_name, item.home_team_name)
if (!gameObj.hasOwnProperty(item.away_team_name) || !gameObj.hasOwnProperty(item.home_team_name)) {
return
}
var gameEl = gameObj[item.away_team_name][0][0]
var originalMainText = gameObj[item.away_team_name][0][1]
if (gameEl !== gameObj[item.home_team_name][0][0]) {
//cry
console.log('mismatch', item)
} else if (gameEl) {
//pop off the game values, in case of double header
gameObj[item.away_team_name].shift()
gameObj[item.home_team_name].shift()
console.log(item, gameEl)
if (media) {
handle_game_media(item, gameEl)
}
//for double headers, now that the game is popped off we can return
if (stop) {
return
}
var text = ''
var cls = ''
if (item.status == 'Warmup') {
text = 'Warmup'
cls = 'warmup'
} else {
if (item.status == 'Game Over' || item.status == 'Final') {
text = 'Final'
//usually extra innings, perhaps rain-shortened?
if (item.inning != 9) {
text += ' (' + item.inning + ')'
}
cls = 'final'
} else {
if (postponed) {
cls = 'postponed'
}
//Top 3, Bottom 5, Middle 7, etc.
//also determine if no hitter worth mentioning
if (item.hasOwnProperty('inning')) {
if (item.top_inning == "Y") {
if (item.outs == 3) {
var topbottom = 'Middle'
} else {
topbottom = 'Top'
}
} else {
if (item.outs == 3) {
topbottom = 'End'
} else {
topbottom = 'Bottom'
}
}
text = topbottom + ' ' + item.inning
if (item.inning >= 7 && (item.away_team_hits == 0 || item.home_team_hits == 0)) {
cls += ' noHitter'
}
}
}
if (item.hasOwnProperty('away_team_runs') && item.hasOwnProperty('home_team_runs')) {
text += ', ' + item.away_team_runs + '-' + item.home_team_runs
var parens = true
} else {
parens = false
}
if (delayed || postponed) {
text += ' '
if (parens) {
text += '('
}
text += item.status
if (item.reason) {
text += ': ' + item.reason
}
if (parens) {
text += ')'
}
}
}
if (unknownStatus) {
text += ' DEBUG:' + item.status
}
//get original text surrounding the 'Team vs Team' to include along with the reordering of the Teams to Away vs Home
gameEl.lastChild.textContent = originalMainText[1] + ' ' + getTeamName(item, 'away') + ' vs ' + getTeamName(item, 'home') + originalMainText[3]
if (text) {
$('<span class="_tmInfo">, <span class="_tmText ' + cls + '">' + text + '</span></span>').appendTo(gameEl)
}
}
})
})
}
})
}
function handle_game_media(item, gameEl) {
if (item.game_media && item.game_media.media) {
var media = item.game_media.media
if ($.isArray(item.game_media.media)) {
media = item.game_media.media[0]
}
if (media.free != "NO") {
if (media.free != "ALL") {
console.log('different media free info', media)
}
gameEl.parentElement.classList.add('_tmMLBFree')
}
}
if (item.tv_station) {
item.tv_station.split(', ').forEach(function (station) {
if (station == 'ESPN' || station == 'ESPN2' || station == 'ESPN (out-of-market only)') {
gameEl.parentElement.classList.add('_tmESPN')
}
})
}
}
//example why this is needed:
//team_city: 'NY Yankees'
//team_name: 'Yankees'
//Should return 'NY Yankees' rather than 'NY Yankees Yankees'
function getTeamName(item, homeaway) {
var city = item[homeaway + '_team_city']
var name = item[homeaway + '_team_name']
if (city.slice(-name.length) == name) {
return city
} else {
return city + ' ' + name
}
}
var initial_delay = 6
var constant_delay = 120
main()
//this blob compensates for 'initial_delay'
// e.g. main loop runs every 2 minutes, with a 6 second initial delay,
// this will wait 114 seconds to run main(6) and register the Interval of 120 seconds at the same time to run main(6)
setTimeout(function () {
main(initial_delay)
setInterval(main, 1000 * constant_delay, initial_delay)
}, 1000 * (constant_delay - initial_delay))
//since we don't do anything when the tab is invisible, force an update when made visible if one was skipped
document.addEventListener('visibilitychange', function () {
if (!document.hidden) {
if (SKIPPED) {
SKIPPED = false
main()
}
}
})
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
addGlobalStyle('._tmInfo ._tmText { color: red; }');
addGlobalStyle('._tmInfo ._tmText.warmup { color: goldenrod; }');
addGlobalStyle('._tmInfo ._tmText.final { color: grey; }');
addGlobalStyle('._tmInfo ._tmText.postponed { color: blue; }');
addGlobalStyle('._tmInfo ._tmText.noHitter { background: chartreuse; }');
addGlobalStyle(selectorParent + '._tmMLBFree { background: gold; }');
addGlobalStyle(selectorParent + '._tmESPN { background: rgba(255,7,7,.25); }');
})()