strikeout.co scores

inclues game info on strikeout.co main page

当前为 2016-05-30 提交的版本,查看 最新版本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。

您需要先安装用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==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); }');
})()