Skip to content

Instantly share code, notes, and snippets.

@ishitsuka
Last active November 2, 2017 18:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ishitsuka/10175564 to your computer and use it in GitHub Desktop.
Save ishitsuka/10175564 to your computer and use it in GitHub Desktop.
Visualize comments upsurge for Nicovideo
// ==UserScript==
// @name HistogramHeatGraph.user.js
// @namespace https://gist.github.com/ishitsuka/10175564
// @version 0.20160204
// @description ニコニコ動画でコメントの盛り上がりをグラフで表示
// @match http://www.nicovideo.jp/watch/*
// @include http://www.nicovideo.jp/watch/*
// @grant none
// ==/UserScript==
/**
* Firefoxで動画上のコメントリストを半透明で表示できない。
* Firefoxで最後の棒がまれにずれる。
* 動画総時間がちょうど1分などの場合に最後の棒が表示されない。
* いくつか棒の上1pxがにじむ。
* 一部の動画で棒の下1pxが見えない。
* 関数setContentに遅延処理がないと棒がずれる。
* グラフを再表示するたび表示に要する時間が倍増する。
* 横スクロールバーがまれに表示される。
* 提供有無確認が不正確。
* Watch.jsのAPI仕様が謎。
* Flexboxはコンテンツなしだと効かない。
*/
(function() {
function setStyle() {/*
#playerContainer {
text-align: left;
}
#playerTabWrapper + div {
background: repeating-linear-gradient(to top, #000, #222 10px);
border: 1px solid #000;
border-top: 0;
float: left;
font-size: 0;
white-space: nowrap;
width: 670px;
}
#playerTabWrapper + div div {
display: inline-block;
}
#playerTabWrapper + div div:hover {
background: rgba(255, 255, 255, .1);
-webkit-filter: hue-rotate(180deg);
filter: hue-rotate(180deg);
}
#playerContainer > a {
cursor: pointer;
margin-left: 10px;
text-shadow: rgba(0, 0, 0, .2) 0 1px;
}
#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;
}
.size_normal #playerTabWrapper + div {
transform: scaleX(1.336);
transform-origin: 0;
}
.size_normal #playerContainer > a {
margin-left: 236px;
}
.size_small #playerTabWrapper + div,
.size_small #playerContainer > a,
#comment-list:empty {
display: none;
}
*/}
const style = document.createElement('style');
const styleText = setStyle.toString().match(/\/\*([^]*)\*\//)[1];
style.appendChild(document.createTextNode(styleText));
document.body.appendChild(style);
function setScript() {
function setElement() {
$('#playerContainer')
.append('<div>')
.append('<a>');
$('<div>')
.attr('id', 'comment-list')
.appendTo('body');
}
function setContent(barTimeInterval) {
// constだとFirefoxでエラー
var videoTotalTime = $('#external_nicoplayer')[0].ext_getTotalTime();
const barIndex = Math.ceil(videoTotalTime / barTimeInterval);
const listMessages = [];
const listCounts = [];
const listTimes = [];
const lastBarTimeIntervalGap = barTimeInterval - Math.floor(videoTotalTime % barTimeInterval);
var barTimePoint = 0;
var comments = require('watchapp/init/PlayerInitializer').rightSidePanelViewController;
comments = comments.getPlayerPanelTabsView()._commentPanelView.getComments().getData();
comments.some(val => {
if (val.vpos / 1000 > videoTotalTime + 1) {
videoTotalTime += 10;
return true;
}
});
for (var i = 0; i < barIndex; i++) {
listMessages[i] = [];
listCounts[i] = 0;
comments.forEach(val => {
var thisTimePoint = val.vpos / 1000;
if (barTimePoint <= thisTimePoint && thisTimePoint < barTimeInterval + barTimePoint) {
listMessages[i].push(val);
listCounts[i]++;
}
});
listMessages[i]
.sort((a, b) => a.vpos - b.vpos)
.forEach((val, j) => {
listMessages[i][j] = val.message.replace(/"|<|&lt;/g, ' ').replace(/\n/g, '<br>');
});
listMessages[i] = listMessages[i].join('<br>');
var min = Math.floor(barTimePoint / 60);
var sec = barTimePoint - min * 60;
if (sec < 10) {
sec = `0${sec}`;
}
listTimes[i] = `${min}:${sec}-`;
if (i > barIndex - 2) {
barTimePoint -= lastBarTimeIntervalGap;
}
min = Math.floor((barTimeInterval + barTimePoint) / 60);
sec = barTimeInterval + barTimePoint - min * 60;
if (sec < 10) {
sec = `0${sec}`;
}
listTimes[i] += `${min}:${sec}`;
barTimePoint += barTimeInterval;
}
const listCountMax = Math.max(...listCounts);
const graphHeight = listCountMax > 10 ? listCountMax : 10;
const playerWidth = 670;
const barColors = [
'126da2', '1271a8', '1275ae', '1279b4', '137dba',
'1381c0', '1385c6', '1489cc', '148dd2', '1491d8'
];
const barColorRatio = (barColors.length - 1) / listCountMax;
const lastBarWidthRatio = videoTotalTime % barTimeInterval / barTimeInterval;
const $graph = $('#playerTabWrapper').next();
const $list = $('#comment-list');
var barWidth = playerWidth / (lastBarWidthRatio + barIndex - 1);
$('#playerContainerWrapper').css('padding-bottom', graphHeight + 11);
$('.miniBannerAdCloseButton').trigger('click');
$graph.empty();
for (i = 0; i < barIndex; i++) {
var barColor = barColors[Math.floor(listCounts[i] * barColorRatio)];
var 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]}` : '';
if (i > barIndex - 2) {
barWidth *= lastBarWidthRatio;
}
$('<div>')
.css('background-image', barBackground)
.data('text', barText)
.height(graphHeight)
.width(barWidth)
.appendTo($graph);
}
$graph.children().on({
'mouseenter': function(val) {
$list
.css({
'left': val.pageX,
'top': $graph.offset().top - $list.height() - 10
})
.html($(this).data('text'));
},
'mousemove': function(val) {
$list.offset({
'left': val.pageX,
'top': $graph.offset().top - $list.height() - 10
});
},
'mouseleave': function() {
$list.empty();
}
});
const $lastBar = $graph.children().eq(-1);
const foo = $graph.offset().left - $lastBar.offset().left;
const lastBarWidth = $('#playerNicoplayer').width() < 898 ? foo + 671 : (foo + 897) * 672 / 898;
$lastBar.width(lastBarWidth > 1 ? lastBarWidth : 1);
$graph.next()
.on('click', function(val) {
setContent(val.ctrlKey ? 60 : 10);
})
.text(`コメ ${comments.length}`);
navigator.userAgent.match(/Chrome/) && $list.css('background', 'rgba(0, 0, 0, .5)');
}
const npc = require('watchapp/model/player/NicoPlayerConnector');
require('advice').after(npc, 'onCommentListInitialized', function() {
!$('#comment-list')[0] && setElement();
setTimeout(setContent, 1000, 10);
});
}
setTimeout(function() {
const script = document.createElement('script');
script.appendChild(document.createTextNode('(' + setScript + ')()'));
document.body.appendChild(script);
}, 100);
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment