redsave

adds feature in libreddit/redlib to save/unsave posts, which is saved in localStorage as post ids (won't work over incognito sessions)

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         redsave
// @namespace    http://tampermonkey.net/
// @version      1
// @description  adds feature in libreddit/redlib to save/unsave posts, which is saved in localStorage as post ids (won't work over incognito sessions)
// @author       @yokelman
// @match        https://libreddit.kavin.rocks/*
// @icon         https://libreddit.kavin.rocks/favicon.ico
// @grant        none
// @license      GNU AGPL-3.0
// ==/UserScript==

(function() {
    // !!!!!! THE SCRIPT CAN ACT WEIRDLY IF USING MULTIPLE TABS TO BROWSE THE SITE SINCE AFAIK LOCALSTORAGE ISN'T SYNCHRONIZED IN REAL TIME TO WORK ACROSS MULTIPLE TABS
    // !!!!!! EXAMPLE: IF YOU SAVE POST A AND B ON THE MAIN PAGE, THEN OPEN POST A ON A NEW TAB, THEN UNSAVE POST B ON THE MAIN PAGE TAB AND THEN UNSAVE POST A THROUGH THE NEWLY OPENED TAB (WHICH ONLY CONTAINS A)...
    // !!!!!! POST B (WHICH SHOULD HAVE BEEN UNSAVED THROUGH MAIN PAGE TAB) WILL STILL BE IN LOCALSTORAGE
    // !!!!!! MORAL: DON'T GO SAVING/UNSAVING ON MULTIPLE PAGES AS FAR AS POSSIBLE, AND AFTER SAVING/UNSAVING ON ONE TAB IDEALLY RELOAD ALL THE OTHER TABS

    // tested on v0.30.1, v0.31.0, v0.31.2, v0.34.0 on both libreddit and redlib which should be the majority of public instances

    'use strict';

    var domain = "https://libreddit.kavin.rocks/";

    // load savedPosts from localStorage and handle if empty
    var savedPosts = window.localStorage.getItem("savedPosts");
    if (!savedPosts) {
        savedPosts = [];
    }
    else {
        savedPosts = savedPosts.split(",");
        // if localStorage has savedPosts="", splitting gives you [""], don't want that empty string as an element
        if (!savedPosts[0]) {
            savedPosts.splice(0);
        }
    }

    // adds an option to view saved posts when user clicks on Feeds at top left corner (if saved posts exist)
    if (savedPosts.length) {
        var link = document.createElement("a");
        link.textContent = "Saved";
        link.onclick = showSaved;
        if (document.getElementById("feed_list").querySelectorAll("p").length == 2) {
            document.getElementById("feed_list").insertBefore(link, document.getElementById("feed_list").children[4]);
        }
        else {
            document.getElementById("feed_list").appendChild(link);
        }
    }

    // manage saving/unsaving when save/unsave button is clicked
    function manageSaved(id) {
        if (document.getElementsByClassName(id)[0].textContent == "save") {
            savedPosts.push(id);
            document.getElementsByClassName(id)[0].textContent = "unsave";
        }
        else {
            savedPosts.splice(savedPosts.indexOf(id), 1);
            document.getElementsByClassName(id)[0].textContent = "save";
        }
        window.localStorage.setItem("savedPosts", savedPosts);
    }

    var post_footer = document.getElementsByClassName("post_footer");

    // go post by post and add the save/unsave element
    for (var i = 0; i < post_footer.length; i++) {
        var save = document.createElement("a");
        // the below is basically a somehow-works hack to get the post id (because the page could either have a collection of posts, or just a single post and i don't want to code for different cases) - can definitely lead to errors if site layout changes
        var postId = post_footer[i].querySelector("a").href.split("/")[6];
        if ((savedPosts.includes(postId))) {
            save.textContent = "unsave";
        }
        else {
            save.textContent = "save";
        }
        save.style = "font-weight: bold;";
        save.className = post_footer[i].querySelector("a").href.split("/")[6];
        (function(localPostId) {save.onclick = function() {manageSaved(localPostId);};})(postId);
        // if url includes comments, it means you're viewing an individual post (hopefully there's no loophole in this)
        if (!window.location.href.includes("comments")) {
            post_footer[i].appendChild(save);
        }
        else {
            document.getElementById("post_links").appendChild(save);
        }
    }

    // function to make a div (manipulate the existing div tbh) to show all the saved posts
    // function is async so posts will show in chronological order but it's a compromise for speed as posts load one by one (speed depends on your network and libreddit/redlib server chosen)
    async function showSaved() {
        if (window.location.href != domain) {
            alert("You can only see Saved posts from home page. Try from there.");
        }
        else {
            if (!savedPosts.length) {
                alert("No saved posts yet. Go ahead and save some!");
            }
            else {
                // no pagination for now
                if (document.querySelectorAll("footer").length == 2) {
                    document.querySelector("footer").remove();
                }
                if (document.querySelectorAll("form").length == 2) {
                    document.querySelectorAll("form")[1].remove();
                }
                document.title = "loading saved...";
                var postPage;
                var hr = document.createElement("hr");
                hr.className = "sep";
                document.getElementById("posts").innerHTML = "";

                for (var j = savedPosts.length - 1; j > -1; j--) {
                    document.getElementById("posts").appendChild(hr);
                    await fetch(domain + "comments/" + savedPosts[j])
                        .then(response => {return response.text();})
                        .then(html => {postPage = new DOMParser().parseFromString(html, "text/html");
                                       document.getElementById("posts").appendChild(postPage.getElementsByClassName("post")[0]);
                                       console.log(j);
                                       document.getElementsByClassName("post")[document.getElementsByClassName("post").length - 1].id = savedPosts[j];})
                        .catch(err => console.error("Error occurred: " + err));
                }
                for (var k = 0; k < savedPosts.length; k++) {
                    var save = document.createElement("a");
                    save.style = "font-weight: bold;";
                    save.className = savedPosts[k];
                    save.textContent = "unsave";
                    (function(index) {save.onclick = function() {manageSaved(savedPosts[index]);};})(k);
                    document.getElementById(savedPosts[k]).querySelector(".post_footer").children[0].appendChild(save);
                }
                document.title = "saved";
            }
        }
    }
})();