0

I made a chrome extension that adds IMDB information onto Netflix Movies and TV Shows. I am new to web dev, and I made this in order to learn and practice my JS. The extension works and the ratings are added to the movies/tv shows info page, but they almost always don't appear unless I scroll a little bit. I have posted my code, and a video demonstrating this.

https://i.stack.imgur.com/gMM7x.jpg (Notice how rating don't come up until I scroll)

//manipulates the DOM to extract the title and year of a video, then calls appropriate function
function fetchMovieNameYear() {
    var synopsis = document.querySelectorAll('.jawBone .jawbone-title-link');
    //console.log(synopsis);
    // If synopsis is null returns undefined
    if (synopsis === null) {
        console.log('Synopsis not found');
        return;
    }
    //returns a nodelist containing the appropriate div
    var logoElement = document.querySelectorAll('.jawBone .jawbone-title-link .title');
    //if logoElement has no memebers, returns undefined
    if (logoElement.length === 0){
        return;
    }
    //logoElement is now just the div containing the img that has the title
    logoElement = logoElement[logoElement.length - 1];

    //Extract the actual Title of the Film or TV Show
    var title = logoElement.querySelector(".logo").getAttribute("alt");

    //Nodelist containing year of the video
    var yearElement = document.querySelectorAll('.jawBone .jawbone-overview-info .meta .year');

    //if yearElement has no members, returns undefined
    if (yearElement.length === 0){
        console.log('YearElement Not found');
        return;
    }
    var year = yearElement[yearElement.length - 1].textContent;
    var divId = getDivId(title, year);
    var divEl = document.getElementById(divId);
    //If rating has already been added for this element, it exits the function
    if (divEl && (divEl.offsetWidth || divEl.offsetHeight || divEl.getClientRects().length)) {
        return;
    }

    var existingImdbRating = window.sessionStorage.getItem(title + ":" + year);

    if ((existingImdbRating !== "undefined") && (existingImdbRating !== null)) {
        addIMDBRating(existingImdbRating, title, year);
    } else {
        makeRequestAndAddRating(title, year)
    }
};

//parses imdbMetaDeta, creates a div with rating and votecount info, and adds it to the DOM
function addIMDBRating(imdbMetaData, name, year) {
    var divId = getDivId(name, year);
    //console.log(divId);
    var divEl = document.getElementById(divId);
    //If rating has already been added for this element, it exits the function
    if (divEl && (divEl.offsetWidth || divEl.offsetHeight || divEl.getClientRects().length)) {
        return;
    }

    var synopsises = document.querySelectorAll('.jawBone .synopsis');
    if (synopsises.length) {
        var synopsis = synopsises[synopsises.length - 1];
        var div = document.createElement('div');

        var imdbRatingPresent = imdbMetaData && (imdbMetaData !== 'undefined') && (imdbMetaData !== "N/A");

        var imdbVoteCount = null;
        var imdbRating = null;
        var imdbId = null;
        if (imdbRatingPresent) {
            var imdbMetaDataArr = imdbMetaData.split(":");
            imdbRating = imdbMetaDataArr[0];
            imdbVoteCount = imdbMetaDataArr[1];
            imdbId = imdbMetaDataArr[2];
        }

        var imdbHtml = null;
        if((imdbRating!=="undefined")||(imdbVoteCount!=="undefined")){
           imdbHtml = 'IMDb rating : ' + "<strong>" + (imdbRatingPresent  ? imdbRating : "N/A")+"</strong>" +"<br>" + "Vote Count : " +"<strong>" + (imdbVoteCount ?  imdbVoteCount : "N/A")+"</strong>";
        }else{
            imdbHtml = "IMDb rating : <strong>Rare_Issue</strong> <br> Vote Count : <strong>Rare_issue</strong> ";
        }

        if (imdbId !== null && (imdbId !== 'undefined')) {
            imdbHtml = "<a style='color:#f3ce13;' target='_blank' href='https://www.imdb.com/title/" + imdbId + "'>" + imdbHtml + "</a>";
        }
        div.style.color = "#f3ce13";
        div.innerHTML = imdbHtml;
        div.className = 'imdbRating';
        div.id = divId;

        synopsis.parentNode.insertBefore(div, synopsis);
    }
}//Creates an Id for the Div that will contain the rating information. Used later on to reduce multiple rating inputs
function getDivId(name, year) {
    name = name.replace(/[^a-z0-9\s]/gi, '');
    name = name.replace(/ /g, '');
    return "aaa" + name + "_" + year;
}

//Makes API call, gets metadata about move/show and calls addImdbRating
function makeRequestAndAddRating(name, year) {

    var url = "https://www.omdbapi.com/?i=tt3896198&apikey=70106a0a" + "&t=" +encodeURI(name)
    + "&y=" + year + "tomatoes=true";


    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.withCredentials = true;
    //xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.onload = function () {
        if (xhr.status === 200) {
            var apiResponse = JSON.parse(xhr.responseText);
            //var metaScore= apiResponse["metaScore"];  
            var imdbRating = apiResponse["imdbRating"];
            var imdbVoteCount = apiResponse["imdbVotes"];
            var imdbId = apiResponse["imdbID"];
            var imdbMetaData = imdbRating + ":" + imdbVoteCount + ":" + imdbId;
            window.sessionStorage.setItem(name + ":" + year, imdbMetaData);
           // window.sessionStorage.setItem("metaScore:" + name + ":" + year, metaScore)
            //window.sessionStorage.setItem("rotten:" + name + ":" + year, rottenRating);
            addIMDBRating(imdbMetaData, name, year);
           // addRottenRating(rottenRating, name, year);
           // addMetaScore(metaScore, name, year);
       }
   };
    xhr.send();
}

//Calls fetchMovieNameYear when the user clicks the chevron on the video thumbnail
if (window.sessionStorage !== "undefined") {
    var target = document.body;
    // create an observer instance
    var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            window.setTimeout(fetchMovieNameYear, 5);
        });
    });
    // configuration of the observer:
    var config = {
        attributes: true,
        childList: true,
        characterData: true
    };
    observer.observe(target, config);
}

New Code below:

    function debounce(func, wait, immediate) {
    var timeout;
    return function() {
        var context = this, args = arguments;
        var later = function() {
            timeout = null;
            if (!immediate) func.apply(context, args);
        };
        var callNow = immediate && !timeout;
        clearTimeout(timeout);
        timeout = setTimeout(later, wait);
        if (callNow) func.apply(context, args);
    };
};
var myEfficientFn = debounce(fetchMovieNameYear(), 250);
        window.addEventListener('MutationEvent', myEfficientFn);
//Calls fetchMovieNameYear when the user clicks the chevron on the video thumbnail
if (window.sessionStorage !== "undefined") {
    var target = document.body;
    // create an observer instance
    var observer = new MutationObserver(function (mutations) {

        myEfficientFn();
    });
    // configuration of the observer:
    var config = {
        attributes: true,
        childList: true,
        characterData: true
    };
    observer.observe(target, config);
}

enter code here
BrownBoii333
  • 85
  • 1
  • 8
  • Such issues should be investigated in devtools debugger. The only obviously wrong thing in the code is the MutationObserver callback: you don't need forEach there, and you should switch to *debounce* (google it up) instead of plain setTimeout. – wOxxOm May 18 '20 at 17:29
  • What would I do instead of forEach, just call the function "fetchMoveNameYear"? – BrownBoii333 May 18 '20 at 17:43
  • No, use debounce. – wOxxOm May 18 '20 at 17:46
  • when you say debounce, do you mean the _.debounce function from underscore.js?If so I'm having trouble getting my use the underscore library with my content script – BrownBoii333 May 18 '20 at 18:11
  • No need for the library, here's a [random google result](https://davidwalsh.name/javascript-debounce-function). – wOxxOm May 18 '20 at 18:13
  • I think I did it, but now I don't get any errors or anything, but my extension does nothing. Nothing happens. I added the new code at the bottom of my original post – BrownBoii333 May 18 '20 at 18:22
  • This is not how debounce is used. Did you see the link I gave? – wOxxOm May 18 '20 at 18:24
  • Sorry, I looked at the link and the usage example and tried to apply it. but now I get this error "Uncaught TypeError: Cannot read property 'apply' of undefined at later" – BrownBoii333 May 18 '20 at 18:43
  • Remove `()` in debounce(fetchMovieNameYear(), 250) – wOxxOm May 18 '20 at 18:48
  • Thanks that fixed the error! However the behavior of the extension is now still pretty much identical to how it was before. I still almost always need to scroll to display the ratings – BrownBoii333 May 18 '20 at 18:53
  • Refer to my first comment. You need to debug it in devtools debugger. – wOxxOm May 18 '20 at 18:57
  • I think the issue is that in fetchMovieNameYear the variables that are extracting the title and year information. even though I have clicked the thumbnail, and the part of the dom they need to search now exists, they are not returning or searching in the right place. However for whatever reason the first movie I expand in any row does search and return the correct movie. I don't know how to fix this however. I have attached link to a post about this (it contains a video illustrating this better), I would really appreciate if you could take a look. Thanks for all the help so far – BrownBoii333 May 18 '20 at 21:43
  • 1
    This is a debugging problem. Debugging exists exactly to solve such issues. Knowing how to debug is an essential skill in programming. To help you I would have to debug your extension myself. – wOxxOm May 19 '20 at 05:52

0 Answers0