// ==UserScript== // @name Hacker News URL Highlighter with Enhanced Panel and Scores & Comments // @namespace https://news.ycombinator.com/ // @version 1.6 // @description Highlights URLs in comments, displays them in a toggleable panel with sorting (frequency, name, upvotes, comment count). // @author MorganGeek // @match https://news.ycombinator.com/item?id=* // @grant GM_xmlhttpRequest // @grant GM_setClipboard // @connect * // @run-at document-end // ==/UserScript== (function() { 'use strict'; const COLORS={low:'#d1e7dd',medium:'#fff3cd',high:'#f8d7da'}; const toggleButton=document.createElement('button'); toggleButton.textContent='Afficher les URLs'; Object.assign(toggleButton.style,{ position:'fixed',bottom:'10px',right:'10px',zIndex:1000,padding:'10px 15px', backgroundColor:'#ff6600',color:'#fff',border:'none',borderRadius:'5px',cursor:'pointer' }); document.body.appendChild(toggleButton); const panel=document.createElement('div'); panel.id='url-panel'; Object.assign(panel.style,{ position:'fixed',top:'10px',right:'10px',width:'350px',backgroundColor:'#fff', border:'1px solid #ccc',borderRadius:'5px',padding:'10px',boxShadow:'0 0 10px rgba(0,0,0,.2)', maxHeight:'80vh',overflowY:'auto',zIndex:1000,display:'none' }); panel.innerHTML=`

URLs

`; document.body.appendChild(panel); const tooltip=document.createElement('div'); tooltip.id='url-tooltip'; Object.assign(tooltip.style,{ position:'absolute',background:'#fff',border:'1px solid #ccc',borderRadius:'5px', padding:'10px',boxShadow:'0 0 10px rgba(0,0,0,.2)',maxWidth:'300px', display:'none',zIndex:1001 }); document.body.appendChild(tooltip); const urlData={}; const comments=document.querySelectorAll('.commtext'); comments.forEach(comment=>{ const links=comment.querySelectorAll('a[href]'); links.forEach(link=>{ const u=link.href; if(!urlData[u]) urlData[u]={url:u,count:0,upvotes:0,commentCount:0}; urlData[u].count++; link.style.backgroundColor='#ffff99'; link.addEventListener('mouseover',()=>{ GM_xmlhttpRequest({ method:'GET',url:u, onload:r=>{ tooltip.innerHTML=''; const d=new DOMParser().parseFromString(r.responseText,'text/html'); const t=d.querySelector('title')?d.querySelector('title').innerText:'No Title'; const desc=d.querySelector('meta[name="description"]')?d.querySelector('meta[name="description"]').content:'No Description'; tooltip.innerHTML=`${t}

${desc}

`; tooltip.style.display='block'; }, onerror:()=>{ tooltip.innerHTML='Preview unavailable'; tooltip.style.display='block'; } }); const rect=link.getBoundingClientRect(); tooltip.style.top=`${rect.bottom+window.scrollY+5}px`; tooltip.style.left=`${rect.left+window.scrollX}px`; }); link.addEventListener('mouseout',()=>{tooltip.style.display='none';}); }); }); function updatePanel(){ const sortBy=panel.querySelector('#sort-select').value; const limit=panel.querySelector('#limit-select').value; let arr=Object.values(urlData); if(sortBy==='frequency') arr.sort((a,b)=>b.count-a.count); else if(sortBy==='name') arr.sort((a,b)=>a.url.localeCompare(b.url)); else if(sortBy==='upvotes') arr.sort((a,b)=>b.upvotes-a.upvotes); else if(sortBy==='commentaires') arr.sort((a,b)=>b.commentCount-a.commentCount); if(limit!=='all') arr=arr.slice(0,parseInt(limit)); const urlList=panel.querySelector('#url-list'); urlList.innerHTML=''; const counts=arr.map(i=>i.count); const maxC=Math.max(...counts),minC=Math.min(...counts); arr.forEach(item=>{ const li=document.createElement('li'); li.style.marginBottom='5px';li.style.wordWrap='break-word';li.style.cursor='pointer'; li.dataset.url=item.url; const r=(item.count-minC)/(maxC-minC+1); li.style.backgroundColor=r>0.66?COLORS.high:r>0.33?COLORS.medium:COLORS.low; li.innerHTML=` ${item.url} ${item.count}${item.upvotes>0?` / ${item.upvotes}`:''}${item.commentCount>0?` / ${item.commentCount}`:''} `; li.addEventListener('click',()=>{ GM_setClipboard(item.url,'text'); alert('URL copiée.'); }); urlList.appendChild(li); }); } updatePanel(); panel.querySelector('#sort-select').addEventListener('change',updatePanel); panel.querySelector('#limit-select').addEventListener('change',updatePanel); toggleButton.addEventListener('click',()=>{ if(panel.style.display==='none'){panel.style.display='block';toggleButton.textContent='Masquer les URLs';} else{panel.style.display='none';toggleButton.textContent='Afficher les URLs';} }); panel.querySelector('#copy-urls').addEventListener('click',()=>{ GM_setClipboard(Object.keys(urlData).join('\n'),'text'); alert('URLs copiées.'); }); const commentRows=document.querySelectorAll('tr.comtr'); commentRows.forEach(row=>{ const commentLink=row.querySelector('a[href^="item?id="]'); if(commentLink){ const pointsSpan=row.querySelector('.score'); const pts=pointsSpan?parseInt(pointsSpan.textContent):0; const c=row.querySelector('.commtext'); if(c){ const links=c.querySelectorAll('a[href]'); links.forEach(l=>{if(urlData[l.href]) urlData[l.href].upvotes+=pts;}); } } }); const childrenMap={}; commentRows.forEach(r=>{ const id=r.id;const pid=r.getAttribute('data-parent'); if(!pid||!id) return; if(!childrenMap[pid]) childrenMap[pid]=[]; childrenMap[pid].push(id); }); const cache={}; function size(id){ if(!childrenMap[id]) return 0; if(cache[id]!=null) return cache[id]; let s=childrenMap[id].length; childrenMap[id].forEach(k=>{s+=size(k);}); cache[id]=s;return s; } commentRows.forEach(r=>{ const id=r.id; const c=r.querySelector('.commtext'); if(!id||!c) return; const count=size(id); const links=c.querySelectorAll('a[href]'); links.forEach(l=>{if(urlData[l.href]) urlData[l.href].commentCount+=count;}); }); updatePanel(); })();