shipment
You're here forever.
- Joined
- Apr 20, 2025
- Messages
- 18,048
Got this hunk of junk working just a moment ago that adds 'ru-esque instant thread updates. This removes the need to refresh and check notifications as to update threads.
Fixed.
JavaScript:// ==UserScript== // @name Soyjak.forum Live New Posts // @namespace https://greasyfork.org/ // @version 8.1.1 // @description Polls XenForo for new thread posts every 5 seconds on the newest page only. // @author You // @match https://soyjak.forum/threads/* // @match https://*.soyjak.forum/threads/* // @grant none // @run-at document-idle // ==/UserScript== (function(){'use strict'; const INTERVAL=5000; let busy=false; const log=(...args)=>console.log('[Soyjak Live]',...args); const getPosts=()=>[...document.querySelectorAll('.message.message--post')]; function getLastTimestamp(){ const posts=getPosts(); if(!posts.length)return null; const time=posts.at(-1).querySelector('time[data-timestamp]'); if(!time){ log('No timestamp found in last post:',posts.at(-1)); return null; } const timestamp=Number(time.getAttribute('data-timestamp')); return Number.isFinite(timestamp)?timestamp:null; } function getCurrentPage(){ const match=location.pathname.match(/\/page-(\d+)\/?$/); return match?Number(match[1]):1; } function getPageNumber(href){ if(!href)return null; try{ const url=new URL(href,location.href); const match=url.pathname.match(/\/page-(\d+)\/?$/); return match?Number(match[1]):1; }catch{ return null; } } function getLastPage(){ const current=getCurrentPage(); const pages=[]; document.querySelectorAll('.pageNav a[href]').forEach(link=>{ const page=getPageNumber(link.getAttribute('href')); if(Number.isFinite(page))pages.push(page); }); document.querySelectorAll('.pageNav-page,.pageNav-page--current').forEach(el=>{ const text=el.textContent.trim(); if(/^\d+$/.test(text))pages.push(Number(text)); }); return pages.length?Math.max(current,...pages):current; } function isLastPage(){ const current=getCurrentPage(); const last=getLastPage(); log(`Pagination: current page ${current}, detected last page ${last}`); return current>=last; } function getNewPostsURL(after){ const url=new URL(location.href); url.pathname=url.pathname.replace(/\/page-\d+\/?$/,'/'); url.pathname=url.pathname.replace(/\/$/,'/new-posts'); url.search=''; url.searchParams.set('after',after); return url.href; } async function poll(){ if(busy||!isLastPage())return; const after=getLastTimestamp(); if(!after){ log('Could not determine last post timestamp.'); return; } busy=true; try{ const url=getNewPostsURL(after); log('Checking:',url); const response=await fetch(url,{ method:'GET', credentials:'same-origin', cache:'no-store', headers:{'X-Requested-With':'XMLHttpRequest'} }); if(!response.ok)throw new Error(`HTTP ${response.status}`); const doc=new DOMParser().parseFromString( await response.text(), 'text/html' ); const newPosts=[ ...doc.querySelectorAll('.message.message--post') ]; if(!newPosts.length){ log('No new posts.'); return; } const container=document.querySelector('.block--messages'); if(!container){ log('Could not find message container.'); return; } const existingIds=new Set(getPosts().map(post=>post.id)); const freshPosts=newPosts.filter(post=>!existingIds.has(post.id)); if(!freshPosts.length){ log('Posts were already present.'); return; } const atBottom= window.innerHeight+window.scrollY>= document.documentElement.scrollHeight-500; let insertAfter=getPosts().at(-1); for(const post of freshPosts){ const imported=document.importNode(post,true); if(insertAfter) insertAfter.insertAdjacentElement('afterend',imported); else container.appendChild(imported); if(typeof XF!=='undefined'&&typeof XF.activate==='function') XF.activate(imported); insertAfter=imported; } log(`Inserted ${freshPosts.length} new post(s).`); if(atBottom) window.scrollTo({ top:document.documentElement.scrollHeight, behavior:'smooth' }); }catch(error){ log('Error:',error); }finally{ busy=false; } } if(!document.querySelector('.message.message--post'))return; if(!isLastPage()){ log('Not on the newest page. Live polling disabled.'); return; } log('Started. Polling every 5 seconds.'); setTimeout(poll,1000); setInterval(poll,INTERVAL); })();
Last edited: