HistogramHeatGraph_html5.user.js

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

Per 10-11-2017. Zie de nieuwste versie.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

// ==UserScript==
// @name           HistogramHeatGraph_html5.user.js
// @namespace      sotoba
// @version        0.20171111
// @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, #222 10px);
border: 1px solid #000;
border-top: 0;
float: left;
font-size: 0;
white-space: nowrap;
}
#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 = [
            '126da2', '1271a8', '1275ae', '1279b4', '137dba',
            '1381c0', '1385c6', '1489cc', '148dd2', '1491d8'
        ];
        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);
        }
        $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);//監視終了
    }
})();