fork(2) download
  1. // ==UserScript==
  2. // @name Ban成績がRPG風に見やすくなるスクリプト
  3. // @namespace http://t...content-available-to-author-only...y.net/
  4. // @version 0.1
  5. // @description 規約違反はBanしよう
  6. // @author 名無し216
  7. // @match https://w...content-available-to-author-only...e.com/reporthistory
  8. // @grant none
  9. // ==/UserScript==
  10. // ライセンスはWTFPL(何でもOK)だから自由に使ってください
  11.  
  12. (function () {
  13. // for debug
  14. const pp = function(obj) {
  15. // hoge = obj;
  16. console.log(Object.prototype.toString.apply(obj))
  17. console.log(JSON.stringify(obj, null, 2))
  18. }
  19.  
  20. // 報告履歴の背景色
  21. const colours = {
  22. 逃亡: 'cyan', // 投稿者が削除した時
  23. 制限: 'yellow', // 制限された時
  24. 削除: 'red', // 削除された時
  25. 生存: 'white' // 生き延びてる時
  26. }
  27. const data = window.ytInitialData.contents.twoColumnBrowseResultsRenderer.tabs[0].tabRenderer.content.sectionListRenderer.contents[1].reportHistorySectionRenderer.reportHistorySectionRenderers;
  28. // 計算結果を表示する要素の親
  29. const parent = document.getElementById('container');
  30. // スコアボードはドラッグで移動可能なdiv要素
  31. const scoreBoard = getScoreBoard();
  32. // 戦績
  33. const record = {total: 0, hetare: 0, limited: 0, deleted: 0, alive: 0 };
  34. // 動的に履歴が読み込まれたときの処理
  35. const observer = new MutationObserver((mutations) => {
  36. mutations.forEach((mutation) => {
  37. mutation.addedNodes.forEach((element) => {
  38. element.getNodes("items").forEach((node) => {
  39. calculateBanScore(node, record);
  40. drawBanScoreTable(scoreBoard, record);
  41. setColour(node);
  42. });
  43. });
  44. });
  45. })
  46. // 報告履歴の背景を状態によって色付け
  47. function setColour(elm){
  48. elm.setAttribute('style', `background: ${ colours[getState(elm)]};`);
  49. }
  50. // 要素から報告後の状態を取得
  51. function getState(elm){
  52. const _state = elm.getElementsByClassName("report-state")[0];
  53. if(!_state){
  54. return '逃亡';
  55. }
  56. switch(_state.textContent){
  57. case '動画は制限されています。':
  58. return '制限';
  59. case '動画が削除されました。':
  60. return '削除';
  61. case '動画は現在アクティブです。':
  62. return '生存';
  63. }
  64. }
  65. // Ban成績を計算
  66. function calculateBanScore(elm, record){
  67. let state = getState(elm);
  68. ++record.total;
  69. switch(state){
  70. case '逃亡':
  71. ++record.hetare;
  72. break;
  73. case '制限':
  74. ++record.limited;
  75. break;
  76. case '削除':
  77. ++record.deleted;
  78. break;
  79. case '生存':
  80. ++record.alive;
  81. break;
  82. }
  83. }
  84. // スコアボードの作成
  85. function getScoreBoard(){
  86. const scoreBoard = document.createElement('div');
  87. scoreBoard.setAttribute('id', 'score-board');
  88. scoreBoard.setAttribute('style', 'font-size: 2em; opacity: 0.9 ; display: inline-block; color: white; line-height: 100%; position: absolute; left: 50px; top: 50px; width: 10em; height: 16em; background-color: black; cursor: move;');
  89. scoreBoard.innerHTML = "計算中……"
  90.  
  91. let isMoving = false;
  92. let XBeforeDrag = 0;
  93. let YBeforeDrag = 0;
  94. // ドラッグ始め
  95. window.onmousedown = function(e) {
  96. isMoving = true;
  97. XBeforeDrag = e.clientX - parseInt(document.getElementById('score-board').style.left);
  98. YBeforeDrag = e.clientY - parseInt(document.getElementById('score-board').style.top);
  99. }
  100. // ドラッグ終わり
  101. window.onmouseup = function(e) {
  102. isMoving = false;
  103. }
  104. // ドラッグ中
  105. window.onmousemove = function(e) {
  106. if(isMoving) {
  107. document.getElementById('score-board').style.left = `${e.clientX - XBeforeDrag}px`;
  108. document.getElementById('score-board').style.top = `${e.clientY - YBeforeDrag}px`;
  109. }
  110. }
  111. return scoreBoard;
  112. }
  113. // ステータスの表示
  114. function drawBanScoreTable(elm, record){
  115. elm.innerHTML = `<table width="97%" style="text-align: right;"><tr><td colspan="2" style="text-align: center;"><div style="margin: 10px 0 1em 0;">つよさ</div></td></tr><tr><td>レベル:</td><td>${getLevel(record)}</td></tr><tr><td>ごうけい:</td><td>${record.total}</td></tr><tr><td>さくじょ:</td><td>${record.deleted}</td></tr><tr><td>せいげん:</td><td>${record.limited}</td></tr><tr><td>とうぼう:</td><td>${record.hetare}</td></tr><tr><td>せいぞん:</td><td>${record.alive}</td></tr><tr><td>だりつ:</td><td>${getBattingAverage(record).toFixed(1)}%</td></tr><tr><td>削除率:</td><td>${getRemovingAverage(record).toFixed(1)}%</td></tr><tr><td>経験値:</td><td>${getExp(record)}</td></tr><tr><td>次のレベ <br>ルまで:</td><td>${getRestExp(record)}</td></tr></table>`;
  116. }
  117. function expTable(level){
  118. return level * (level - 1) / 2;
  119. }
  120. function getLevel(record){
  121. return Math.floor((Math.sqrt(8 * getExp(record) + 1) + 1) / 2);
  122. }
  123. function getRestExp(record){
  124. return expTable(getLevel(record) + 1) - getExp(record);
  125. }
  126. function getExp(record){
  127. return record.deleted*3 + record.hetare + record.limited;
  128. }
  129. function getRemovingAverage(record){
  130. return 100*record.deleted/record.total;
  131. }
  132. function getBattingAverage(record){
  133. return 100*(1 - record.alive/record.total);
  134. }
  135. // スコアボードを追加
  136. parent.insertBefore(scoreBoard, parent.firstChild);
  137. // 報告結果がリストされるノード(の親?)
  138. const target = document.getElementById('contents');
  139. // 最初に表示される履歴を処理
  140. const nodes = document.getElementsByTagName('ytd-video-report-renderer');
  141. for(let i = 0; i < nodes.length; i++){
  142. let node = nodes[i];
  143. calculateBanScore(node, record);
  144. drawBanScoreTable(scoreBoard, record);
  145. setColour(node);
  146. }
  147. // 報告履歴の監視開始
  148. observer.observe(target, {childList: true});
  149. })();
  150.  
Runtime error #stdin #stdout #stderr 0.02s 9488KB
stdin
Standard input is empty
stdout
Standard output is empty
stderr
prog.js:48:34 SyntaxError: illegal character:
prog.js:48:34         elm.setAttribute('style', `background: ${ colours[getState(elm)]};`);
prog.js:48:34 ..................................^