- // ==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(/"|<|</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);//監視終了
- }
- })();