- // ==UserScript==
- // @name hololyzer Sort Tool
- // @name:zh hololyzer 排序工具
- // @name:zh-TW hololyzer 排序工具
- // @name:zh-HK hololyzer 排序工具
- // @name:zh-CN hololyzer 排序工具
- // @name:zh-SG hololyzer 排序工具
- // @name:en hololyzer Sort Tool
- // @name:ja hololyzerのソートツール
- // @name:ko hololyzer 정렬 도구
- // @name:fr Outil de tri hololyzer
- // @name:es Herramienta de ordenación hololyzer
- // @name:ar أداة ترتيب هولوليزر
- // @name:de hololyzer-Sortierwerkzeug
- // @name:hi होलोलाइज़र सॉर्ट टूल
- // @name:ru Инструмент сортировки hololyzer
- // @name:pt Ferramenta de classificação hololyzer
- // @name:sw Chombo cha utaratibu wa hololyzer
- // @name:sr Alat za sortiranje hololajzera
- // @name:hr Alat za sortiranje hololajzera
- // @name:it Strumento di ordinamento hololyzer
- // @name:ms Alat penyusunan hololyzer
- // @name:id Alat pengurutan hololyzer
- // @name:nl hololyzer sorteertool
- // @name:fa ابزار مرتب سازی hololyzer
- // @namespace https://github.com/kevin823lin
- // @version 0.3
- // @description Add support for sorting hololyzer's super chat list by name.
- // @description:zh 讓 hololyzer 的超級留言清單支援姓名排序功能
- // @description:zh-TW 讓 hololyzer 的超級留言清單支援姓名排序功能
- // @description:zh-HK 讓 hololyzer 的超級留言清單支援姓名排序功能
- // @description:zh-CN 让 hololyzer 的超级留言清单支持姓名排序功能
- // @description:zh-SG 让 hololyzer 的超级留言清单支持姓名排序功能
- // @description:en Add support for sorting hololyzer's super chat list by name.
- // @description:ja hololyzerのスーパーチャットリストを名前でソートする機能を追加する
- // @description:ko hololyzer의 슈퍼 챗 목록을 이름별로 정렬하는 기능
- // @description:fr Ajouter la prise en charge du tri de la liste de super chats hololyzer par nom.
- // @description:es Agregar soporte para ordenar la lista de super chats de hololyzer por nombre.
- // @description:ar إضافة دعم لترتيب قائمة الدردشة الخارقة لـ hololyzer حسب الاسم.
- // @description:de Unterstützung zum Sortieren der Super-Chat-Liste von hololyzer nach Namen hinzufügen.
- // @description:hi नाम द्वारा होलोलाइजर के सुपर चैट सूची को सॉर्ट करने के लिए समर्थन जोड़ें।
- // @description:ru Добавить поддержку сортировки списка супер-чатов hololyzer по имени.
- // @description:pt Adicionar suporte para classificar a lista de superchats do hololyzer por nome.
- // @description:sw Ongeza msaada wa kupanga orodha ya gumzo kuu la hololyzer kwa jina.
- // @description:sr Dodajte podršku za sortiranje super-čet liste hololyzer-a po imenu.
- // @description:hr Dodajte podršku za sortiranje super chat liste hololyzer po imenu.
- // @description:it Aggiungere il supporto per ordinare l'elenco dei super chat di hololyzer per nome.
- // @description:ms Tambah sokongan untuk mengurutkan senarai sembang super hololyzer mengikut nama.
- // @description:id Tambahkan dukungan untuk mengurutkan daftar super chat hololyzer berdasarkan nama.
- // @description:nl Voeg ondersteuning toe voor het sorteren van de superchatlijst van hololyzer op naam.
- // @description:fa پشتیبانی از مرتب سازی لیست چت های فوق العاده hololyzer بر اساس نام.
- // @author kevin823lin
- // @match https://www.hololyzer.net/*/superchat/*
- // @icon https://www.google.com/s2/favicons?domain=hololyzer.net
- // @grant none
- // @date 2023-03-08
- // ==/UserScript==
- /*Translate and optimize with ChatGPT*/
-
- (function () {
- 'use strict';
-
- // Your code here...
- init();
-
- function i18n(name, param) {
- const lang = navigator.appName == "Netscape" ? navigator.language : navigator.userLanguage;
- let config = {};
- switch (lang) {
- case "zh":
- case "zh-TW":
- case "zh-HK":
- config = {
- sortByTime: "時間排序",
- sortByName: "姓名排序",
- copyTable: "複製表格",
- copyFailed: "複製失敗"
- };
- break;
- case "zh-CN":
- case "zh-SG":
- config = {
- sortByTime: "时间排序",
- sortByName: "姓名排序",
- copyTable: "复制表格",
- copyFailed: "复制失败"
- };
- break;
- case "en":
- config = {
- sortByTime: "Sort by time",
- sortByName: "Sort by name",
- copyTable: "Copy table",
- copyFailed: "Copy failed"
- };
- break;
- case "ja":
- config = {
- sortByTime: "時間で並び替え",
- sortByName: "名前で並び替え",
- copyTable: "表をコピーする",
- copyFailed: "コピーに失敗しました"
- };
- break;
-
- case "ko":
- config = {
- sortByTime: "시간순 정렬",
- sortByName: "이름순 정렬",
- copyTable: "표 복사하기",
- copyFailed: "복사 실패"
- };
- break;
- case "fr":
- config = {
- sortByTime: "Trier par temps",
- sortByName: "Trier par nom",
- copyTable: "Copier le tableau",
- copyFailed: "Copie échouée"
- };
- break;
- case "es":
- config = {
- sortByTime: "Ordenar por tiempo",
- sortByName: "Ordenar por nombre",
- copyTable: "Copiar tabla",
- copyFailed: "Error al copiar"
- };
- break;
- case "ar":
- config = {
- sortByTime: "ترتيب حسب الوقت",
- sortByName: "ترتيب حسب الاسم",
- copyTable: "نسخ الجدول",
- copyFailed: "فشل النسخ"
- };
- break;
- case "de":
- config = {
- sortByTime: "Nach Zeit sortieren",
- sortByName: "Nach Name sortieren",
- copyTable: "Tabelle kopieren",
- copyFailed: "Kopieren fehlgeschlagen"
- };
- break;
- case "hi":
- config = {
- sortByTime: "समय के अनुसार क्रमबद्ध करें",
- sortByName: "नाम के अनुसार क्रमबद्ध करें",
- copyTable: "टेबल कॉपी करें",
- copyFailed: "कॉपी असफल"
- };
- break;
- case "ru":
- config = {
- sortByTime: "Сортировать по времени",
- sortByName: "Сортировать по имени",
- copyTable: "Копировать таблицу",
- copyFailed: "Ошибка копирования"
- };
- break;
- case "pt":
- config = {
- sortByTime: "Ordenar por hora",
- sortByName: "Ordenar por nome",
- copyTable: "Copiar tabela",
- copyFailed: "Falha ao copiar"
- };
- break;
- case "sw":
- config = {
- sortByTime: "Sort by Time",
- sortByName: "Sort by Name",
- copyTable: "Copy Table",
- copyFailed: "Kushindwa nakala"
- };
- break;
- case "sr":
- case "hr":
- case "it":
- config = {
- sortByTime: "Sortiraj po vremenu",
- sortByName: "Sortiraj po imenu",
- copyTable: "Kopiraj tabelu",
- copyFailed: "Kopiranje nije uspelo"
- };
- break;
- case "ms":
- case "id":
- config = {
- sortByTime: "Susun mengikut masa",
- sortByName: "Susun mengikut nama",
- copyTable: "Salin Jadual",
- copyFailed: "Salinan gagal"
- };
- break;
- case "nl":
- config = {
- sortByTime: "Sorteren op tijd",
- sortByName: "Sorteren op naam",
- copyTable: "Tabel kopiëren",
- copyFailed: "Kopiëren mislukt"
- };
- break;
- case "fa":
- config = {
- sortByTime: "مرتب سازی بر اساس زمان",
- sortByName: "مرتب سازی بر اساس نام",
- copyTable: "رونوشت جدول",
- copyFailed: "کپی ناموفق"
- };
- break;
- default:
- config = {
- sortByTime: "Sort by time",
- sortByName: "Sort by name",
- copyTable: "Copy table",
- copyFailed: "Copy failed"
- };
- break;
- }
- return config[name] ? config[name].replace("#t#", param) : name;
- }
-
- async function init() {
- document.body.dataset.sortBy = "time";
- insertButton();
- await waitElementsLoaded('table[border]');
- const { tbody, newTbody } = getTbodyAndFakeTbody();
- insertNoByBame(newTbody);
- replaceTbody(tbody, newTbody);
- }
-
- function insertButton() {
- const sortByTimeBtn = document.createElement('button');
- const sortByNameBtn = document.createElement('button');
- const copyTableBtn = document.createElement('button');
- sortByTimeBtn.innerText = i18n('sortByTime');
- sortByNameBtn.innerText = i18n('sortByName');
- copyTableBtn.innerText = i18n('copyTable');
- sortByTimeBtn.addEventListener("click", function () {
- if (document.body.dataset.sortBy !== "time") {
- document.body.dataset.sortBy = "time";
- main("time");
- }
- });
- sortByNameBtn.addEventListener("click", async function () {
- if ((document.body.dataset.sortBy) !== "name") {
- document.body.dataset.sortBy = "name";
- main("name");
- }
- });
- copyTableBtn.addEventListener("click", function () {
- copyTable();
- });
- document.body.insertAdjacentElement('afterbegin', copyTableBtn);
- document.body.insertAdjacentElement('afterbegin', sortByNameBtn);
- document.body.insertAdjacentElement('afterbegin', sortByTimeBtn);
- }
-
- function insertNoByBame(tbody) {
- const ths = [...tbody.querySelectorAll("th")];
- const trs = [...tbody.querySelectorAll("tr:has(>td):nth-child(odd)")];
-
- const insertIndex = ((index) => index === -1 ? 0 : index)(ths.findIndex(th => /^(n|N)o$/.test(th.innerText)));
- const sortIndex = ((index) => index === -1 ? 6 : index)(ths.findIndex(th => /name|チャンネル名/.test(th.innerText)));
-
- const sortedTrs = sortTrs(trs, sortIndex);
-
- let count = 0;
- const countList = sortedTrs.map((tr, i) => {
- const preName = sortedTrs[i - 1]?.element.children[sortIndex]?.childNodes[0].textContent;
- const name = tr.element.children[sortIndex]?.childNodes[0].textContent;
- return preName !== name ? ++count : count;
- });
-
- sortedTrs.forEach((tr, i) => {
- const insertEle = tr.element.insertCell(insertIndex + 1);
- insertEle.innerText = countList[i];
- insertEle.setAttribute('rowspan', 2);
- insertEle.style.textAlign = "right";
- });
-
- const parentRow = tbody.querySelector("tr");
- const childrenEle = parentRow.children[insertIndex + 1];
- const insertEle = document.createElement("th");
- insertEle.innerText = "no by name";
- insertEle.setAttribute('rowspan', 2);
- parentRow.insertBefore(insertEle, childrenEle);
- }
-
- async function main(sortBy) {
- const { tbody, newTbody } = getTbodyAndFakeTbody();
- sort(newTbody, sortBy);
- replaceTbody(tbody, newTbody);
- }
-
- function sort(tbody, sortBy) {
- const trs = [...tbody.querySelectorAll("tr:has(>td):nth-child(odd)")];
-
- let sortIndex;
-
- switch (sortBy) {
- case "time":
- sortIndex = ((index) => index === -1 ? 0 : index)([...tbody.querySelectorAll('th')].findIndex(th => /^(n|N)o$/.test(th.innerText)));
- break;
- case "name":
- sortIndex = ((index) => index === -1 ? 1 : index)([...tbody.querySelectorAll('th')].findIndex(th => /no by name/.test(th.innerText)));
- break;
- }
- const sortedTrs = sortTrs(trs, sortIndex, true);
-
- sortedTrs.forEach(item => { tbody.appendChild(item.element); tbody.appendChild(item.nextElementSibling) });
- }
-
- function sortTrs(trs, sortIndex, num = false) {
- return trs.map(tr => ({
- element: tr,
- previousElementSibling: tr.previousElementSibling,
- nextElementSibling: tr.nextElementSibling,
- key: tr.children[sortIndex].innerText
- })).sort((a, b) => num ? (a.key - b.key) : a.key.localeCompare(b.key, 'ja'));
- }
-
- function getTbodyAndFakeTbody() {
- const tbody = document.querySelector('table[border] > tbody');
-
- const clonedTbody = tbody.cloneNode(true);
- const fragment = new DocumentFragment();
- fragment.append(clonedTbody);
-
- const newTbody = fragment.querySelector('tbody')
-
- return { tbody, newTbody };
- }
-
- function replaceTbody(tbody, newTbody) {
- tbody.replaceWith(newTbody);
- }
-
- function copyTable() {
- copyElement(document.querySelector('table[border] > tbody'));
- }
-
- function copyElement(ele) {
- if (document.createRange && window.getSelection) {
- const sel = window.getSelection();
- const oldRange = Array.from({ length: sel.rangeCount }, (_, i) => sel.getRangeAt(i));
- const copyRange = document.createRange();
- sel.removeAllRanges();
- try {
- copyRange.selectNode(ele);
- sel.addRange(copyRange);
- } catch (e) {
- copyRange.selectNodeContents(ele);
- sel.addRange(copyRange);
- }
- navigator.clipboard.writeText(sel.toString());
- sel.removeAllRanges();
- oldRange.forEach(range => { sel.addRange(range) });
- } else {
- alert(i18n('copyFailed'));
- }
- }
-
- function waitElementsLoaded(...eles) {
- return Promise.all(eles.map(ele => {
- return new Promise(async resolve => {
- while (!document.querySelector(ele)) {
- await wait(100);
- }
- resolve();
- });
- }));
- }
-
- function wait(ms) {
- try {
- return new Promise(r => setTimeout(r, ms));
- } catch (e) {
- console.error(`wait: ${e}`);
- }
- }
- })();