HistogramHeatGraph_html5.user.js

ニコニコ動画でコメントの盛り上がりをグラフで表示(html5版)

Versione datata 11/11/2017. Vedi la nuova versione l'ultima versione.

Dovrai installare un'estensione come Tampermonkey, Greasemonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Violentmonkey per installare questo script.

Dovrai installare un'estensione come Tampermonkey o Userscripts per installare questo script.

Dovrai installare un'estensione come ad esempio Tampermonkey per installare questo script.

Dovrai installare un gestore di script utente per installare questo script.

(Ho già un gestore di script utente, lasciamelo installare!)

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione come ad esempio Stylus per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

Dovrai installare un'estensione per la gestione degli stili utente per installare questo stile.

(Ho già un gestore di stile utente, lasciamelo installare!)

// ==UserScript==
// @name           HistogramHeatGraph_html5.user.js
// @namespace      sotoba
// @version        0.20171111.1
// @description    ニコニコ動画でコメントの盛り上がりをグラフで表示(html5版)
// @match          http://www.nicovideo.jp/watch/*
// @include        http://www.nicovideo.jp/watch/*
// @require        http://code.jquery.com/jquery-latest.min.js
// @grant          none
// ==/UserScript==

(function () {

    const MINIMUMBARNUM=50;
    const DEFAULTINTERBAL=10;
    const MAXCOMMENTNUM=30;
    const  GRAPHHEIGHT = 30;
    const styleString = `
#comment-graph {
background: repeating-linear-gradient(to top, #000, #111 5px);
border: 1px solid #000;
border-top: 0;
float: left;
font-size: 0;
white-space: nowrap;
}
#comment-graph :hover{
-webkit-filter: hue-rotate(180deg);
filter: hue-rotate(180deg);
}
#comment-list {
background: #000;
color: #fff;
font-size: 12px;
line-height: 1.25;
padding: 4px 4px 0;
pointer-events: none;
position: absolute;
z-index: 9999;
}
#comment-list:empty {
display: none;
}
`;
    const style = document.createElement('style');
    style.appendChild(document.createTextNode(styleString));
    document.body.appendChild(style);

    $('.PlayerContainer').eq(0).append('<div id=comment-graph></div>');
    $('.MainContainer').eq(0).append('<div id=comment-list></div>');

    const $commentgraph = $('#comment-graph');
    const $commentlist = $('#comment-list');

    var ApiJsonData=JSON.parse(document.getElementById('js-initial-watch-data').getAttribute('data-api-data'));

    var thread_id;
    var video_id;
    var user_id;
    if(ApiJsonData.video.dmcInfo !== null){
        thread_id=ApiJsonData.video.dmcInfo.thread.thread_id;
        video_id=ApiJsonData.video.dmcInfo.video.video_id;
        user_id=ApiJsonData.video.dmcInfo.user.user_id;
    }else{
        thread_id=ApiJsonData.thread.ids.default;
        video_id=ApiJsonData.video.id;
        user_id=ApiJsonData.viewer.id;
    }

    if(video_id.startsWith('sm')||video_id.startsWith('nm')){
        $.ajax({
            url:'http://nmsg.nicovideo.jp/api/thread?thread='+thread_id+'&version=20061206&res_from=-1000&scores=1',
            type:'GET',
            dataType:'xml',
            timeout:3000,
            error:function() {
                console.log("Ajax:failed");
            },
            success:function(xml){
                drowgraph(xml,ApiJsonData);
            }
        });
    }else{
        $.ajax({
            url:'http://flapi.nicovideo.jp/api/getthreadkey?thread='+thread_id,
            type:'GET',
            timeout:3000,
            error:function() {
                console.log("Ajax:failed");
            },
            success:function(response){
                $.ajax({
                    url:'http://nmsg.nicovideo.jp/api/thread?thread='+thread_id+'&version=20061206&res_from=-1000&scores=1&user='+user_id+'&'+response,
                    type:'GET',
                    dataType:'xml',
                    timeout:3000,
                    error:function() {
                        console.log("Ajax:failed...");
                    },
                    success:function(xml){
                        drowgraph(xml,ApiJsonData);
                    }
                });
            }
        });
    }

    function  drowgraph(commentData,ApiJsonData){
        var $canvas=$("#CommentRenderer").children('canvas').eq(0);
        var playerWidth =parseFloat($canvas.css("width"));
        var videoTotalTime = ApiJsonData.video.dmcInfo !== null ?  ApiJsonData.video.dmcInfo.video.length_seconds : ApiJsonData.video.duration;
        var barTimeInterval;
        var barIndexNum;
        if(videoTotalTime > MINIMUMBARNUM*DEFAULTINTERBAL){
            barTimeInterval=DEFAULTINTERBAL;
            barIndexNum=Math.ceil(videoTotalTime / barTimeInterval);
        }else if(videoTotalTime>MINIMUMBARNUM){
            barIndexNum=MINIMUMBARNUM;
            barTimeInterval=Math.round(videoTotalTime/MINIMUMBARNUM);
        }else{
            barIndexNum=Math.floor(videoTotalTime);
            barTimeInterval=1;
        }
        $('#comment-graph').width( playerWidth );
        const barColors = [
            '003165',  '00458f',  '0058b5','005fc4', '006adb',
            '0072ec', '007cff', '55a7ff','3d9bff'
        ];
        var listCounts = (new Array(barIndexNum)).fill(0);
        var listMessages = (new Array(barIndexNum)).fill("");
        var listTimes = (new Array(barIndexNum)).fill("");
        var lastBarTimeIntervalGap = Math.floor(videoTotalTime- (barIndexNum * barTimeInterval));
        var barWidth = playerWidth / barIndexNum;
        var barTimePoint = 0;

        $(commentData).find('chat').each(function(index){
            var vpos = $(this).attr('vpos')/100;
            var section=Math.floor(vpos/barTimeInterval);
            listCounts[section]++;
            if(listCounts[section]<=MAXCOMMENTNUM){
                var comment=$(this).text().replace(/"|<|&lt;/g, ' ').replace(/\n/g, '<br>');
                listMessages[section]+=comment+'<br>';
            }
        });
        var startMin=0;
        var startSec=0;
        var min=0;
        var sec=0;
        for (var i = 0; i < barIndexNum-1; i++) {
            startMin=min;
            startSec=sec;
            sec+=barTimeInterval;
            if(59 < sec){
                min+=1;
                sec-=60;
            }
            listTimes[i] += `${("0"+startMin).slice(-2)}:${("0"+startSec).slice(-2)}-${("0"+min).slice(-2)}:${("0"+sec).slice(-2)}`;
        }
        startMin=min;
        startSec=sec;
        sec+=(barTimeInterval+lastBarTimeIntervalGap);
        if(59 < sec){
            min+=1;
            sec-=60;
        }
        listTimes[barIndexNum-1] += `${("0"+startMin).slice(-2)}:${("0"+startSec).slice(-2)}-${("0"+min).slice(-2)}:${("0"+sec).slice(-2)}`;

        // TODO なぜかbarIndexNum以上の配列ができる
        listCounts=listCounts.slice(0, barIndexNum);
        var listCountMax = Math.max.apply(null,listCounts);
        const barColorRatio = (barColors.length - 1) / listCountMax;


        $commentgraph.empty();
        $commentgraph.height(GRAPHHEIGHT);
        var barColor;
        var barBackground;
        for (i = 0; i <= barIndexNum; i++) {
            barColor = barColors[Math.floor(listCounts[i] * barColorRatio)];
            barBackground = `linear-gradient(to top, #${barColor}, #${barColor} ` +
                `${listCounts[i]}px, transparent ${listCounts[i]}px, transparent)`;
            var barText = listCounts[i] ?
                `${listMessages[i]}<br><br>${listTimes[i]} コメ ${listCounts[i]}` : '';
            $('<div>')
                .css('background-image', barBackground)
                .css('float','left')
                .data('text', barText)
                .height(GRAPHHEIGHT)
                .width(barWidth)
                .addClass("commentbar")
                .appendTo($commentgraph);
        }
        function mouseOverFunc() {
            $commentlist.css({
                'left': $(this).offset().left,
                'top': $commentgraph.offset().top - $commentlist.height() - 10
            })
                .html($(this).data('text'));
        }
        function mouseOutFunc() {
            $commentlist.empty();
        }

        $commentgraph.children().on({
            'mouseenter': function(val) {
                $commentlist.css({
                    'left': $(this).offset().left,
                    'top': $commentgraph.offset().top - $commentlist.height() - 10
                })
                    .html($(this).data('text'));
            },
            'mousemove': function(val) {
                $commentlist.offset({
                    'left': $(this).offset().left,
                    'top': $commentgraph.offset().top - $commentlist.height() - 10
                });
            },
            'mouseleave': function() {
                $commentlist.empty();
            }
        });

        /* 1 Dom Style Watcher本体 監視する側*/
        var domStyleWatcher = {
            Start: function(tgt, styleobj){
                function eventHappen(data1, data2){
                    var throwval = tgt.css(styleobj);
                    tgt.trigger('domStyleChange', [throwval]);
                }
                var tge = tgt[0];
                var filter = ['style'];
                var options = {
                    attributes: true,
                    attributeFilter: filter
                };
                var mutOb = new MutationObserver(eventHappen);
                mutOb.observe(tge, options);
                return mutOb;
            },
            Stop: function(mo){
                mo.disconnect();
            }
        };
        function catchEvent(event, value){
            playerWidth=parseFloat(value);
            $('#comment-graph').width(playerWidth);
            $('.commentbar').width(playerWidth / barIndexNum);
            console.log(event);
            console.log(value);
        }
        var target = $canvas;
        var styleobj = 'width';
        target.on('domStyleChange', catchEvent);//イベントを登録
        var dsw = domStyleWatcher.Start(target, styleobj);//監視開始
        //domStyleWatcher.Stop(dsw);//監視終了
    }
})();