0

I'm trying to capture some information in original image URLs, which are removed from the DOM when a fallback placeholder is used.

These images are sourced by MLB Crypto Baseball, on a portfolio page that lists assets (MLB digital collectibles) that a user owns. At the time of writing, many of these images, which reveal the aesthetic attributes of assets, did not exist. However, the file paths include numeric sequences from which attributes can be extracted. The non-existent images are replaced by a generic placeholder that does not contain attribute info.

I have attempted to capture and parse the original image URLs with a Chrome extension, to then insert relevant text onto the image placeholders. I've used an error listener, as follows (drawing on an example by @gkalpak):

content.js

var dnaProxy = document.createElement('script');
dnaProxy.id = 'dnaSpy';
dnaProxy.dataset.lastDNA = '';

dnaProxy.textContent = [
    'var attributes = {',
    '    position : { "801": "P", "802": "LF", "803": "CF", "804": "RF", "805": "1B", "806": "2B", "807": "3B", "808": "SS", "809": "C", "810": "SPECIAL", "811": "DH" },',
    '    stance : { "001": "Groundball", "002": "Fly Ball (Outfielder)", "003": "Running Catch", "004": "Long Hop", "005": "Backhand", "006": "Pop Fly", "007": "Ready", "008": "Step Behind", "009": "Crow Hop", "010": "Sidearm", "011": "Windup", "012": "Stride", "013": "Release", "014": "Snap Throw", "015": "Fly Ball (Catcher)", "016": "Jab Step", "017": "Follow Through", "018": "Stretch and Fire", "019": "Load Position", "020": "Sweet Spot", "021": "Batter-runner" },',
    '    itemType : { "001": "glove", "002": "glove", "003": "glove", "004": "glove", "005": "glove", "006": "glove", "007": "glove", "008": "glove", "009": "glove", "010": "glove", "011": "glove", "012": "glove", "013": "glove", "014": "glove", "015": "glove", "016": "glove", "017": "bat", "018": "bat", "019": "bat", "020": "bat", "021": "bat" },',
    '    item : {"bat" : {   "001": "Wood Bat",  "002": "Wood Bat w/ Grip",  "003": "Wood Bat w/ Black Finish",  "004": "Wood Bat w/ Walnut Finish", "005": "Silver Bat",    "006": "Gold Bat",  "007": "Iridescent Bat",    "008": "Jade Bat",  "009": "Ruby Bat"   },"glove" : {   "001": "Standard Glove",    "002": "Midnight Glove",    "003": "Classic Glove", "004": "Team USA Glove"} },',
    '    uniform : { "001": "Uniform Pants Long Sleeves", "002": "Uniform Pants Short Sleeves", "003": "Uniform Socks Long Sleeves", "004": "Uniform Socks Short Sleeves" },',
    '    rarity : { "000": "Common", "001": "Bronze", "002": "Silver", "003": "Gold", "004": "Legendary", "005": "Perfect Game", "006": "No Hitter", "007": "Home Run Distance (495 ft.)", "008": "Immaculate Inning", "009": "Hit for the Cycle", "010": "4 Home Run Game (Single Hitter)", "011": "Grand Slam", "012": "Triple", "013": "Hit by Pitch", "014": "Shutout", "015": "Walk Off", "016": "100 mph Pitch" },',
    '    team : { "001": "Astros", "002": "Dodgers", "003": "Cubs", "004": "Yankees", "005": "Indians", "006": "Nationals", "007": "Red Sox", "008": "Diamondbacks", "009": "Rockies", "010": "Twins", "011": "Brewers", "012": "Cardinals", "013": "Angels", "014": "Royals", "015": "Rays", "016": "Mariners", "017": "Rangers", "018": "Marlins", "019": "Blue Jays", "020": "Orioles", "021": "Athletics", "022": "Pirates", "023": "Braves", "024": "Padres", "025": "Mets", "026": "Reds", "027": "White Sox", "028": "Phillies", "029": "Tigers", "030": "Giants", "099": "Trophy" },',
    '    teamEvent : { "001": "Perfect Game", "002": "No Hitter", "003": "Home Run Distance (495 ft.)", "004": "Immaculate Inning (9 pitches 9 strikes)", "005": "Hit for the Cycle", "006": "4 Home Run Game (Single Hitter)", "007": "Grand Slam", "008": "Triple", "009": "Hit by Pitch", "010": "Shutout", "011": "Walk Off", "012": "100 mph Pitch", "013": "Home Run", "014": "Double Play", "015": "Double", "016": "5 Run Game", "017": "9 Strikeout Game", "018": "9 Hit Game", "019": "5 RBI Game" }',
    '};',
    'function parseDNA(dna) {',
    '    try {',
    '        var attrs = [];',
    '        var  result = [];',
    '        while (dna.length >= 3) { ',
    '            attrs.push(dna.substring(0, 3));',
    '            dna = dna.substring(3, dna.length);',
    '        }',
    '        result[0] = attributes.rarity[attrs[7]];', // rarity
    '        result[1] = attributes.position[attrs[0]];', // position
    '        result[2] = attributes.teamEvent[attrs[13]];', // teamEvent
    '        result[3] = attributes.stance[attrs[1]];', // stance
    '        result[4] = attributes.item[attributes.itemType[attrs[1]]][attrs[5]];', // item
    '        result[5] = attributes.uniform[attrs[6]];', // uniform
    '        return result',
    '    } catch (error) {',
    '        console.log("Couldn\'t parse DNA: ", dna, error);',
    '    }',
    '}',
    '(function() {', 
    '    var script = document.querySelector("script#' + dnaProxy.id + '");',
    '    window.addEventListener("error", function(evt) {',   
    '        var dna = [];',
    '        var dnaNew = 1;',
    '        for (var i = 0; i < evt.path[2].children.length; i++) { ',
    '            var p = evt.path[2].children[i].children[2].currentSrc;',
    '            dna[i] = p.split("/")[p.split("/").length-2];',
    '            if (p===""||p==="https://mlbcryptobaseball.com/assets/images/brand/baseball/asset-placeholder.png") dnaNew = 0; ',
    '        }',
    '        if (dnaNew===1 && dna.join(";") !== script.dataset.lastDNA) {',
    '            script.dataset.lastDNA = dna.join(";");',
    '            console.log(evt)',
    '            console.log(dna);',
    '            for (var i = 0; i < dna.length; i++) { ',
    '                var dnaParsed = parseDNA(dna[i]).join(", ");',
    '                console.log(dnaParsed);',
    '                var node = document.createElement("P");',
    '                var textnode = document.createTextNode(dnaParsed);',
    '                node.style.cssText = "color: #fff; margin: 0; padding: 0.5rem;";',
    '                node.appendChild(textnode);',
    '                document.getElementsByClassName("cards")[0].getElementsByClassName("content")[i].appendChild(node)',
    '            }',
    '        }',
    '    }, true);',
    '})();',
    ''].join('\n');

/* Add the <script> element to the DOM */
document.documentElement.appendChild(dnaProxy);

manifest.json

{
    "manifest_version": 2,

    "name":    "MLB Crypto Baseball DNA Spy",
    "version": "1.0",

    "content_scripts": [{
        "matches":    ["*://mlbcryptobaseball.com/profile/rewards/*"],
        "js":         ["content.js"],
        "run_at":     "document_start",
        "all_frames": true
    }]
}

The collectibles listed on the web page are paginated, and at present the extension works for some but not all pages (I'm not sure why). An example of a working page is seen here, where the attributes of interest have been added in white text immediately below the placeholder trophies.

I realise that this is a suboptimal approach. I don't handle other errors, for starters. I wonder if the webRequest API might be more appropriate, but I'm not sure how to implement it. Can someone provide some pointers for how best to do what I'm trying to do?

I appreciate that this is a difficult problem to test, because to do so requires users to have MetaMask installed and to own MLB Crypto Baseball assets. However, any guidance is greatly appreciated.

FWIW, here are the headers from devtools, for one of the failed image requests:

General
  Request URL: https://d1llt8x08lrx4z.cloudfront.net/Thumbnails/23/801013015018013001001000033023000012000009/Thumb.png
  Request Method: GET
  Status Code: 403 
  Remote Address: 52.85.40.121:443
  Referrer Policy: no-referrer-when-downgrade

Response Headers
  content-type: application/xml

Request Headers
  Provisional headers are shown
  Referer: https://mlbcryptobaseball.com/profile/rewards
  User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36
dApped
  • 1
  • Why do you put your code in a script element? It exposes variables and functions in page context. As for your approach in general, it seems fine so you simply need to debug those pages where it doesn't work and find what's different. – wOxxOm Sep 20 '18 at 07:34
  • Good question @wOxxOm—I have very little background in js/web dev, and was mostly following the example I linked. You’re right, though... no need to have it there! Nice to hear the general approach isn’t completely wrong! Thanks for your comment – dApped Sep 20 '18 at 08:45
  • @wOxxOm - FWIW I ended up using a Mutation Observer - worked much better – dApped Oct 01 '18 at 04:20

0 Answers0