HistogramHeatGraph_html5.user.js

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

Fra 07.11.2017. Se den seneste versjonen.

  1. // ==UserScript==
  2. // @name HistogramHeatGraph_html5.user.js
  3. // @namespace sotoba
  4. // @version 0.20171108
  5. // @description ニコニコ動画でコメントの盛り上がりをグラフで表示(html5版)
  6. // @match http://www.nicovideo.jp/watch/*
  7. // @include http://www.nicovideo.jp/watch/*
  8. // @require http://code.jquery.com/jquery-latest.min.js
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. (function () {
  13.  
  14. const MINIMUMBARNUM=50;
  15. const DEFAULTINTERBAL=10;
  16. const MAXCOMMENTNUM=30;
  17. const GRAPHHEIGHT = 30;
  18. function setStyle() {/*
  19. #comment-graph {
  20. background: repeating-linear-gradient(to top, #000, #222 10px);
  21. border: 1px solid #000;
  22. border-top: 0;
  23. float: left;
  24. font-size: 0;
  25. white-space: nowrap;
  26. }
  27. #comment-list {
  28. background: #000;
  29. color: #fff;
  30. font-size: 12px;
  31. line-height: 1.25;
  32. padding: 4px 4px 0;
  33. pointer-events: none;
  34. position: absolute;
  35. z-index: 9999;
  36. }
  37. #comment-list:empty {
  38. display: none;
  39. }
  40. */}
  41. const style = document.createElement('style');
  42. const styleText = setStyle.toString().match(/\/\*([^]*)\*\//)[1];
  43. style.appendChild(document.createTextNode(styleText));
  44. document.body.appendChild(style);
  45.  
  46. var ControllerBox=$('.ControllerBoxContainer').eq(0);
  47. var PlayerContainer=$('.PlayerContainer').eq(0);
  48.  
  49. PlayerContainer.append('<div id=comment-graph></div>');
  50. $('.MainContainer').eq(0).append('<div id=comment-list></div>');
  51. const $commentgraph = $('#comment-graph');
  52.  
  53. const $list = $('#comment-list');
  54. var ApiJsonData=JSON.parse(document.getElementById('js-initial-watch-data').getAttribute('data-api-data'));
  55.  
  56. var thread_id;
  57. var video_id;
  58. var user_id;
  59. if(ApiJsonData.video.dmcInfo !== null){
  60. thread_id=ApiJsonData.video.dmcInfo.thread.thread_id;
  61. video_id=ApiJsonData.video.dmcInfo.video.video_id;
  62. user_id=ApiJsonData.video.dmcInfo.user.user_id;
  63. }else{
  64. thread_id=ApiJsonData.thread.ids.default;
  65. video_id=ApiJsonData.video.id;
  66. user_id=ApiJsonData.viewer.id;
  67. }
  68.  
  69. if(video_id.startsWith('sm')||video_id.startsWith('nm')){
  70. $.ajax({
  71. url:'http://nmsg.nicovideo.jp/api/thread?thread='+thread_id+'&version=20061206&res_from=-1000&scores=1',
  72. type:'GET',
  73. dataType:'xml',
  74. timeout:3000,
  75. error:function() {
  76. console.log("Ajax:failed");
  77. },
  78. success:function(xml){
  79. drowgraph(xml,ApiJsonData);
  80. }
  81. });
  82. }else{
  83. $.ajax({
  84. url:'http://flapi.nicovideo.jp/api/getthreadkey?thread='+thread_id,
  85. type:'GET',
  86. timeout:3000,
  87. error:function() {
  88. console.log("Ajax:failed");
  89. },
  90. success:function(response){
  91. $.ajax({
  92. url:'http://nmsg.nicovideo.jp/api/thread?thread='+thread_id+'&version=20061206&res_from=-1000&scores=1&user='+user_id+'&'+response,
  93. type:'GET',
  94. dataType:'xml',
  95. timeout:3000,
  96. error:function() {
  97. console.log("Ajax:failed...");
  98. },
  99. success:function(xml){
  100. drowgraph(xml,ApiJsonData);
  101. }
  102. });
  103. }
  104. });
  105. }
  106.  
  107. function drowgraph(commentData,ApiJsonData){
  108. const playerWidth =parseFloat($("#CommentRenderer").children('canvas').eq(0).css("width"));
  109. var videoTotalTime = ApiJsonData.video.dmcInfo !== null ? ApiJsonData.video.dmcInfo.video.length_seconds : ApiJsonData.video.duration;
  110. var barTimeInterval;
  111. var barIndexNum;
  112. if(videoTotalTime > MINIMUMBARNUM*DEFAULTINTERBAL){
  113. barTimeInterval=DEFAULTINTERBAL;
  114. barIndexNum=Math.ceil(videoTotalTime / barTimeInterval);
  115. }else if(videoTotalTime>MINIMUMBARNUM){
  116. barIndexNum=MINIMUMBARNUM;
  117. barTimeInterval=Math.round(videoTotalTime/MINIMUMBARNUM);
  118. }else{
  119. barIndexNum=Math.floor(videoTotalTime);
  120. barTimeInterval=1;
  121. }
  122. $('#comment-graph').css( "width" , playerWidth );
  123. const barColors = [
  124. '126da2', '1271a8', '1275ae', '1279b4', '137dba',
  125. '1381c0', '1385c6', '1489cc', '148dd2', '1491d8'
  126. ];
  127. var listCounts = (new Array(barIndexNum)).fill(0);
  128. var listMessages = (new Array(barIndexNum)).fill("");
  129. var listTimes = (new Array(barIndexNum)).fill("");
  130. var lastBarTimeIntervalGap = Math.floor(videoTotalTime- (barIndexNum * barTimeInterval));
  131. var barWidth = playerWidth / barIndexNum;
  132. var barTimePoint = 0;
  133.  
  134. $(commentData).find('chat').each(function(index){
  135. var vpos = $(this).attr('vpos')/100;
  136. var section=Math.floor(vpos/barTimeInterval);
  137. listCounts[section]++;
  138. if(listCounts[section]<=MAXCOMMENTNUM){
  139. var comment=$(this).text().replace(/"|<|&lt;/g, ' ').replace(/\n/g, '<br>');
  140. listMessages[section]+=comment+'<br>';
  141. }
  142. });
  143. var startMin=0;
  144. var startSec=0;
  145. var min=0;
  146. var sec=0;
  147. for (var i = 0; i < barIndexNum-1; i++) {
  148. startMin=min;
  149. startSec=sec;
  150. sec+=barTimeInterval;
  151. if(59 < sec){
  152. min+=1;
  153. sec-=60;
  154. }
  155. listTimes[i] += `${("0"+startMin).slice(-2)}:${("0"+startSec).slice(-2)}-${("0"+min).slice(-2)}:${("0"+sec).slice(-2)}`;
  156. }
  157. startMin=min;
  158. startSec=sec;
  159. sec+=(barTimeInterval+lastBarTimeIntervalGap);
  160. if(59 < sec){
  161. min+=1;
  162. sec-=60;
  163. }
  164. listTimes[barIndexNum-1] += `${("0"+startMin).slice(-2)}:${("0"+startSec).slice(-2)}-${("0"+min).slice(-2)}:${("0"+sec).slice(-2)}`;
  165.  
  166. // TODO なぜかbarIndexNum以上の配列ができる
  167. listCounts=listCounts.slice(0, barIndexNum);
  168. var listCountMax = Math.max.apply(null,listCounts);
  169. const barColorRatio = (barColors.length - 1) / listCountMax;
  170.  
  171.  
  172. $commentgraph.empty();
  173. $commentgraph.height(GRAPHHEIGHT);
  174. var barColor;
  175. var barBackground;
  176. for (i = 0; i <= barIndexNum; i++) {
  177. barColor = barColors[Math.floor(listCounts[i] * barColorRatio)];
  178. barBackground = `linear-gradient(to top, #${barColor}, #${barColor} ` +
  179. `${listCounts[i]}px, transparent ${listCounts[i]}px, transparent)`;
  180. var barText = listCounts[i] ?
  181. `${listMessages[i]}<br><br>${listTimes[i]} コメ ${listCounts[i]}` : '';
  182. $('<div>')
  183. .css('background-image', barBackground)
  184. .css('float','left')
  185. .data('text', barText)
  186. .height(GRAPHHEIGHT)
  187. .width(barWidth)
  188. .appendTo($commentgraph);
  189. }
  190. $commentgraph.children().on({
  191. 'mouseenter': function(val) {
  192. $list
  193. .css({
  194. 'left': $(this).offset().left,
  195. 'top': $commentgraph.offset().top - $list.height() - 10
  196. })
  197. .html($(this).data('text'));
  198. },
  199. 'mousemove': function(val) {
  200. $list.offset({
  201. 'left': $(this).offset().left,
  202. 'top': $commentgraph.offset().top - $list.height() - 10
  203. });
  204. },
  205. 'mouseleave': function() {
  206. $list.empty();
  207. }
  208. });
  209.  
  210. }
  211. })();