Greasy Fork is available in English.
Ajouter la prise en charge du tri de la liste de super chats hololyzer par nom.
// ==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}`); } } })();