// ==UserScript==
// @name Yahoo Fantasy Baseball Matchups 2008
// @namespace http://glenncarr.com/greasemonkey/yahoofantasy
// @include http://baseball.fantasysports.yahoo.com/*
// $LastChangedRevision$
// $LastChangedDate$
// ==/UserScript==
/*
Updates:
25-Jun-2008 - Fixed bug that was showing incorrect hitter data, added current season stats vs L/RHP pitching
8-Jul-2008 - Removed debug textarea
21-Jul-2008 - Fixed placement of 'retrieving...' status text so that rows wouldn't expand/contract as much
21-Jul-2008 - Instead of automatically displaying the matchup status, added 'Show Details' link
1-Aug-2008 - Show which way hitter bats (L,R,S)
9-Apr-2009 - Fixed to work with Yahoo 2009 changes
29-Apr-2009 - Minor tweaks: display message if preview link is available, minor UI changes
12-Jun-2009 - Now displays last week of stats for hitter
9-Jul-2009 - Fixed intermittent bug causing most last week of stats to not be displayed
*/
(function(){
if ( !/http:\/\/baseball\.fantasysports\.yahoo\.com\/.+\/.+/i.test( location.href ) )
return;
var table = document.getElementById( 'statTable0' );
if ( table == null )
return;
var commentHeader = document.evaluate( "//table[@id='statTable0']//tr[@class='headerRow1']/th/div[contains(.,'Comment')]", document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
if ( commentHeader.snapshotLength == 0 )
return;
commentHeader = commentHeader.snapshotItem( 0 );
commentHeader.innerHTML += ' Show Details';
// Change this to L14 or whatever if you want something other than last week's stats
var recentStatsUrl = location.href.replace( /(.+\/[^\/]+\/\d+\/\d+\/).+/i, '$1team?stat1=S&stat2=L7' );
var linkInvoke = commentHeader.getElementsByTagName( 'a' )[ 0 ];
linkInvoke.addEventListener( 'click', function(e) {
e.preventDefault();
if ( /show/i.test( this.innerHTML ) )
{
this.innerHTML = 'Hide Details';
showData();
}
else
{
this.innerHTML = 'Show Details';
hideData();
}
}, false );
// Adjust these per your preference
var MIN_BAD_ERA = 5.0;
var MAX_GOOD_ERA = 3.0;
var MIN_GOOD_BA = 0.3;
var MAX_BAD_BA = 0.2;
String.prototype.stripTags = function() {
return this.replace(/<\/?[^>]+>|&[^;]+;|^\s+|\s+$/gi,'');
}
var gSpan = document.createElement( 'span' );
var HITTER_HIGHLIGHT = GM_getValue("hitter_highlight_color", "#FFFFA5");
GM_setValue("hitter_highlight_color", HITTER_HIGHLIGHT);
var PITCHER_HIGHLIGHT = GM_getValue("pitcher_highlight_color", "#E0FFFF");
GM_setValue("pitcher_highlight_color", PITCHER_HIGHLIGHT);
var GOOD_STAT_STYLES = GM_getValue("good_stat_styles", "color: green; font-weight: bold;");
GM_setValue("good_stat_styles", GOOD_STAT_STYLES);
var BAD_STAT_STYLES = GM_getValue("bad_stat_styles", "color: red; font-weight: bold;");
GM_setValue("bad_stat_styles", BAD_STAT_STYLES);
GM_addStyle( '\
.gncMatchupHitter { border-bottom: solid 1px #eee; margin-bottom: 1px; position:relative }\
.gncGoodStat { ' + GOOD_STAT_STYLES + ' }\
.gncBadStat { ' + BAD_STAT_STYLES + ' }\
.gncStatus { color: #666680; font-style: italic; position:absolute; right:0px; background:#E0FFFF; padding:2px 2px; border:solid 1px black }\
.gncRecentStats { }\
.gncRecentStats TABLE TD { padding: 0px; font-size: 10px }\
#gncMatchupComment { background: #FFFFA5; color: #333; font-style: italic; white-space: normal }\
' );
var WORKING_IMG_URL = "data:image/gif,GIF89a%0A%00%0A%00%91%03%00%CC%CC%CC%FFff%FF%00%00%FF%FF%FF!%FF%" +
"0BNETSCAPE2.0%03%01%00%00%00!%F9%04%05%00%00%03%00%2C%00%00%00%00%0A%00%0A%00%00%02%17%9C'r%06%80%1A%" +
"02s'%AE%3Bqk%9A%E2%C3%81%14Gz%D9Q%00%00!%F9%04%05%00%00%03%00%2C%01%00%00%00%08%00%03%00%00%02%0A%9C%" +
"136%22%83%03%00S%10%14%00!%F9%04%05%00%00%03%00%2C%00%00%00%00%06%00%06%00%00%02%0C%9C%070%11%A8%7C%A" +
"2%11%22%D2X%00%00!%F9%04%05%00%00%03%00%2C%00%00%01%00%03%00%08%00%00%02%0A%1C%608%13%C1%BE%96%10c%16" +
"%00!%F9%04%05%00%00%03%00%2C%00%00%04%00%06%00%06%00%00%02%0A%04%86c%C9%1C%E1%A0%10l%16%00!%F9%04%05%" +
"00%00%03%00%2C%01%00%07%00%08%00%03%00%00%02%0A%04%86%23b%13%A1Dz%A9%00%00!%F9%04%05%00%00%03%00%2C%0" +
"4%00%04%00%06%00%06%00%00%02%0C%9C'r%A8%BB%11%06%00%03Jz%0A%00!%F9%04%09%00%00%03%00%2C%07%00%01%00%0" +
"3%00%08%00%00%02%0A%94f%A3%1A1%BD%00%18r%14%00%3B";
var origCells = new Array();
var newCells = new Object();
function hideData()
{
try {
for ( var i = 0; i < origCells.length; i++ )
origCells[ i ].cell.innerHTML = origCells[ i ].innerHTML;
} catch ( e ) { alert( e.description ); }
}
function showData()
{
var recentStatElements = {};
for ( var iRow = 0; iRow < table.rows.length; iRow++ )
{
var row = table.rows[ iRow ];
var rowClass = row.getAttribute( "class" );
if ( /^(even|odd)/i.test( rowClass ) )
{
var hitterLink = null;
var hitterCell = null;
var previewLink = null;
var hitterAtHome = true;
for ( var iCell = 0; iCell < row.cells.length; iCell++ )
{
var cell = row.cells[ iCell ];
var cellClass = cell.getAttribute( "class" );
if ( /^player/i.test( cellClass ) )
{
var links = cell.getElementsByTagName( 'a' );
if ( links.length > 0 )
{
hitterLink = links[ 0 ].href;
hitterCell = cell;
}
}
if ( /^gametime/i.test( cellClass ) )
{
var links = cell.getElementsByTagName( 'a' );
if ( links.length > 0 )
previewLink = links[ 0 ].href.replace( /boxscore|recap/i, 'preview' );
}
else if ( /^opp/i.test( cellClass ) )
{
hitterAtHome = !/\@/i.test( cell.innerHTML );
}
else if ( /^auto/i.test( cellClass ) )
{
if ( newCells.hasOwnProperty( hitterLink ) )
cell.innerHTML = newCells[ hitterLink ];
else
{
origCells.push( { cell:cell, innerHTML:cell.innerHTML } );
// Create an element just for the status message
var elStatus = document.createElement( 'span' );
elStatus.setAttribute( "class", "gncStatus" );
if ( previewLink != null )
elStatus.innerHTML = 'Retrieving game preview data... 
';
else
elStatus.innerHTML = 'Game preview link not available.';
var elMatchup = document.createElement( 'div' );
elMatchup.setAttribute( "class", "gncMatchupHitter" );
elMatchup.appendChild( elStatus );
// Create an element for the hitters most recent stats
var elRecentStats = document.createElement( 'div' );
elRecentStats.setAttribute( "class", "gncRecentStats" );
elRecentStats.style.display = 'none';
elMatchup.appendChild( elRecentStats );
recentStatElements[ hitterLink ] = elRecentStats;
cell.innerHTML = '
';
cell.insertBefore( elMatchup, cell.firstChild )
// Fetch game preview link, passing this cell to the callback
if ( previewLink != null )
{
GM_xmlhttpRequest({
method: 'GET',
url: previewLink,
onload: getGamePreviewInfoHandler( handlePreviewInfo, elStatus, elMatchup, hitterAtHome, hitterLink, hitterCell ),
});
}
}
}
}
}
}
try {
GM_xmlhttpRequest({
method: 'GET',
url: recentStatsUrl,
onload: getRecentStatsHandler( handleRecentStats, recentStatElements ),
});
} catch ( e ) { alert ( e ) }
}
function getRecentStatsHandler( responseHandler, recentStatElements )
{
return function ( responseDetails )
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, recentStatElements );
}
}
function handleRecentStats( responseText, recentStatElements )
{
try {
gSpan.innerHTML = responseText;
var links = gSpan.getElementsByTagName( 'a' );
var statCaptions = {};
var captionsFound = false;
for ( var iLink = 0; iLink < links.length; iLink++ )
{
var link = links[ iLink ];
if ( /players\/\d+/i.test( link.href ) )
{
if ( recentStatElements.hasOwnProperty( link.href ) )
{
if ( !captionsFound )
{
var table = link;
do
{
var table = table.parentNode;
}
while ( table != null && table.tagName != 'TABLE' );
if ( table != null )
{
for ( var iCell = 0; iCell < table.rows[ 1 ].cells.length; iCell++ )
{
var cell = table.rows[ 1 ].cells[ iCell ];
var cellClass = cell.getAttribute( "class" );
var cellValue = cell.innerHTML.stripTags();
if ( /^stat/i.test( cellClass ) && !/% started/i.test( cellValue ) )
{
statCaptions[ iCell ] = cellValue;
}
}
captionsFound = true;
}
}
var tr = link.parentNode.parentNode.parentNode;
var html = 'Last week: ';
var delim = '';
for ( var iCell = 0; iCell < tr.cells.length; iCell++ )
{
var cellValue = tr.cells[ iCell ].innerHTML.stripTags();
if ( statCaptions.hasOwnProperty( iCell ) )
{
if ( /^AVG/.test( statCaptions[ iCell ] ) )
cellValue = formatHitterBattingAverage( cellValue );
html += delim + cellValue + ' ' + statCaptions[ iCell ];
delim = ', ';
}
}
recentStatElements[ link.href ].style.display = '';
recentStatElements[ link.href ].innerHTML = html;
}
}
}
} catch ( e ) { alert( e ); }
}
function getGamePreviewInfoHandler( responseHandler, elStatus, elMatchup, hitterAtHome, hitterLink, hitterCell )
{
return function ( responseDetails )
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, elStatus, elMatchup, hitterAtHome, hitterLink, hitterCell );
else
elStatus.innerHTML = 'Unable to retrieve game preview data';
}
}
function handlePreviewInfo( responseText, elStatus, elMatchup, hitterAtHome, hitterLink, hitterCell )
{
var AWAY = 0;
var HOME = 1;
gSpan.innerHTML = responseText;
var divs = gSpan.getElementsByTagName( 'div' );
for ( var iDiv = 0; iDiv < divs.length; iDiv++ )
{
var class = divs[ iDiv ].getAttribute( "class" );
if ( /^starting-pitchers/i.test( class ) )
{
var div = divs[ iDiv ];
var thPitchers = div.getElementsByTagName( 'th' );
var oppPitcher = thPitchers[ hitterAtHome ? AWAY : HOME ].getElementsByTagName( 'a' )[ 0 ];
var rows = div.getElementsByTagName( 'tr' );
var record = '';
var era = '';
var whip = '';
for ( var iRow = 0; iRow < rows.length; iRow++ )
{
var row = rows[ iRow ];
var tds = row.getElementsByTagName( 'td' ); // first TD is away pitcher, second home pitcher
var th = row.getElementsByTagName( 'th' )[ 0 ]; // Second element is a TH with the caption
if ( /record/i.test( th.innerHTML ) )
record = tds[ hitterAtHome ? AWAY : HOME ].innerHTML;
else if ( /ERA/.test( th.innerHTML ) )
era = tds[ hitterAtHome ? AWAY : HOME ].innerHTML;
else if ( /WHIP/.test( th.innerHTML ) )
whip = tds[ hitterAtHome ? AWAY : HOME ].innerHTML;
}
var elPitcherInfo = document.createElement( 'span' );
elPitcherInfo.innerHTML =
'' + oppPitcher.innerHTML + ' ('
+ record
+ ', ' + era + ' ERA'
+ ', ' + whip + ' WHIP'
+ ')';
elStatus.innerHTML = 'Retrieving opposing pitcher data... 
';
GM_xmlhttpRequest({
method: 'GET',
url: oppPitcher.href,
onload: getPitcherInfoHandler( handlePitcherInfo, elStatus, elMatchup, hitterAtHome, elPitcherInfo, hitterLink, hitterCell ),
});
return;
}
}
}
function getPitcherInfoHandler( responseHandler, elStatus, elMatchup, hitterAtHome, elPitcherInfo, hitterLink, hitterCell )
{
return function ( responseDetails )
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, elStatus, elMatchup, hitterAtHome, elPitcherInfo, hitterLink, hitterCell );
else
elStatus.innerHTML = 'Unable to retrieve opposing pitcher data';
}
}
function handlePitcherInfo( responseText, elStatus, elMatchup, hitterAtHome, elPitcherInfo, hitterLink, hitterCell )
{
gSpan.innerHTML = responseText;
var divs = gSpan.getElementsByTagName( 'div' );
var pitcherThrows = ''; // L or R
for ( var iDiv = 0; iDiv < divs.length; iDiv++ )
{
var class = divs[ iDiv ].getAttribute( "class" );
if ( /^player-info/i.test( class ) )
{
var div = divs[ iDiv ];
var lis = div.getElementsByTagName( 'li' );
for ( var i = 0; i < lis.length; i++ )
{
var li = lis[ i ];
if ( /^throws/i.test( li.getAttribute( "class" ) ) )
{
pitcherThrows = li.lastChild.nodeValue.stripTags();
elPitcherInfo.innerHTML = pitcherThrows + 'HP ' + elPitcherInfo.innerHTML;
break;
}
}
break;
}
}
//elPitcherInfo.appendChild( document.createElement( 'br' ) );
elMatchup.appendChild( elPitcherInfo );
elStatus.innerHTML = 'Retrieving basic hitter vs pitcher data... 
';
var elHitterInfo = document.createElement( 'span' );
GM_xmlhttpRequest({
method: 'GET',
url: hitterLink,
onload: getHitterInfoHandler( handleHitterInfo, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows, hitterCell ),
});
}
function getHitterInfoHandler( responseHandler, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows, hitterCell )
{
return function ( responseDetails )
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows, hitterCell );
else
elStatus.innerHTML = 'Unable to retrieve basic hitter vs pitcher data';
}
}
function handleHitterInfo( responseText, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows, hitterCell )
{
// Get hitter's career numbers vs pitcher from main profile page
var matches = responseText.match( /(Career\s+vs\s+]+>[^<]+<\/a>)\s*<\/td>((?:\s*]+>[^<]+<\/td>)+)\s*(?:<\/tr>)/mi );
if ( matches )
{
var values = matches[ 2 ].split( /<\/td>\s* | ]+>/i );
var parts = new Array();
parts.push( ' ' ); parts.push( matches[ 1 ] ); // Career vs [pitcher name]
parts.push( ': ' ); parts.push( formatHitterBattingAverage( values[ 12 ], values[ 3 ], values[ 1 ] ) ); // Avg
parts.push( ', ' ); parts.push( values[ 15 ] ); parts.push( ' OPS' );
parts.push( ', ' ); parts.push( values[ 6 ] ); parts.push( ' HR' );
parts.push( ', ' ); parts.push( values[ 7 ] ); parts.push( ' RBI' );
parts.push( ', ' ); parts.push( values[ 8 ] ); parts.push( ' BB' );
parts.push( ', ' ); parts.push( values[ 9 ] ); parts.push( ' K' );
parts.push( ', ' ); parts.push( values[ 10 ] ); parts.push( ' SB' );
parts.push( ', ' ); parts.push( values[ 11 ] ); parts.push( ' CS' );
elHitterInfo.innerHTML = parts.join( '' );
}
elMatchup.appendChild( elHitterInfo );
var matches = responseText.match( /\s*\s*Bats:\s*<\/strong>\s*(\S+)<\/li>/mi );
if ( matches )
{
hitterCell.getElementsByTagName( 'div' )[ 0 ].innerHTML += ' (' + matches[ 1 ] + ')';
}
// Get hitter's career splits vs left/right-handed pitchers
elStatus.innerHTML = 'Retrieving career hitter vs pitcher data...  ';
var hitterSplitsLink = hitterLink + '/splits?year=career&type=Batting';
GM_xmlhttpRequest({
method: 'GET',
url: hitterSplitsLink,
onload: getHitterCareerSplitsInfoHandler( handleHitterCareerSplitsInfo, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows ),
});
}
function getHitterCareerSplitsInfoHandler( responseHandler, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows )
{
return function ( responseDetails )
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows );
else
elStatus.innerHTML = 'Unable to retrieve career hitter vs pitcher data';
}
}
function handleHitterCareerSplitsInfo( responseText, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows )
{
var re = new RegExp( 'vs\\.?\\s+' + (pitcherThrows == 'L' ? 'Left' : 'Right') + '\\s*<\\/td>((?:\\s*]+>[^<]+<\\/td>)+)\\s*(?:<\\/tr>)', "mi" );
var matches = responseText.match( re );
if ( matches )
{
var values = matches[ 1 ].split( /<\/td>\s* | ]+>/i );
elHitterInfo.innerHTML += ' Career vs ' + pitcherThrows + 'HP: '
+ formatHitterBattingAverage( values[ 13 ], values[ 4 ], values[ 2 ] ) // Avg
+ ', ' + values[ 16 ] + ' OPS'
+ ', ' + values[ 7 ] + ' HR'
;
}
// Get hitter's current season splits vs left/right-handed pitchers
elStatus.innerHTML = 'Retrieving current season hitter vs pitcher data...  ';
var hitterSplitsLink = hitterLink + '/splits?type=Batting';
GM_xmlhttpRequest({
method: 'GET',
url: hitterSplitsLink,
onload: getHitterCareerSplitsInfoHandler( handleHitterSeasonSplitsInfo, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows ),
});
}
function getHitterSeasonSplitsInfoHandler( responseHandler, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows )
{
return function ( responseDetails )
{
if ( responseDetails.status == 200 )
responseHandler( responseDetails.responseText, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows );
else
elStatus.innerHTML = 'Unable to retrieve current season hitter vs pitcher data';
}
}
function handleHitterSeasonSplitsInfo( responseText, elStatus, elMatchup, hitterAtHome, elHitterInfo, hitterLink, pitcherThrows )
{
var re = new RegExp( 'vs\\.?\\s+' + (pitcherThrows == 'L' ? 'Left' : 'Right') + '\\s*<\\/td>((?:\\s* | ]+>[^<]+<\\/td>)+)\\s*(?:<\\/tr>)', "mi" );
var matches = responseText.match( re );
if ( matches )
{
var values = matches[ 1 ].split( /<\/td>\s* | ]+>/i );
elHitterInfo.innerHTML += '; This year: ' // vs ' + (pitcherThrows == 'L' ? 'left' : 'right') + '-handers: '
+ formatHitterBattingAverage( values[ 13 ], values[ 4 ], values[ 2 ] ) // Avg
+ ', ' + values[ 16 ] + ' OPS'
+ ', ' + values[ 7 ] + ' HR'
;
}
elStatus.innerHTML = '';
newCells[ hitterLink ] = elMatchup.parentNode.innerHTML;
elStatus.style.display = 'none';
}
function formatHitterBattingAverage( avg, h, ab )
{
var favg = parseFloat( avg );
if ( typeof h == 'undefined' )
var displayAvg = avg;
else
var displayAvg = avg + ' (' + h + '/' + ab + ')';
if ( favg >= MIN_GOOD_BA )
return '' + displayAvg + ''
else if ( favg < MAX_BAD_BA )
return '' + displayAvg + ''
return displayAvg;
}
})(); | |