>Ironically I'm the only non degenerate on this site. I am a romantic, I want a genuine relationship with a lovely woman. Not lust.
  • Welcome. Registering and having your account be approved may take a while since there's only one guy checking and approving accounts and guestposts
  • Boards are being moved around and added. Leave feedback in this thread and let jannies move your threads

Userscripts! Userscripts? Userscripts.

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);

})();
 
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);

})();
[addscript=now]
 
Back
Top Bottom