Add Syntax Highlighting (this will take a few seconds, probably freezing your browser while it works)
// ==UserScript==
// @name Heat the nicovideo up
// @author noriaki
// @namespace http://blog.fulltext-search.biz/
// @description Visualize comments upsurge for Nicovideo
// @license MIT License
// @version 0.3.0
// @released 2007-09-11 09:00:00
// @updated 2007-12-11 13:00:00
// @compatible Greasemonkey
// @include http://www.nicovideo.jp/watch/*
// ==/UserScript==
/*
* This file is a Greasemonkey user script. To install it, you need
* the Firefox plugin "Greasemonkey" (URL: http://greasemonkey.mozdev.org/)
* After you installed the extension, restart Firefox and revisit
* this script. Now you will see a new menu item "Install User Script"
* in your tools menu.
*
* To uninstall this script, go to your "Tools" menu and select
* "Manage User Scripts", then select this script from the list
* and click uninstall :-)
*
* The MIT License (--> or Public Domain)
* http://www.opensource.org/licenses/mit-license.php
* http://sourceforge.jp/projects/opensource/wiki/licenses%2FMIT_license (Japanese)
*/
(function(){
var COLOR_MAP = [
'#060026', '#0f0082', '#181395', '#214dd6',
'#3b8cd2', '#36b9d3', '#34c5a5', '#41cc27',
'#8fd104', '#bfd70e', '#c8ab0b', '#c38509',
'#c65706', '#c22404', '#c51b20', '#c51b20'
];
var detail = false;
if(detail) {
var WIDTH = 2;
var DIVISION = 82;
} else {
var WIDTH = 3;
var DIVISION = 55;
}
var WIDTH_ = WIDTH;
var VIDEO_LENGTH;
var $ = function(id){ return unsafeWindow.document.getElementById(id); };
var $$ = unsafeWindow.$$;
var Element = unsafeWindow.Element;
if(!document.getElementsByTagName('h1')[0]) return;
Element.scrollTo($$("p.TXT12").first());
function heat_map() {
var output = document.createElement('div');
output.id = 'heat_output';
output.innerHTML = '<p>Loading...</p>';
if(!$('WATCHFOOTER')) return;
$('WATCHFOOTER').parentNode.insertBefore(output, $('WATCHFOOTER'));
var flvplayer = $('flvplayer');
flvplayer.get = function(target) {
return this.GetVariable(target);
};
var video_info = flvplayer.get('o').split('&').inject({}, parseQueryString);
var thread_id = video_info.thread_id;
var vlsec = VIDEO_LENGTH = video_info.l;
var url = video_info.ms;
var download_url = video_info.url;
GM_xmlhttpRequest({
method: 'POST',
headers: {
'User-Agent': 'Mozilla/4.0 (compatible) Greasemonkey (Heat the Nicovideo up)',
'Content-type': 'text/xml'
},
url: url,
data: '<thread res_from="-1000" version="20061206" thread="' + thread_id + '" />',
onload: function(res){ extract(res); },
onerror: function(res){ GM_log(res.status + ':' + res.responseText); }
});
function extract(res) {
var responseXML = (new DOMParser).parseFromString(res.responseText, "application/xml");
var comments = responseXML.getElementsByTagName('chat');
var counts = new Array(DIVISION).fill(0);
if(/^sm(\d+)$/.test(unsafeWindow.video_id)) {
var sm_video_id = RegExp.$1;
} else {
var message = document.createElement('p');
message.id = 'heat_message';
message.innerHTML = 'Sorry, this video is unsupported.'
output.innerHTML = '';
output.appendChild(message);
return;
}
var vlmsec = vlsec.to_i() * 100;
for(var i = 0, len = comments.length; i < len; i++) {
var pmsec = comments[i].getAttribute('vpos');
if(vlmsec > pmsec) {
counts[~~(pmsec / vlmsec * DIVISION)]++;
} else if(vlmsec == pmsec){
counts[DIVISION-1]++;
}
}
var max = counts.max();
var per_msec = vlmsec / DIVISION;
var color_map_size = COLOR_MAP.length - 1;
output.innerHTML = '';
for(var i = 0, len = counts.length; i < len; i++){
var start_msec = per_msec * i;
var end_msec = start_msec + per_msec - 1;
var span = document.createElement('span');
var index = ~~(counts[i] * color_map_size / max);
var color = COLOR_MAP[index];
var comment_info_header = 'コメント数:';
var comment_info_html = ['<span class="heat_level', index, '">',
counts[i], '</span>'].join('');
var comment_info_footer = [
'(', (~~(to_min(start_msec))).z(2), ':',
(~~(to_sec(start_msec) % 60)).z(2), '〜',
(~~(to_min(end_msec))).z(2), ':',
(~~(to_sec(end_msec) % 60)).z(2), ')'].join('');
span.style.color = color;
span.style.backgroundColor = color;
span.title = comment_info_header + counts[i] + comment_info_footer;
span.innerHTML = comment_info_header + comment_info_html + comment_info_footer;
span.setAttribute('class', i);
output.appendChild(span);
}
var message = document.createElement('p');
message.setAttribute('id', 'heat_message');
message.innerHTML = 'Comment Heat Map for nicovideo おまけ機能→';
var heat_comments_info = document.createElement('p');
heat_comments_info.setAttribute('id', 'heat_info');
var info_message = '色の上にマウスを乗せるとコメント数を表示します.';
heat_comments_info.innerHTML = info_message;
heat_comments_info.setAttribute('title', info_message);
var reload_link = document.createElement('a');
reload_link.id = 'heat_reload_link';
reload_link.appendChild(document.createTextNode('再読込み'));
reload_link.title = 'Reload Comment Heat Map'
Element.buttonize(reload_link, function() {
Element.remove(output);
heat_map();
});
var filter_link = document.createElement('a');
filter_link.setAttribute('id', 'heat_filter_link');
filter_link.setAttribute('title', '設定されているフィルター一覧を表示する(ネタバレ注意)');
filter_link.appendChild(document.createTextNode('フィルター'));
Element.buttonize(filter_link, function() {
Element.toggle(filter_list)
});
/* var relational_video = document.createElement('a');
relational_video.setAttribute('id', 'heat_relational_video');
relational_video.setAttribute('title', 'この動画を見た人は,こんな動画も見ています');
relational_video.appendChild(document.createTextNode('関連動画'));
Element.buttonize(relational_video, function() {
Element.remove(relational_video);
});
*/
var download_link = document.createElement('a');
download_link.setAttribute('id', 'heat_download_link');
download_link.setAttribute('title', '動画をダウンロードする');
download_link.appendChild(document.createTextNode('動画ダウンロード'));
Element.buttonize(download_link, function() {});
download_link.setAttribute('href', download_url);
output.appendChild(reload_link);
output.appendChild(heat_comments_info);
if(WIDTH == WIDTH_) {
message.appendChild(download_link);
message.appendChild(filter_link);
// message.appendChild(relational_video);
output.appendChild(message);
};
setSpanWidth();
var filter_list = document.createElement('div');
filter_list.setAttribute('id', 'heat_filter_list');
Element.setStyle(filter_list, {
display: 'none',
top: output.offsetHeight + 10 + 'px',
left: filter_link.offsetLeft + 'px'
});
if(video_info.ng_up) {
var filter_words = video_info.ng_up.split('&');
var filters = ['<h3>フィルター一覧</h3>'];
filters.push('<ul>');
for(var i=0,length=filter_words.length; i<length; i++) {
var filter = filter_words[i].split('=');
filters.push('<li><a href="javascript:void(0);" title="');
filters.push(decodeURIComponent(filter[1]));
filters.push('" onclick="$(\'flvplayer\').SetVariable(\'ChatInput.text\', \'');
filters.push(decodeURIComponent(filter[0]));
filters.push('\'); return false;">');
filters.push(decodeURIComponent(filter[0]));
filters.push('</a></li>');
}
filters.push('</ul>');
filters = filters.join('');
} else {
var filters = '<h3>フィルターは設定されていません</h3>';
}
var close = document.createElement('a');
close.appendChild(document.createTextNode('x'));
close.setAttribute('title', '閉じる');
close.setAttribute('href', 'javascript:void(0);');
Element.addClassName(close, 'heat_close');
close.addEventListener('click', function() {
Element.hide(this.parentNode);
}, false);
filter_list.innerHTML = filters;
filter_list.appendChild(close);
message.appendChild(filter_list);
var max_comment_num = document.createElement('p');
max_comment_num.setAttribute('id', 'heat_max_comment_num');
max_comment_num.innerHTML = max;
var min_comment_num = document.createElement('p');
min_comment_num.setAttribute('id', 'heat_min_comment_num');
min_comment_num.innerHTML = '0';
output.appendChild(max_comment_num);
output.appendChild(min_comment_num);
$('heat_max_comment_num').title = $$('span.heat_level'+color_map_size).first().parentNode.title;
}
function to_hour(msec) {
return(to_min(msec) / 60);
}
function to_min(msec) {
return(to_sec(msec) / 60);
}
function to_sec(msec) {
return(msec / 100);
}
function parseQueryString(hash, pair) {
if ((pair = pair.split('='))[0]) {
var name = decodeURIComponent(pair[0]);
var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
if (hash[name] !== undefined) {
if (hash[name].constructor != Array)
hash[name] = [hash[name]];
if (value) hash[name].push(value);
}
else hash[name] = value;
}
return hash;
}
Element.buttonize = function(elem, func) {
Element.addClassName(elem, 'button');
elem.setAttribute('href', 'javascript:void(0);');
elem.addEventListener('mouseout', function() {
Element.removeClassName(elem, 'click');
}, false);
elem.addEventListener('mousedown', function() {
Element.addClassName(elem, 'click');
}, false);
elem.addEventListener('mouseup', function() {
Element.removeClassName(elem, 'click');
}, false);
elem.addEventListener('click', func, false);
}
unsafeWindow.fitPlayerToWindow = function() {
var seek_width = window.innerWidth - 339 - 77;
WIDTH = seek_width / (DIVISION - 1);
setSpanWidth();
$("flvplayer").setStyle({width: "100%", height: "100%"});
var player_height = $('PAGEBODY').offsetHeight - $('heat_output').offsetHeight - 1 + 'px';
$('flvplayer_container').setStyle({height: player_height});
}
unsafeWindow.toggleMaximizePlayer = function() {
if (unsafeWindow.playerMaximized) {
unsafeWindow.restorePlayer();
$('heat_output').style.paddingLeft = '79px';
WIDTH = WIDTH_;
setSpanWidth();
$('heat_message').show();
} else {
$('heat_message').hide();
$('heat_output').style.paddingLeft = '77px';
unsafeWindow.maximizePlayer();
}
commentsCountArea($('heat_info'), $$('span.0').first());
unsafeWindow.playerMaximized = !unsafeWindow.playerMaximized;
}
}
function commentsCountArea(node, span) {
node.innerHTML = span.innerHTML;
var position_x = -8 + WIDTH / 2 + span.getAttribute('class').to_i() * WIDTH;
node.style.backgroundPosition = position_x + 'px 0px';
node.style.color = span.style.color;
node.style.display = 'block';
}
function setSpanWidth() {
$$('#heat_output > span').each(function(node) {
node.setStyle({width: WIDTH + 'px'});
/*node.addEventListener('mouseover', function(){
commentsCountArea($('heat_info'), node);
}, false);*/
});
}
function wait_ready() {
var vlsec = $('flvplayer').GetVariable('ContentLength');
if(typeof vlsec == 'undifined') return 0;
var interval = vlsec / DIVISION / 10;
if(interval > 1) interval = 1;
return interval;
}
function follow_seek_bar() {
var vlsec = $('flvplayer').GetVariable('ContentLength');
if(typeof vlsec == 'undefined') return;
var percent_video_moving = $('flvplayer').GetVariable('moved_time') / vlsec;
var spans = $$('span.' + ~~(percent_video_moving * DIVISION));
if(spans.size() == 0) return;
commentsCountArea($('heat_info'), spans.first());
}
var PE = unsafeWindow.PeriodicalExecuter;
new PE(function() {
var frequency = wait_ready();
if(frequency > 0) {
this.callback = follow_seek_bar;
this.frequency = frequency;
heat_map();
}
}, 0.5);
Array.prototype.fill = function(v){
for(var i=0,l=this.length;i<l;this[i++]=v);
return this
}
Array.prototype.max = function(){
return Math.max.apply(null,this)
}
Array.prototype.inject = function(memo, iterator) {
for (var i = 0, length = this.length; i < length; i++)
memo = iterator(memo, this[i], i);
return memo;
}
String.prototype.to_i = function(){
return parseInt(this, 10)
}
Number.prototype.z = function(len){
if(Math.pow(10,len) <= this) return this.toString();
var s = '0'.fill(len) + this.toString();
return s.substr(s.length - len);
};
String.prototype.fill = function(len){
var result = '';
for(var i = 0; i < len; i++){
result += this;
}
return result;
};
function UpdateChecker() {};
UpdateChecker.prototype = {
script_name: 'Heat the nicovideo up',
script_url: 'http://blog.fulltext-search.biz/files/heatthenicovideoup.user.js',
current_version: '0.3.0',
more_info_url: 'http://blog.fulltext-search.biz/pages/visualize-comments-upsurge-greasemonkey-script-for-nicovideo',
remote_version: null,
// Render update information in HTML
render_update_info: function() {
var newversion = document.createElement('div');
newversion.setAttribute('id', 'gm_update_alert');
var update_message = document.createElement('p');
update_message.innerHTML = [
'現在お使いのGreasemonkeyスクリプト \'',
this.script_name,
'(var. ', this.current_version, ')',
'\' は新しいバージョン ',
this.remote_version,
' が公開されています.アップデートしますか?'
].join('');
var update_link = document.createElement('a');
update_link.setAttribute('id', 'gm_update_alert_link');
update_link.setAttribute('href', this.script_url);
update_link.addEventListener('click', function() {
var update_alert = document.getElementById('gm_update_alert');
update_alert.parentNode.removeChild(update_alert);
}, false);
update_link.innerHTML =
'[Yes]今すぐアップデートする';
if(this.more_info_url) {
var more_link = document.createElement('a');
more_link.setAttribute('href', this.more_info_url);
more_link.innerHTML = '(詳細情報)';
update_message.appendChild(more_link);
}
var close_link = document.createElement('a');
close_link.setAttribute('href', 'javascript:void(0);');
close_link.addEventListener('click', function() {
GM_setValue('last_check_day', new Date().days_since_start());
var update_alert = document.getElementById('gm_update_alert');
update_alert.parentNode.removeChild(update_alert);
}, false);
close_link.innerHTML = [
'[No]今はアップデートしない(日付が変わるまで有効)'
].join('');
var scroll_link = document.createElement('a');
if(/(.*?)\#/.test(document.location)) {
scroll_link.href = RegExp.$1 + '#gm_update_alert';
} else {
scroll_link.href = document.location + '#gm_update_alert';
}
scroll_link.innerHTML = '(ページ最上部に\'Comment Heat Map for nicovideo\'からのお知らせがあります)';
newversion.appendChild(update_message);
newversion.appendChild(update_link);
newversion.appendChild(close_link);
document.body.appendChild(newversion);
$('WATCHFOOTER').parentNode.insertBefore(scroll_link, $('WATCHFOOTER'));
},
add_update_info_style: function() {
GM_addStyle(<><![CDATA[
/* style(like CSS) for update information */
#gm_update_alert {
padding: 5px 0pt;
background-color: #FFF280;
color: #CC0099;
width: 100%;
position: absolute;
z-index: 99;
top: 0px;
left: 0px;
text-align: center;
font-size: 11px;
font-family: Tahoma;
}
#gm_update_alert p {
margin: 0pt;
}
#gm_update_alert a:link {
color: #333333;
}
#gm_update_alert > a:link {
margin: 0.5em 1em 0pt 1em;
}
#gm_update_alert p + a:link {
font-weight: bold;
}
]]></>);
},
// Check script update remote
check_update: function() {
if(!this.has_need_for_check) return;
var user_script = this;
GM_xmlhttpRequest({
method: 'GET',
url: this.script_url,
onload: function(res) {
user_script.remote_version = user_script.check_version(res.responseText);
if(user_script.remote_version && user_script.remote_version > user_script.current_version) {
user_script.add_update_info_style();
user_script.render_update_info();
} else {
GM_setValue('last_check_day', new Date().days_since_start());
}
},
onerror: function(res) { GM_log(res.status + ':' + res.responseText); }
});
},
// Check the necessity for update: [Boolean]
// return [true] if necessary
has_need_for_check: function() {
var last_check_day = GM_getValue('last_check_day');
var current_day = new Date().days_since_start();
if(typeof last_check_day == 'undefined' || current_day > last_check_day) {
return true;
} else {
return false;
}
},
// Check version in remote script file: [String]
check_version: function(string) {
if(/\/\/\s?@version\s+([\d.]+)/.test(string)) {
return RegExp.$1;
} else {
return null;
}
}
};
Date.prototype.days_since_start = function() {
var DAYS_IN_MONTH = [31,59,90,120,151,181,212,243,273,304,334,365];
return(this.getYear() * 365 + DAYS_IN_MONTH[this.getMonth()] + this.getDate());
};
//instantiate and run
GM_addStyle(<><![CDATA[
#heat_output {
padding: 5px 1em 3px 79px;
font-size: 80%;
border: 1px solid #333;
background: #FFFFFF url('http://blog.fulltext-search.biz/images/gm/thermograph.png') no-repeat scroll 10px 5px;
position: relative;
min-height: 85px;
}
#heat_output > span {
display: block;
height: 1.4em;
float: left;
cursor: default;
overflow: hidden;
}
#heat_output a.button {
margin-left: 1em;
padding: 0pt 0.5em;
text-decoration: none;
border: 2px solid #444;
}
#heat_output a.button:link,
#heat_output a.button:visited {
border-left: 1px solid #999;
border-top: 1px solid #999;
}
#heat_output a.button.click {
border: 2px solid #444;
border-right: 1px solid #999;
border-bottom: 1px solid #999;
}
#heat_output a.heat_close {
background-color: #f88;
border: 1px solid #fff;
color: #fff;
font-weight: bold;
line-height: 1;
padding: 0.18em 0.25em;
position: absolute;
right: 4px;
text-decoration: none;
top: 4px;
}
#heat_info {
clear: left;
margin: 2px 0pt 5px;
padding-top: 18px;
font-weight: bold;
background: #fff url('http://blog.fulltext-search.biz/images/gm/up_silver.png') no-repeat;
height: 2.8em;
}
#heat_info span {
color: #333;
margin: 0pt 0.2em;
}
#heat_info span.heat_level0 { font-size: 80%; }
#heat_info span.heat_level1 { font-size: 85%; }
#heat_info span.heat_level2 { font-size: 90%; }
#heat_info span.heat_level3 { font-size: 95%; }
#heat_info span.heat_level4 { font-size: 100%; }
#heat_info span.heat_level5 { font-size: 105%; }
#heat_info span.heat_level6 { font-size: 110%; }
#heat_info span.heat_level7 { font-size: 115%; }
#heat_info span.heat_level8 { font-size: 120%; }
#heat_info span.heat_level9 { font-size: 130%; }
#heat_info span.heat_level10 { font-size: 140%; }
#heat_info span.heat_level11 { font-size: 150%; }
#heat_info span.heat_level12 { font-size: 170%; }
#heat_info span.heat_level13 { font-size: 200%; }
#heat_info span.heat_level14 { font-size: 230%; }
#heat_info span.heat_level15 { font-size: 280%; }
#heat_max_comment_num, #heat_min_comment_num {
font-size: 10px;
position: absolute;
padding-left: 35px;
left: 0px;
}
#heat_max_comment_num {
top: 5px;
}
#heat_min_comment_num {
top: 77px;
}
#heat_filter_list {
position: absolute;
width: 300px;
border: #3a3 1px solid;
z-index: 4;
background-color: #eee;
padding: 0.5em 10px;
}
#heat_filter_list ul {
margin: 5px 0;
padding: 0;
font-family: Tahoma, Arial, Helvetica, sans-serif;
font-size: 13px;
line-height: 1.5;
}
#heat_filter_list ul li {
margin: 0 5px 3px 0;
padding: 0;
display: inline;
font-size: 100%;
list-style: none;
}
#heat_filter_list ul li a {
text-decoration: none;
border: #aaa 1px solid;
padding: 2px;
background-color: #fff;
}
#heat_filter_list ul li a:hover {
background-color: #333;
color: #fff;
}
]]></>);
var user_script = new UpdateChecker();
user_script.check_update();
})();