您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Панель сортировки, цветной график топ-100 сообщений. Поддержка /a/ и /k/, drag&drop, фильтры, экспорт CSV. 🇺🇦 Зроблено в Україні.
// ==UserScript== // @name Telegram Web Sort Panel + Chart (Зроблено в Україні) // @namespace https://example.com // @version 3.2 // @description Панель сортировки, цветной график топ-100 сообщений. Поддержка /a/ и /k/, drag&drop, фильтры, экспорт CSV. 🇺🇦 Зроблено в Україні. // @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: 280px; 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 { margin:2px;padding:3px 5px;border:none;border-radius:4px; background:#0d6efd;color:#fff;cursor:pointer;font-size:12px; } #ua-buttons button:hover {opacity:0.8;} #ua-chart {width:100%;height:200px;} #ua-hide { position:absolute;top:2px;right:2px;cursor:pointer;font-weight:bold; } `); 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> <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 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); } })();