Random reddit post

Load a random reddit post from your subs

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Random reddit post
// @description  Load a random reddit post from your subs
// @license      MIT
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Random reddit post
// @author       John
// @match        https://old.reddit.com/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @run-at     document-idle
// @grant       GM_registerMenuCommand
// @grant       GM_getValue
// @grant       GM_setValue
// ==/UserScript==
// a == random subreddit post
// s == random post

const verbose = true;
const LOG_PREFIX = "[Random Reddit]:";

function navigate(currentDoc, path) {
    if (verbose) console.log(LOG_PREFIX, "Navigating to:", path);
    currentDoc.location = path;
}

function createButton(name) {
    let btn = document.createElement("a");
    btn.innerHTML = name;
    btn.style = "text-decoration: none; font-size: 1.4em"
    btn.style.padding = "3px 3px 3px 3px";
    // btn.style.border = "thick solid #FFFFFF";
    // btn.style.margin = "3px 3px 3px 3px";
    btn.href = "javascript:void(0)"
    let div = document.getElementById("header-bottom-right");
    if (div) {
        div.insertBefore(btn, div.firstChild);
    } else {
        if (verbose) console.log(LOG_PREFIX, "header not ready");
    }
    return btn;
}
function updateImages() {
    let maxHeight = window.innerHeight / 2.5;
    let width = '100%';

    let linkElements = document.getElementsByClassName("link");

    for (let linkElement of linkElements) {
        // linkElement.marginBottom = '10px';
        // linkElement.width = width;
        // linkElement.style.maxWidth = width;
        // linkElement.style.width = width;
    }

    let thumbnailElements = document.getElementsByClassName("thumbnail");
    // if (verbose) console.log(LOG_PREFIX, "thumbnails:", thumbnailElements)

    for (let thumbnailElement of thumbnailElements) {
        // thumbnailElement.style.maxWidth = width;
        thumbnailElement.style.width = "20%";
        // thumbnailElement.style.width = 'auto';
        // thumbnailElement.style.height = 'auto';
        // thumbnailElement.style.height = '100px';
        // thumbnailElement.width = '600px';
        // thumbnailElement.marginBottom = '20%';
        let img = thumbnailElement.childNodes.item("");
        if (img) {
            var url = thumbnailElement.parentElement.getAttribute("data-url")
            // if (verbose) console.log(LOG_PREFIX, "url:", url)
            if (url != undefined && url != null &&
                (url.includes(".jpg")
                || url.includes(".png")
                || url.includes(".jpeg"))
                ) {
                // if (verbose) console.log(LOG_PREFIX, "Setting url:", url)
                img.src = url;
            }
            // console.log(LOG_PREFIX, "img:", img)
            // img.style.maxHeight = '100%';
            // img.maxWidth = width;
            // img.width = width;
            img.style.maxWidth = width;
            img.style.width = width;
            // img.style.width = '640px';
            // img.style.width = '600px';
            // img.style.maxHeight = '70%';
            img.style.height = 'auto';
            img.style.maxHeight = `${maxHeight}px`;
            img.style.objectFit = 'contain';
        } else {
            // console.log(LOG_PREFIX, "No img");
        }
    }
}

function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
}

// Blacklist, useful when overloaded with one subreddit
const BLACKLIST_SR = [
    "hentai"
];

function parsePosts(posts, filterMedia, startTime, getParams) {
    const prefix = window.location.protocol + "//" + window.location.host;
    if (filterMedia) {
        posts = posts.filter(function (post) {
            var isCrosspostVideo = false;
            var crosspostParent = post.data.crosspost_parent_list || undefined;
            // console.log("Post:", post)
            try {
                while (crosspostParent != undefined) {
                    crosspostParent = crosspostParent[0];
                    // console.log("Crosspost parent:", crosspostParent);
                    var postHint = crosspostParent.post_hint || "";
                    var url = crosspostParent.url || crosspostParent.link_url;
                    if (postHint.includes("video") || url.includes(".mp4") || url.includes(".gif")) {
                        isCrosspostVideo = true;
                        console.log("isCrosspostVideo:", isCrosspostVideo)
                        break;
                    }
                    crosspostParent = crosspostParent.crosspost_parent_list || undefined;
                }
            } catch (e) { }
            var postHint = post.data.post_hint || "";
            var url = post.data.url || post.data.link_url;
            // console.log("Post:", postHint, url, post.data);
            // console.log("isCrosspostVideo 2:", isCrosspostVideo)
            // console.log("Post:", post.data.subreddit);
            var isValidPost = BLACKLIST_SR.some((sr) => window.location.href.includes(sr)) || !BLACKLIST_SR.includes(post.data.subreddit);
            return (postHint.includes("video") || url.includes(".mp4") || url.includes(".gif") || isCrosspostVideo || post.data.media) && isValidPost;
        });
        if (verbose) console.log(LOG_PREFIX, 'Filter animated: ', posts);
    }
    if (verbose) console.log(LOG_PREFIX, 'Media posts: ', posts);
    if (posts.length > 0) {
        shuffleArray(posts);
        var randPost = posts[Math.floor(Math.random()*posts.length)];
        // var randPostLink = prefix + randPost.data.permalink + `?${PREFIX_KEY}=` + (getParams || "");
        var randPostLink = prefix + randPost.data.permalink + (getParams || "");
        // console.log(LOG_PREFIX, randPost, randPostUrl);
        if (verbose) console.log(LOG_PREFIX, "Random post link:", randPostLink);
        navigate(document, randPostLink);
    } else {
        $("body").css("cursor", "default");
        console.log("No media post")
    }
    var endTime = performance.now();
    if (verbose) console.log(`Random post time taken: ${endTime - startTime} milliseconds`);
}

const PREFIX_KEY="prefix"
const SEARCH_KEY="q"

function randomPost(extraPath, filterMedia, getParams, onlyTop) {
    var startTime = performance.now()
    $("body").css("cursor", "progress");
    if (verbose) console.log(LOG_PREFIX, "Random post:", extraPath, ", filter:", filterMedia, ", prefix:", getParams, ", only top:", onlyTop);

    const durationArray = ["all", "month", "week", "year"];
    var duration = durationArray[Math.floor(Math.random()*durationArray.length)];
    if (extraPath.startsWith("saved")) {
        duration = "all";
    }

    // const sortArray = ["top", "new", "hot", "gilded"];
    var sortArray = ["top", "new", "hot"];
    var sortArrayWeights = [8, 2, 5];
    if (onlyTop) {
        sortArray = ["top"];
        sortArrayWeights = [1];
    }
    // var sortType = sortArray[Math.floor(Math.random()*sortArray.length)];
    var sortType = "";
    const savedPath = extraPath.startsWith("saved")
    if (!savedPath) {
        sortType = weighted_random(sortArray, sortArrayWeights);
    }
    // const maxPostLimit = 100;
    // const minPostLimit = 25;
    // var postLimit = Math.floor(Math.random() * (maxPostLimit - minPostLimit + 1)) + minPostLimit;
    var postLimit = 100;
    if (verbose) console.log(LOG_PREFIX, "Sort type:", sortType, "post limit:", postLimit);

    var fetchUrl = `https://old.reddit.com/` + extraPath;
    fetchUrl += `${sortType}.json?`;
    if (getParams && getParams.includes("q")) {
        // Search
        fetchUrl = `https://old.reddit.com/` + `${extraPath}.json` + getParams + `&sort=${sortType}`;
    }
    fetchUrl += `&t=all&limit=${postLimit}`;
    if (verbose) console.log(LOG_PREFIX, "Fetch 1:", fetchUrl);
    fetch(fetchUrl)
        .then(result => result.json())
        .then((output) => {
            if (verbose) console.log(LOG_PREFIX, 'Output: ', output);
            var posts = output.data.children;
            var lastPost = posts.at(-1);
            console.log("Last path:", lastPost.data.name);
            
            var fetchUrl = `https://old.reddit.com/` + extraPath;
            fetchUrl += `${sortType}.json?`;
            if (getParams && getParams.includes("q")) {
                // Search
                fetchUrl = `https://old.reddit.com/` + `${extraPath}.json` + getParams + `&sort=${sortType}`;
            }
            fetchUrl += `&t=${duration}&limit=${postLimit}&after=${lastPost.data.name}`;
            if (verbose) console.log(LOG_PREFIX, "Fetch 2:", fetchUrl);
            fetch(fetchUrl)
                .then(result => result.json())
                .then((output) => {
                    if (verbose) console.log(LOG_PREFIX, 'Output: ', output);
                    // var posts = output.data.children;
                    // console.log(LOG_PREFIX, 'All posts: ', posts);
                    posts = posts.concat(output.data.children);
                    // console.log(LOG_PREFIX, 'All posts: ', posts);
                    // if (savedPath) {
                        var lastPost = posts.at(-1);
                        console.log("Last path:", lastPost.data.name);

                        var fetchUrl = `https://old.reddit.com/` + extraPath;
                        fetchUrl += `${sortType}.json?`;
                        if (getParams && getParams.includes("q")) {
                            // Search
                            fetchUrl = `https://old.reddit.com/` + `${extraPath}.json` + getParams + `&sort=${sortType}`;
                        }
                        fetchUrl += `&t=${duration}&limit=${postLimit}&after=${lastPost.data.name}`;
                        if (verbose) console.log(LOG_PREFIX, "Fetch 3:", fetchUrl);
                        fetch(fetchUrl)
                            .then(result => result.json())
                            .then((output) => {
                                if (verbose) console.log(LOG_PREFIX, 'Output: ', output);
                                // var posts = output.data.children;
                                posts = posts.concat(output.data.children);
                                // console.log(LOG_PREFIX, 'All posts: ', posts);
                                parsePosts(posts, filterMedia, startTime, getParams);
                        }).catch(err => console.error(err))
                    // } else {
                    //     parsePosts(posts, filterMedia, startTime);
                    // }
            }).catch(err => console.error(err))
    }).catch(err => console.error(err))
}

function openInNewTab(url) {
    window.open(url, '_blank').focus();
}
function openFirstVideo() {
    // Tries to open first video element
    var titleElements = document.getElementsByClassName("title");
    for (let titleElement of titleElements) {
        try {
            if (titleElement.tagName == "A") {
                var videoLink = titleElement.href || titleElement.data-href-url;
                console.log("Opening video:", videoLink);
                // navigate(document, videoLink);
                openInNewTab(videoLink);
                break;
            }
        } catch (e) {
            console.error("Failed to open video:", e);
        }
    }
}

if (!window.location.pathname.includes("comments")) {
    var interval = setInterval(function(){
        updateImages();
    }, 1000);
} else {
    var maxHeight = 550;
    var maxWidth = 300;
    try {
        var items = document.getElementsByClassName("expando");
        // items[0].style.maxWidth = "100px";
        // items[0].style.maxHeight = "1139px";
        // items[0].style.maxHeight = "600px";
        // // items[0].style.maxWidth = "811px";
        // items[0].style.maxWidth = "300px";
        items[0].style.maxHeight = `${maxHeight}px`;
        // items[0].style.maxWidth = `${maxWidth}px`;
    } catch (e) {
        // console.error("Failed to set video width:", e);
    }
    function allDescendants (node) {
        try {
            for (var i = 0; i < node.childNodes.length; i++) {
            var child = node.childNodes[i];
                allDescendants(child);
                child.style.maxHeight = `${maxHeight}px`;
                // child.style.maxWidth = `${maxWidth}px`;
                // child.style.maxHeight = "600px";
                // child.style.maxWidth = "300px";
            }
        } catch (e) {
            // console.error("Failed to set video width:", e);
        }
    }
    allDescendants(items[0]);

    console.log("items:", items)
    var videoList = document.getElementsByTagName("video");
    console.log("Videos:", videoList)
    for (var e of videoList) {
        // e.setAttribute('style', "width: 100px; height: 100px");
        try {
            // var newHeight = document.body.clientHeight * 0.75;
            // console.log("New height:", newHeight);
            // e.parentElement.parentElement.parentElement.style = `height: ${newHeight}px` 
            var videoWidth = e.parentElement.parentElement.parentElement.offsetWidth;
            e.setAttribute('style', `width: ${videoWidth}px`);
            console.log("New videoWidth:", videoWidth);
        } catch (e) {
            console.error("Failed to set video width:", e);
        }
    }
}

// var videoList = document.getElementsByTagName("video");
// console.log("Videos:", videoList)
// for (var e of videoList) {
//     // e.setAttribute('style', "width: 100px; height: 100px");
//     try {
//         var newHeight = document.body.clientHeight * 0.75;
//         console.log("New height:", newHeight);
//         e.parentElement.parentElement.parentElement.style = `height: ${newHeight}px` 
//         var videoWidth = e.parentElement.parentElement.parentElement.offsetWidth;
//         e.setAttribute('style', `width: ${videoWidth}px`);
//     } catch (e) {
//         console.error("Failed to set video width:", e);
//     }
// }
// window.addEventListener('load', function() {
//     console.log("Window loaded");
//     setTimeout(function(){}, 1000)
//     var videoList = document.getElementsByTagName("video");
//     console.log("Videos:", videoList)
//     for (var e of videoList) {
//         // e.setAttribute('style', "width: 100px; height: 100px");
//         try {
//             var newHeight = document.body.clientHeight * 0.75;
//             console.log("New height:", newHeight);
//             e.parentElement.parentElement.parentElement.style = `height: ${newHeight}px` 
//             // var videoWidth = e.parentElement.parentElement.parentElement.offsetWidth;
//             // e.setAttribute('style', `width: ${videoWidth}px`);
//         } catch (e) {
//             console.error("Failed to set video width:", e);
//         }
//     }
// });

    // var observer = new MutationObserver(function(mutations) {
    //     console.log("Mutations:", mutations)
    //     // if (document.contains(myElement)) {
    //     //     console.log("It's in the DOM!");
    //     //     observer.disconnect();
    //     // }
    //     setTimeout(function(){}, 1000)
    //     var videoList = document.getElementsByTagName("video");
    //     for (var e of videoList) {
    //         // e.setAttribute('style', "width: 100px; height: 100px");
    //         try {
    //             var newHeight = document.body.clientHeight * 0.75;
    //             console.log("New height:", newHeight);
    //             e.parentElement.parentElement.parentElement.style = `height: ${newHeight}px` 
    //             // var videoWidth = e.parentElement.parentElement.parentElement.offsetWidth;
    //             // e.setAttribute('style', `width: ${videoWidth}px`);
    //         } catch (e) {
    //             console.error("Failed to set video width:", e);
    //         }
    //     }
    // });
    
    // observer.observe(document, {attributes: false, childList: true, characterData: false, subtree:true});
    // observer.observe(document, {attributes: true, childList: true, characterData: false, subtree:true});
 

// window.addEventListener('load', function() {
    const randSavedPostBtn = createButton("Saved (Q)");
    randSavedPostBtn.onclick = () => {
        randomPost("saved/");
    };
    const randSavedMediaPostBtn = createButton("Media saved (W)");
    randSavedMediaPostBtn.onclick = () => {
        randomPost("saved/", filterMedia = true);
    };
    const randPostBtn = createButton("Rand post (S)");
    randPostBtn.onclick = () => {
        randomPost("");
    };
    var randSrPostPath = "";
    if (window.location.pathname != "/") {
        var pathArray = window.location.pathname.split('/');
        const randSrPostBtn = createButton("Sr post (A)");
        randSrPostBtn.onclick = () => {
            randomPost(`r/${pathArray[2]}/`);
        };
    }
    const randMediaPostBtn = createButton("Media (B)");
    randMediaPostBtn.onclick = () => {
        randomPost("", filterMedia = true);
    };
    if (window.location.pathname != "/") {
        var pathArray = window.location.pathname.split('/');
        const randSrMediaPostBtn = createButton("Media sr (V)");
        randSrMediaPostBtn.onclick = () => {
            randomPost(`r/${pathArray[2]}/`, filterMedia = true);
        };
    }
    const openVideoBtn = createButton("Open video");
    openVideoBtn.onclick = () => {
        openFirstVideo();
    };


    document.onkeyup = function (e) {
        console.log("event:", e);
        e = e || window.event;
        var charCode = e.charCode || e.keyCode,
            character = String.fromCharCode(charCode);

        var tagName = e.target.nodeName.toLowerCase();
        // if (tagName == "input" || tagName == "textarea" || e.shiftKey || e.ctrlKey) {
        if (tagName == "input" || tagName == "textarea" || e.ctrlKey) {
            if (verbose) console.log(LOG_PREFIX, "Ignoring input");
            return;
        }
        if (e.code === 'Enter' && e.ctrlKey) {
        // if (e.code === 'Enter') {
            openFirstVideo();
            return;
        }
        const onlyTop = !e.shiftKey;

        if (verbose) console.log(LOG_PREFIX, "Key press:", character);
        if (character.toUpperCase() == 'A') {
            if (window.location.pathname != "/") {
                var pathArray = window.location.pathname.split('/');
                if (window.location.pathname.endsWith("search")) {
                    // var path = parse_query_string(window.location.search.substring(1))[SEARCH_KEY]
                    var prefix = window.location.search + `&${PREFIX_KEY}=${window.location.pathname}`
                    randomPost(`${window.location.pathname}`, true, prefix, onlyTop);
                } else if (window.location.search.includes(PREFIX_KEY)) {
                    var path = parse_query_string(window.location.search.substring(1))[PREFIX_KEY]
                    randomPost(`${path}`, true, window.location.search, onlyTop);
                } else if (window.location.pathname.includes("user/") && window.location.pathname.includes("m/")) {
                    // 1 to 4
                    var path = pathArray.slice(1,5).join("/")
                    randomPost(`${path}/`, null, `?${PREFIX_KEY}=${window.location.pathname}`, onlyTop);
                } else {
                    randomPost(`r/${pathArray[2]}/`, null, null, onlyTop);
                }
            }
        }
        if (character.toUpperCase() == 'S') {
            randomPost("", null, null, onlyTop);
        }
        if (character.toUpperCase() == 'V') {
            if (window.location.pathname != "/") {
                var pathArray = window.location.pathname.split('/');
                if (window.location.pathname.endsWith("search")) {
                    // var path = parse_query_string(window.location.search.substring(1))[SEARCH_KEY]
                    var prefix = window.location.search + `&${PREFIX_KEY}=${window.location.pathname}`
                    randomPost(`${window.location.pathname}`, filterMedia = true, prefix, onlyTop);
                } else if (window.location.search.includes(PREFIX_KEY)) {
                    var path = parse_query_string(window.location.search.substring(1))[PREFIX_KEY]
                    randomPost(`${path}`, true, window.location.search, onlyTop);
                } else if (window.location.pathname.includes("user/") && window.location.pathname.includes("m/")) {
                    // 1 to 4
                    var path = pathArray.slice(1,5).join("/")
                    randomPost(`${path}/`, true, `?${PREFIX_KEY}=${window.location.pathname}`, onlyTop);
                } else {
                    randomPost(`r/${pathArray[2]}/`, filterMedia = true, undefined, onlyTop);
                }
            }
        }
        if (character.toUpperCase() == 'B') {
            randomPost("", filterMedia = true, undefined, onlyTop);
        }
        if (character.toUpperCase() == 'Q') {
            randomPost("saved/", null, null, onlyTop);
        }
        if (character.toUpperCase() == 'W') {
            randomPost("saved/", filterMedia = true, null, onlyTop);
        }
    };
// }, false);


function parse_query_string(query) {
    var vars = query.split("&");
    var query_string = {};
    for (var i = 0; i < vars.length; i++) {
        var pair = vars[i].split("=");
        var key = decodeURIComponent(pair.shift());
        var value = decodeURIComponent(pair.join("="));
        // If first entry with this name
        if (typeof query_string[key] === "undefined") {
        query_string[key] = value;
        // If second entry with this name
        } else if (typeof query_string[key] === "string") {
        var arr = [query_string[key], value];
        query_string[key] = arr;
        // If third or later entry with this name
        } else {
        query_string[key].push(value);
        }
    }
    return query_string;
}

// https://old.reddit.com/r/javascript/top.json?t=all

// &sort=desc

// &limit=250

function weighted_random(items, weights) {
    var i;

    for (i = 0; i < weights.length; i++)
        weights[i] += weights[i - 1] || 0;
    
    var random = Math.random() * weights[weights.length - 1];
    
    for (i = 0; i < weights.length; i++)
        if (weights[i] > random)
            break;
    
    return items[i];
}


function toggleHentai() {
    console.log("toggleHentai");
    var enableHentai = GM_getValue("enable_hentai");
    if (!enableHentai) {
        console.log("init enableHentai")
        GM_setValue("enable_hentai", true);
        enableHentai = true;
    }
    console.log("enableHentai:", enableHentai)
    // [].forEach.call(
    //     ['contextmenu', 'copy', 'cut', 'paste', 'mouseup', 'mousedown', 'keyup', 'keydown', 'drag', 'dragstart', 'select', 'selectstart'],
    //     function(event) {
    //         document.addEventListener(event, function(e) { e.stopPropagation(); }, true);
    //     }
    // );
}

function enableCommandMenu() {
    var commandMenu = true;
    try {
        if (typeof(GM_registerMenuCommand) == undefined) {
            return;
        } else {
            if (commandMenu == true ) {

                GM_registerMenuCommand('Toggle Hentai', function() {
                    toggleHentai();
                });
            }
        }
    }
    catch(err) {
        console.log(err);
    }
}

function init() {
    enableCommandMenu();}

init();

// $("body").css("cursor", "default");

// var prefix = "https://old.reddit.com/";
// var sortArray = ["top", "new", "hot", "gilded"];
// var sortType = sortArray[Math.floor(Math.random()*sortArray.length)];
// // var sortArrayWeights = [8, 3, 4, 4];
// // var sortType = weighted_random(sortArray, sortArrayWeights);
// console.log("Sort type:", sortType);
// fetch(`https://old.reddit.com/r/javascript/${sortType}.json?t=all&limit=250`)
//     .then(result => result.json())
//     .then((output) => {
//         console.log('Output: ', output);
//         var posts = output.data.children;
//         posts = posts.filter(function (post) {
//             var postHint = post.data.post_hint || "";
//             var url = post.data.url || post.data.link_url;
//             console.log("Post:", postHint, url, post.data);
//             return postHint.includes("video") || url.includes(".mp4") || url.includes(".gif");
//         });
//         if (posts.length > 0) {
//             var randPost = posts[Math.floor(Math.random()*posts.length)];
//             var randPostLink = prefix + randPost.data.permalink;
//             console.log(randPost, randPostLink);
//         } else {
//             console.log("No media post")
//         }
// }).catch(err => console.error(err));


//https://old.reddit.com/r/javascript/top.json?t=all