pietro.giucastro / Youtube OCD Sugoi Ratio

// ==UserScript==
// @name         Youtube OCD Sugoi Ratio
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  Know in advance how much videos are appreciated! The result of each video is the ratio between its likes and unlikes (Update: fixed bugs. If a video can't be analyzed, you will find "1/1" instead of the real ratio.)
// @author       speep95 (pietrogiucastro@alice.it)
// @match        https://www.youtube.com/*
// @match        http://www.youtube.com/*
// @require      http://code.jquery.com/jquery-latest.js
// @grant        none
// ==/UserScript==

var rcmain = $('<div class="result-container result-main"><div class="ocd-spinner"></div></div>')[0];
var rcmainnew = $('<div class="result-container result-main-new"><div class="ocd-spinner"></div></div>')[0];
var rclat =  $('<div class="result-container result-lat"><div class="ocd-spinner"></div></div>')[0];
var rclatplay =  $('<div class="result-container result-lat-play"><div class="ocd-spinner"></div></div>')[0];
var rcchannel =  $('<div class="result-container result-channel"><div class="ocd-spinner"></div></div>')[0];

var computer = {
    luratioCalc : function(a) {
        a.luratio = a.stats.likes / a.stats.dislikes;
        if (isNaN(a.luratio)) a.luratio = 1; //check if 0/0
        else if (!isFinite(a.luratio)) a.luratio = a.stats.likes; //check if Infinite (3/0)

        return Math.floor(a.luratio*10)/10;
    },
    luratio : function(videolist) {
        videolist.forEach(function(a) {
            a.result = computer.luratioCalc(a);
        });
        return videolist;
    }
};

function getParam(url, par) {
    if (!url.split('?')[1]) return;
    var parValue;
    url.split('?')[1].split('&').forEach(function(el) {
        if (el.split('=')[0] == par) { parValue =  el.split('=')[1]; return;}
    });
    return parValue;
}

function initVideoList(videos) {
    videolist = [];
    $(videos).each(function() {
        videolist.push(
            {element: this,
             url: getParam($(this).find('a')[0].href, 'v'),
             stats: {views: -1, likes: -1, dislikes: -1, pubDate: new Date(0)}}
        );
    });

    return videolist;
}

function getSetAPI(videolist) {
    var partlist = videolist.splice(0,40); // get first 40 ids
    var idlist = partlist.map(function(e) { return e.url; });
    var url = 'https://www.googleapis.com/youtube/v3/videos?id=';
    url += idlist.toString();
    console.log('ocd - checking ' + idlist.length + ' elements..');

    $.get(url , {
        key    :   'AIzaSyCtO4m53m1gQzxJzJes_KiURc0xoTcwsbg',
        part   :   'snippet,statistics'
    }, function(res) {
        partlist = setAPI(res.items, partlist);
        setRatios(partlist);
        if (videolist.length) getSetAPI(videolist);
    });
}

function setAPI(res, videolist) {
    res.forEach(function(item, index) {
        if (!item.statistics) return console.log(item);
        videolist[index].stats.views = parseInt(item.statistics.viewCount || -1);
        videolist[index].stats.likes = parseInt(item.statistics.likeCount || -1);
        videolist[index].stats.dislikes = parseInt(item.statistics.dislikeCount || -1);
        videolist[index].stats.pubDate = new Date(item.snippet.publishedAt || new Date());
    });
    return videolist;
}

function setRatios(videolist) {
    videolist = computer.luratio(videolist);
    videolist.forEach(function(el) {
        $(el.element).find('.result-container').html(el.result+'/1');
        luColor(el);
    });
}

function luColor(el) {
    var v_ratio = el.result;
    var v_red = Math.max(0, 255 - Math.floor(v_ratio/1.5));
    var v_green = Math.min(255, Math.floor(v_ratio*4));
    var v_color= "rgb("+v_red+","+v_green+",30)";
    $(el.element).find('.result-container').css('color', v_color);
}

function addRatiosTo(containersel, videosel, rc) {
    var container = $(containersel),
        videos    = container.find(videosel).not('.ocd-checked');

    if (!videos.length) return;
    var videolist = initVideoList(videos);

    var appendtomain    = function(el) { $(el.element).addClass('ocd-checked').append(rc.cloneNode(true)); };
    var appendtolat     = function(el) { $(el.element).addClass('ocd-checked').find('.content-link, ytd-video-meta-block').append(rc.cloneNode(true)); };
    var appendtolatplay = function(el) { $(el.element).addClass('ocd-checked').append(rc.cloneNode(true)); };
    var appendtochannel = function(el) { $(el.element).addClass('ocd-checked').append(rc.cloneNode(true)); };

    var appendtotarget = appendtomain;
    if ($(rc).hasClass('result-lat')) appendtotarget = appendtolat;
    else if ($(rc).hasClass('result-lat-play')) appendtotarget = appendtolatplay;
    else if ($(rc).hasClass('result-channel')) appendtotarget = appendtochannel;

    videolist.forEach(appendtotarget);
    getSetAPI(videolist);
}

function addRatiosToMain(containersel) {
    var rc = rcmain;

    var container = $(containersel);

    if (container.hasClass('ocd-checked')) return;

    var videolist = [{
        element: container,
        url: getParam(window.location.search, 'v'),
        stats: {views: -1, likes: -1, dislikes: -1, pubDate: new Date(0)}
    }];

    var appendtomain = function(el) { $(el.element).addClass('ocd-checked').prepend(rc.cloneNode(true)); }; //old layout
    if (container.is('#info')) {
        rc = rcmainnew;
        appendtomain = function(el) { $(el.element).addClass('ocd-checked').find('#flex').after(rc.cloneNode(true)); }; //new layout
    }
    videolist.forEach(appendtomain);
    getSetAPI(videolist);
}


function listener() { //triggered when document title is changed, so when another page is loaded.
    if (document.title.match('ocd-waiting')) return;

    // OLD LAYOUT //
    if ($('.section-list').length)                    addRatiosTo('.section-list', '.yt-lockup', rcmain);                           // index
    if ($('#watch-related').length)                   addRatiosTo('#watch-related', 'li.video-list-item', rclat);                           // related
    if ($('#channels-browse-content-grid').length)    addRatiosTo('#channels-browse-content-grid', '.yt-lockup', rcchannel);   // channel videos
    if ($('.yt-uix-shelfslider-list').length)         addRatiosTo('.yt-uix-shelfslider-list,#browse-items-primary', '.yt-lockup', rcchannel);          // channel homepage

    if ($('#watch8-sentiment-actions').length)        addRatiosToMain('#watch8-sentiment-actions'); // main video

    // NEW LAYOUT //
    if ($('ytd-browse:visible').length)               addRatiosTo('ytd-browse', 'ytd-grid-video-renderer:visible,ytd-video-renderer:visible', rcmain);   // index
    if ($('#items.ytd-watch-next-secondary-results-renderer:visible').length)
        addRatiosTo('#items.ytd-watch-next-secondary-results-renderer:visible', 'ytd-compact-video-renderer:visible', rclat);      // related
    if ($('.playlist-items:visible').length)          addRatiosTo('.playlist-items:visible', 'ytd-playlist-panel-video-renderer:visible', rclatplay);      // related playlist

    if ($('#info:visible').length)                    addRatiosToMain('#info:visible'); // main video
}

function resetOCD() {
    $('.result-container').remove();
    $('.ocd-checked').removeClass('ocd-checked');
}

!function main() {
    $('body').append('<style type="text/css">  .result-container {margin-top: 5px; display: inline-block; padding: 2px 3px; background-color: rgb(100,100,100); color: white; font-size:11px; border-radius: 3px;} .ocd-spinner { background-image: url(https://loading.io/assets/img/ellipsis.gif); background-repeat: no-repeat; background-size: cover; width:23px; height:13px; background-position-y: -5px; } '
                     + ' .result-main {  } .result-main-new { margin-right: 15px; } .result-lat { display: inline-table; } .result-lat-play { display: inline-table } .result-channel {  } </style>'); // style

    var prevstate = '';

    setInterval(function() {
        var thisstate = history.state;

        if (prevstate != thisstate) {
            console.log('changed');
            resetOCD();
            document.title += ' - ocd-waiting';
            console.log('ocd-waiting');
            prevstate = thisstate;
        }

        if (!document.title.match('ocd-checked')) {
            document.title = document.title.replace('- ocd-waiting', '');
            document.title += ' - ocd-checked';
            console.log('ocd-checked');
            resetOCD();
        }

        listener();
    }, 1000);
}();