gazza911 / Netflix - Open Largest Images

// ==UserScript==
// @name         Netflix - Open Largest Images
// @namespace    Netflix
// @version      1.2
// @description  Get the largest Netflix images of each type
// @author       gazza911
// @match        https://www.netflix.com/browse*
// @match        https://www.netflix.com/title*
// @match        https://www.netflix.com/*/title*
// @match        https://www.netflix.com/search*
// @match        https://www.netflix.com/watch*
// @icon         https://www.google.com/s2/favicons?domain=netflix.com
// @grant        GM.openInTab
// @grant        GM.registerMenuCommand
// @run-at       document-start
// @updateURL    https://openuserjs.org/meta/gazza911/Netflix_-_Open_Largest_Images.meta.js
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @license      MIT
// ==/UserScript==

(function() {
   var clickedEl;

    document.addEventListener("contextmenu", function(event){
        clickedEl = event.target;
    });

    GM.registerMenuCommand("Open Largest Element", ()=>{
        openLargestImage(clickedEl);
    });
})();

function getHighestImages(path, dimension) {
    var highestDimension = 0;
    var images = [];
    if (path) {
        for (var i = 0; i < path.length; i++) {
            if (path[i][dimension] > highestDimension) {
                images = [path[i].url];
                highestDimension = path[i].h;
            } else if (path[i][dimension] === highestDimension) {
                if (images.indexOf(path[i].url) === -1) {
                    images.push(path[i].url);
                }
            }
        }
    }
    return images;
}

function getTrackId(href) {
    if (href.indexOf('/watch/') === 0 || href.indexOf('/title/') === 0) {
        var end = href.indexOf('?');
        if (end > 0) {
            return href.substr(7, end - 7);
        } else {
            return href.substr(7);
        }
    }
}

function getDataFromSections(clickedEl) {
    var sectionData = netflix.reactContext.models.nmTitleUI.data.sectionData;
    var clickedImg = clickedEl.src || clickedEl.style["background-image"];
    if (clickedImg.indexOf("url") === 0) {
        var match = /url\(['"]*([^\)]*?)['"]*\)/gm.exec(clickedImg);
        clickedImg = match[1];
    }
    var track;
    for (var section of Object.values(sectionData)) {
        switch (section.type) {
           case "hero": {
               if (clickedImg === section.data.artwork.heroImage.url) {
                   GM.openInTab(clickedImg);
                   return {trackId: null, episodeId: null};
               }
               break;
           }
            case "additionalVideos": {
                for (var i = 0; i < section.data.supplementalVideos.length; i++) {
                   if (clickedImg === section.data.supplementalVideos[i].placeholderImageUrl) {
                       return {trackId: section.data.supplementalVideos[i].id, episodeId: null};
                   }
                }
                break;
            }
            case "seasonsAndEpisodes": {
                for (var j = 0; j < section.data.seasons.length; j++) {
                    for (var k = 0; k < section.data.seasons[j].episodes.length; k++) {
                        if (clickedImg === section.data.seasons[j].episodes[k].artworkUrl) {
                            return {trackId: section.data.seasons[j].episodes[k].episodeId, episodeId: section.data.seasons[j].episodes[k].episodeId};
                        }
                    }
                }
                break;
            }
            case "moreTitles": {
                for (var l = 0; l < section.data.titles.length; l++) {
                   if (clickedImg === section.data.titles[l].imageSrc) {
                       return {trackId: section.data.titles[l].id, episodeId: null};
                   }
                }
                break;
            }
        }
    }
}

function openLargestImage(clickedEl) {
    var apiUrl = netflix.reactContext.models.playerModel.data.config.ui.initParams.apiUrl;
    if (apiUrl) {
       var trackId;
       var episodeId;
       if ($(':focus').length > 0 || $(clickedEl).length === 1) {
           if ($(':focus').hasClass('previewModal--container')) {
               trackId = $(':focus').children(':first').children(':first').children(':first').attr("id");
               if (!/^\d+$/.test(trackId)) {
                  trackId = null;
               }
           }
           else {
               var href = $(':focus').attr('href');
               href = href ?? $(':focus').closest('.slider-refocus').attr("href");
               trackId = href ? getTrackId(href) : null;
               if (!trackId) {
                   href = $(':focus').closest('.slider-refocus').attr("href");
                   trackId = href ? getTrackId(href) : null;
               }
               var ptrackData = $(':focus').find('.ptrack-content').data('ui-tracking-context');
               if (ptrackData) {
                   var startVideoIndex = ptrackData.indexOf('%22video_id%22:');
                   var endVideoIndex = ptrackData.indexOf(',', startVideoIndex);
                   trackId = ptrackData.substr(startVideoIndex + 15, endVideoIndex - startVideoIndex - 15);
                   episodeId = parseInt(trackId);
               }
               if (!trackId) {
                   trackId = getTrackId(window.location.pathname);
               }
           }
           if (!trackId && $(clickedEl).length === 1) {
               var data = getDataFromSections(clickedEl);
               if (data) {
                   trackId = data.trackId;
                   episodeId = data.episodeId;
               }
           }
           if (trackId) {
               $.get(apiUrl + '/metadata?movieid=' + trackId, function (data) {
                   var images = {};
                   if (episodeId) {
                       for (var season of data.video.seasons) {
                           for (var episode of season.episodes) {
                               if (episodeId === episode.episodeId) {
                                   images.episode = getHighestImages(episode.stills, 'w');
                               }
                           }
                       }
                   } else {
                       images.artwork = getHighestImages(data.video.artwork, 'w');
                       images.stills = getHighestImages(data.video.stills, 'w');
                       images.storyart = getHighestImages(data.video.storyart, 'w');
                       images.boxart = getHighestImages(data.video.boxart, 'h');
                       window.open(apiUrl + '/metadata?movieid=' + trackId);
                   }
                   for (var type in images) {
                       for (var i = 0; i < images[type].length; i++) {
                           GM.openInTab(images[type][i]);
                       }
                   }
               });
           }
       }
   } else {
       console.log('Unable to get shakti build');
   }
}