// ==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);
})();
[addscript=now]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); })();
No Cargo I am Coder I am not an Amerimutt[addscript=now]
Fuck youNo Cargo I am Coder I am not an Amerimutt