您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Панель сортировки, график топ-100 сообщений + языковая панель. 🇺🇦 Зроблено в Україні.
// ==UserScript== // @name Telegram Web Sort Panel + Chart + Lang (Зроблено в Україні) // @namespace https://example.com // @version 3.3 // @description Панель сортировки, график топ-100 сообщений + языковая панель. 🇺🇦 Зроблено в Україні. // @match https://web.telegram.org/a/* // @match https://web.telegram.org/k/* // @grant GM_addStyle // @run-at document-end // ==/UserScript== (function() { 'use strict'; // === Chart.js === const chartScript = document.createElement('script'); chartScript.src = 'https://cdn.jsdelivr.net/npm/chart.js'; document.head.appendChild(chartScript); GM_addStyle(` #ua-panel { position: fixed; top: 100px; right: 20px; width: 300px; background: var(--tg-theme-bg-color, #fff); color: var(--tg-theme-text-color, #000); border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.3); padding: 8px; z-index: 99999; font-family: Arial,sans-serif; } #ua-panel-header { display:flex;align-items:center;justify-content:space-between; font-weight:bold; cursor:move; } #ua-buttons button, #ua-lang select { margin:2px;padding:3px 5px;border:none;border-radius:4px; background:#0d6efd;color:#fff;cursor:pointer;font-size:12px; } #ua-buttons button:hover, #ua-lang select:hover {opacity:0.8;} #ua-chart {width:100%;height:200px;} #ua-hide { position:absolute;top:2px;right:2px;cursor:pointer;font-weight:bold; } #ua-lang { margin-top:5px; } `); const panel = document.createElement('div'); panel.id = 'ua-panel'; panel.innerHTML = ` <div id="ua-panel-header"> <span>🇺🇦 Зроблено в Україні</span> <span id="ua-hide">✖</span> </div> <div id="ua-buttons"> <button data-sort="reactions">По реакциям</button> <button data-sort="date_desc">Дата ↓</button> <button data-sort="date_asc">Дата ↑</button> <button data-sort="media">По медиа</button> <button data-sort="length">По длине</button> <button data-action="24h">За 24ч</button> <button data-action="refresh">Обновить</button> <button data-action="csv">Экспорт CSV</button> </div> <div id="ua-lang"> <select> <option value="ua">Українська</option> <option value="ru">Русский</option> <option value="en">English</option> <option value="de">Deutsch</option> <option value="fr">Français</option> <option value="es">Español</option> <option value="it">Italiano</option> <option value="pt">Português</option> <option value="pl">Polski</option> <option value="zh">中文</option> <option value="ja">日本語</option> <option value="ko">한국어</option> </select> </div> <canvas id="ua-chart"></canvas> `; document.body.appendChild(panel); // === drag & drop + сохранение позиции === let offsetX, offsetY, isDragging=false; const savedPos = JSON.parse(localStorage.getItem('uaPanelPos')||'{}'); if(savedPos.left && savedPos.top){ panel.style.left = savedPos.left+'px'; panel.style.top = savedPos.top+'px'; panel.style.right = 'unset'; } panel.querySelector('#ua-panel-header').addEventListener('mousedown',e=>{ isDragging=true; offsetX=e.clientX-panel.offsetLeft; offsetY=e.clientY-panel.offsetTop; }); document.addEventListener('mouseup',()=>isDragging=false); document.addEventListener('mousemove',e=>{ if(isDragging){ panel.style.left=(e.clientX-offsetX)+'px'; panel.style.top=(e.clientY-offsetY)+'px'; panel.style.right='unset'; } }); window.addEventListener('beforeunload',()=>{ localStorage.setItem('uaPanelPos',JSON.stringify({left:panel.offsetLeft,top:panel.offsetTop})); }); // === скрыть === panel.querySelector('#ua-hide').addEventListener('click',()=>{ panel.style.display='none'; localStorage.setItem('uaPanelHidden','true'); }); if(localStorage.getItem('uaPanelHidden')==='true') panel.style.display='none'; // === Chart.js загрузился === chartScript.onload = ()=>init(); function init(){ const ctx=document.getElementById('ua-chart').getContext('2d'); let chart=new Chart(ctx,{type:'bar',data:{labels:[],datasets:[{label:'ТОП-10',data:[],backgroundColor:[]}]}}); function randomColor(){ return `hsl(${Math.floor(Math.random()*360)},70%,50%)`; } function collectMessages(){ const msgs=document.querySelectorAll('[class*="message"]'); let arr=[]; msgs.forEach(m=>{ const text=m.innerText||''; const date=m.querySelector('time')?.getAttribute('datetime')||''; const reactions=m.querySelectorAll('[class*="reaction"]').length; const media=m.querySelectorAll('img,video').length; arr.push({el:m,text,date,reactions,media}); }); return arr; } function updateChart(data){ chart.data.labels=data.slice(0,10).map((_,i)=>i+1); chart.data.datasets[0].data=data.slice(0,10).map(d=>d.value); chart.data.datasets[0].backgroundColor=data.slice(0,10).map(()=>randomColor()); chart.update(); } function sortData(type){ let msgs=collectMessages(); let now=Date.now(); if(type==='24h') msgs=msgs.filter(m=>now-(new Date(m.date).getTime())<86400000); let data=[]; switch(type){ case 'reactions': data=msgs.map(m=>({value:m.reactions,text:m.text})).sort((a,b)=>b.value-a.value); break; case 'date_desc': data=msgs.map(m=>({value:new Date(m.date).getTime(),text:m.text})).sort((a,b)=>b.value-a.value); break; case 'date_asc': data=msgs.map(m=>({value:new Date(m.date).getTime(),text:m.text})).sort((a,b)=>a.value-b.value); break; case 'media': data=msgs.map(m=>({value:m.media,text:m.text})).sort((a,b)=>b.value-a.value); break; case 'length': data=msgs.map(m=>({value:m.text.length,text:m.text})).sort((a,b)=>b.value-a.value); break; default: data=msgs.map(m=>({value:m.text.length,text:m.text})); } updateChart(data); } document.querySelectorAll('#ua-buttons button').forEach(btn=>{ btn.addEventListener('click',()=>{ const sort=btn.dataset.sort; const action=btn.dataset.action; if(sort) sortData(sort); if(action==='24h') sortData('24h'); if(action==='refresh') sortData('reactions'); if(action==='csv'){ const msgs=collectMessages(); let csv='Текст;Реакции;Медиа;Дата\n'; msgs.forEach(m=>csv+=`"${m.text.replace(/"/g,'""')}";${m.reactions};${m.media};${m.date}\n`); const blob=new Blob([csv],{type:'text/csv'}); const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='telegram_export.csv'; a.click(); } }); }); // === языковая смена === const langSelect = panel.querySelector('#ua-lang select'); langSelect.addEventListener('change',()=>{ const lang = langSelect.value; localStorage.setItem('uaPanelLang', lang); applyLang(lang); }); const savedLang = localStorage.getItem('uaPanelLang') || 'ua'; langSelect.value = savedLang; applyLang(savedLang); function applyLang(lang){ const translations = { ua: { reactions:'За реакціями', date_desc:'Дата ↓', date_asc:'Дата ↑', media:'По медіа', length:'По довжині', '24h':'За 24г', refresh:'Оновити', csv:'Експорт CSV' }, ru: { reactions:'По реакциям', date_desc:'Дата ↓', date_asc:'Дата ↑', media:'По медиа', length:'По длине', '24h':'За 24ч', refresh:'Обновить', csv:'Экспорт CSV' }, en: { reactions:'By reactions', date_desc:'Date ↓', date_asc:'Date ↑', media:'By media', length:'By length', '24h':'Last 24h', refresh:'Refresh', csv:'Export CSV' }, de: { reactions:'Nach Reaktionen', date_desc:'Datum ↓', date_asc:'Datum ↑', media:'Nach Medien', length:'Nach Länge', '24h':'Letzte 24h', refresh:'Aktualisieren', csv:'CSV exportieren' }, fr: { reactions:'Par réactions', date_desc:'Date ↓', date_asc:'Date ↑', media:'Par médias', length:'Par longueur', '24h':'24h', refresh:'Rafraîchir', csv:'Exporter CSV' }, es: { reactions:'Por reacciones', date_desc:'Fecha ↓', date_asc:'Fecha ↑', media:'Por medios', length:'Por longitud', '24h':'Últimas 24h', refresh:'Actualizar', csv:'Exportar CSV' }, it: { reactions:'Per reazioni', date_desc:'Data ↓', date_asc:'Data ↑', media:'Per media', length:'Per lunghezza', '24h':'Ultime 24h', refresh:'Aggiorna', csv:'Esporta CSV' }, pt: { reactions:'Por reações', date_desc:'Data ↓', date_asc:'Data ↑', media:'Por mídia', length:'Por comprimento', '24h':'Últimas 24h', refresh:'Atualizar', csv:'Exportar CSV' }, pl: { reactions:'Według reakcji', date_desc:'Data ↓', date_asc:'Data ↑', media:'Według mediów', length:'Według długości', '24h':'Ostatnie 24h', refresh:'Odśwież', csv:'Eksport CSV' }, zh: { reactions:'按反应', date_desc:'日期 ↓', date_asc:'日期 ↑', media:'按媒体', length:'按长度', '24h':'24小时内', refresh:'刷新', csv:'导出 CSV' }, ja: { reactions:'リアクション順', date_desc:'日付 ↓', date_asc:'日付 ↑', media:'メディア順', length:'長さ順', '24h':'過去24時間', refresh:'更新', csv:'CSVエクスポート' }, ko: { reactions:'반응순', date_desc:'날짜 ↓', date_asc:'날짜 ↑', media:'미디어순', length:'길이순', '24h':'최근 24시간', refresh:'새로고침', csv:'CSV 내보내기' } }; document.querySelectorAll('#ua-buttons button').forEach(btn=>{ const key = btn.dataset.sort || btn.dataset.action; if(translations[lang][key]) btn.textContent = translations[lang][key]; }); } const chatContainer=document.querySelector('#column-center')||document.body; if(chatContainer){ const observer=new MutationObserver(()=>sortData('reactions')); observer.observe(chatContainer,{childList:true,subtree:true}); } setTimeout(()=>sortData('reactions'),3000); } })();