hololyzer 排序工具

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

目前为 2021-12-10 提交的版本。查看 最新版本

  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.1
  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. // @date 2021-12-11
  17. // ==/UserScript==
  18.  
  19. (function () {
  20. 'use strict';
  21.  
  22. // Your code here...
  23. window.addEventListener('load', function (event) {
  24. document.body.dataset.sortBy = "time";
  25. insertButton();
  26. }, false);
  27.  
  28. function insertButton() {
  29. const sortByTime = document.createElement('button');
  30. const sortByName = document.createElement('button');
  31. sortByTime.innerHTML = "時間排序";
  32. sortByName.innerHTML = "姓名排序";
  33. sortByTime.addEventListener("click", function () {
  34. if (document.body.dataset.sortBy !== "time") {
  35. window.location.href = window.location.href;
  36. }
  37. });
  38. sortByName.addEventListener("click", async function () {
  39. if ((document.body.dataset.sortBy) !== "name") {
  40. document.body.dataset.sortBy = "name";
  41. await waitElementsLoaded('table[border]');
  42. main();
  43. }
  44. });
  45. document.body.insertAdjacentElement('afterbegin', sortByName);
  46. document.body.insertAdjacentElement('afterbegin', sortByTime);
  47. }
  48.  
  49. function main() {
  50. move();
  51. sort();
  52. insert();
  53. }
  54.  
  55. function move() {
  56. const tbody = document.querySelector('table[border] > tbody');
  57. const trs = tbody.querySelectorAll("tr");
  58. const insertIndex = [...tbody.querySelectorAll("th")].findIndex(th => th.matches('[style]'));
  59. tbody.querySelectorAll('[rowspan]').forEach(a => a.removeAttribute('rowspan'))
  60. trs.forEach((tr, i) => {
  61. if (i % 2) {
  62. const parentEle = trs[i - 1];
  63. const childrenEle = parentEle.children[insertIndex + 1];
  64. const insertEle = tr.querySelector("th") || tr.querySelector("td");
  65. childrenEle.removeAttribute('style');
  66. insertEle.removeAttribute('style');
  67. insertEle.parentElement.remove();
  68. parentEle.insertBefore(insertEle, childrenEle);
  69. }
  70. })
  71. }
  72.  
  73. function sort() {
  74. const tbody = document.querySelector('table[border] > tbody');
  75. const trs = [...tbody.querySelectorAll("tr")].filter(tr => {
  76. return tr.querySelector('td');
  77. });
  78.  
  79. let sortIndex = [...tbody.querySelectorAll('th')].findIndex(th => th.innerText === "チャンネル名");
  80. if (sortIndex === -1) {
  81. sortIndex = 6;
  82. }
  83. trs.sort(function (a, b) {
  84. var keyA = a.querySelector(`td:nth-child(${sortIndex + 1})`).textContent;
  85. var keyB = b.querySelector(`td:nth-child(${sortIndex + 1})`).textContent;
  86. return keyA.localeCompare(keyB, 'ja');
  87. });
  88. for (const tr of trs) {
  89. tbody.append(tr);
  90. }
  91. }
  92.  
  93. function insert() {
  94. const tbody = document.querySelector('table[border] > tbody');
  95. const trs = [...tbody.querySelectorAll("tr")].filter(tr => {
  96. return tr.querySelector('td');
  97. });
  98.  
  99. let insertIndex = [...tbody.querySelectorAll('th')].findIndex(th => th.innerText === "No");
  100. if (insertIndex === -1) {
  101. insertIndex = 0;
  102. }
  103. let sortIndex = [...tbody.querySelectorAll('th')].findIndex(th => th.innerText === "チャンネル名");
  104. if (sortIndex === -1) {
  105. sortIndex = 6;
  106. }
  107.  
  108. let count = 0;
  109. const countList = new Array();
  110. for (const [i, tr] of trs.entries()) {
  111. const preName = trs[i - 1] && trs[i - 1].querySelector(`:nth-child(${sortIndex + 1})`)?.innerText;
  112. const name = tr.querySelector(`:nth-child(${sortIndex + 1})`)?.innerText;
  113. countList.push(preName !== name ? ++count : count);
  114. }
  115. for (const [i, tr] of trs.entries()) {
  116. const insertEle = tr.insertCell(insertIndex + 1);
  117. insertEle.innerHTML = countList[i];
  118. insertEle.style = "text-align: right";
  119. }
  120. const parentEle = tbody.querySelector("tr");
  121. const childrenEle = parentEle.children[insertIndex + 1];
  122. const insertEle = document.createElement("th");
  123. insertEle.innerHTML = "去除重複";
  124. insertEle.style = "white-space: nowrap;";
  125. parentEle.insertBefore(insertEle, childrenEle);
  126. }
  127.  
  128. function waitElementsLoaded(...eles) {
  129. return Promise.all(eles.map(ele => {
  130. return new Promise(async resolve => {
  131. while (!document.querySelector(ele)) {
  132. await wait(100);
  133. }
  134. resolve();
  135. });
  136. }));
  137. }
  138.  
  139. function wait(ms) {
  140. try {
  141. return new Promise(r => setTimeout(r, ms));
  142. } catch (e) {
  143. console.error(`wait: ${e}`);
  144. }
  145. }
  146. })();