hololyzer 排序工具

让 hololyzer 的超级留言清单支持按姓名排序

目前为 2021-12-13 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name hololyzer Sort Tool
  3. // @name:zh hololyzer 排序工具
  4. // @name:zh-TW hololyzer 排序工具
  5. // @name:zh-CN hololyzer 排序工具
  6. // @namespace https://github.com/kevin823lin
  7. // @version 0.2
  8. // @description Add support for sort hololyzer's super chat list by name.
  9. // @description:zh 讓 hololyzer 的超級留言清單支援按姓名排序
  10. // @description:zh-TW 讓 hololyzer 的超級留言清單支援按姓名排序
  11. // @description:zh-CN 让 hololyzer 的超级留言清单支持按姓名排序
  12. // @author kevin823lin
  13. // @match https://www.hololyzer.net/*/superchat/*
  14. // @icon https://www.google.com/s2/favicons?domain=hololyzer.net
  15. // @grant none
  16. // @run-at document-start
  17. // @date 2021-12-13
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. 'use strict';
  22.  
  23. // Your code here...
  24. window.addEventListener('DOMContentLoaded', function (event) {
  25. document.body.dataset.sortBy = "time";
  26. insertButton();
  27. }, false);
  28.  
  29. function insertButton() {
  30. const sortByTimeBtn = document.createElement('button');
  31. const sortByNameBtn = document.createElement('button');
  32. const copyTableBtn = document.createElement('button');
  33. sortByTimeBtn.innerText = "時間排序";
  34. sortByNameBtn.innerText = "姓名排序";
  35. copyTableBtn.innerText = "複製表格";
  36. sortByTimeBtn.addEventListener("click", function () {
  37. if (document.body.dataset.sortBy !== "time") {
  38. window.location.href = window.location.href;
  39. }
  40. });
  41. sortByNameBtn.addEventListener("click", async function () {
  42. if ((document.body.dataset.sortBy) !== "name") {
  43. document.body.dataset.sortBy = "name";
  44. await waitElementsLoaded('table[border]');
  45. main();
  46. }
  47. });
  48. copyTableBtn.addEventListener("click", function () {
  49. copyTable();
  50. });
  51. document.body.insertAdjacentElement('afterbegin', copyTableBtn);
  52. document.body.insertAdjacentElement('afterbegin', sortByNameBtn);
  53. document.body.insertAdjacentElement('afterbegin', sortByTimeBtn);
  54. }
  55.  
  56. function main() {
  57. moveYenCol();
  58. sortByName();
  59. insertRemoveDuplicatesCol();
  60. }
  61.  
  62. function moveYenCol() {
  63. const tbody = document.querySelector('table[border] > tbody');
  64. const trs = tbody.querySelectorAll("tr");
  65. const insertIndex = [...tbody.querySelectorAll("th")].findIndex(th => th.matches('[style]'));
  66. tbody.querySelectorAll('[rowspan]').forEach(a => a.removeAttribute('rowspan'))
  67. trs.forEach((tr, i) => {
  68. if (i % 2) {
  69. const parentEle = trs[i - 1];
  70. const childrenEle = parentEle.children[insertIndex + 1];
  71. const insertEle = tr.querySelector("th") || tr.querySelector("td");
  72. childrenEle.removeAttribute('style');
  73. insertEle.removeAttribute('style');
  74. insertEle.parentElement.remove();
  75. parentEle.insertBefore(insertEle, childrenEle);
  76. }
  77. })
  78. }
  79.  
  80. function sortByName() {
  81. const tbody = document.querySelector('table[border] > tbody');
  82. const trs = [...tbody.querySelectorAll("tr")].filter(tr => {
  83. return tr.querySelector('td');
  84. });
  85.  
  86. let sortIndex = [...tbody.querySelectorAll('th')].findIndex(th => th.innerText === "チャンネル名");
  87. if (sortIndex === -1) {
  88. sortIndex = 6;
  89. }
  90. trs.sort(function (a, b) {
  91. var keyA = a.querySelector(`td:nth-child(${sortIndex + 1})`).textContent;
  92. var keyB = b.querySelector(`td:nth-child(${sortIndex + 1})`).textContent;
  93. return keyA.localeCompare(keyB, 'ja');
  94. });
  95. for (const tr of trs) {
  96. tbody.append(tr);
  97. }
  98. }
  99.  
  100. function insertRemoveDuplicatesCol() {
  101. const tbody = document.querySelector('table[border] > tbody');
  102. const trs = [...tbody.querySelectorAll("tr")].filter(tr => {
  103. return tr.querySelector('td');
  104. });
  105.  
  106. let insertIndex = [...tbody.querySelectorAll('th')].findIndex(th => th.innerText === "No");
  107. if (insertIndex === -1) {
  108. insertIndex = 0;
  109. }
  110. let sortIndex = [...tbody.querySelectorAll('th')].findIndex(th => th.innerText === "チャンネル名");
  111. if (sortIndex === -1) {
  112. sortIndex = 6;
  113. }
  114.  
  115. let count = 0;
  116. const countList = new Array();
  117. for (const [i, tr] of trs.entries()) {
  118. const preName = trs[i - 1] && trs[i - 1].querySelector(`:nth-child(${sortIndex + 1})`)?.innerText;
  119. const name = tr.querySelector(`:nth-child(${sortIndex + 1})`)?.innerText;
  120. countList.push(preName !== name ? ++count : count);
  121. }
  122. for (const [i, tr] of trs.entries()) {
  123. const insertEle = tr.insertCell(insertIndex + 1);
  124. insertEle.innerText = countList[i];
  125. insertEle.style = "text-align: right";
  126. }
  127. const parentEle = tbody.querySelector("tr");
  128. const childrenEle = parentEle.children[insertIndex + 1];
  129. const insertEle = document.createElement("th");
  130. insertEle.innerText = "去除重複";
  131. insertEle.style = "white-space: nowrap;";
  132. parentEle.insertBefore(insertEle, childrenEle);
  133. }
  134.  
  135. function copyTable() {
  136. copyElement(document.querySelector('table[border] > tbody'));
  137. }
  138.  
  139. function copyElement(ele) {
  140. if (document.createRange && window.getSelection) {
  141. const sel = window.getSelection();
  142. const oldRange = Array.apply(null, new Array(sel.rangeCount)).map((a, i) => sel.getRangeAt(i));
  143. const copyRange = document.createRange();
  144. sel.removeAllRanges();
  145. try {
  146. copyRange.selectNode(ele);
  147. sel.addRange(copyRange);
  148. } catch (e) {
  149. copyRange.selectNodeContents(ele);
  150. sel.addRange(copyRange);
  151. }
  152. document.execCommand("copy");
  153. sel.removeAllRanges();
  154. oldRange.forEach(range => { sel.addRange(range) });
  155. } else {
  156. alert("複製失敗");
  157. }
  158. }
  159.  
  160. function waitElementsLoaded(...eles) {
  161. return Promise.all(eles.map(ele => {
  162. return new Promise(async resolve => {
  163. while (!document.querySelector(ele)) {
  164. await wait(100);
  165. }
  166. resolve();
  167. });
  168. }));
  169. }
  170.  
  171. function wait(ms) {
  172. try {
  173. return new Promise(r => setTimeout(r, ms));
  174. } catch (e) {
  175. console.error(`wait: ${e}`);
  176. }
  177. }
  178. })();