Reddit visited link remover

hides links you already visited on reddit for a week

目前為 2014-06-19 提交的版本,檢視 最新版本

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

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

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name            Reddit visited link remover
// @version         0.6
// @namespace       [email protected]
// @description     hides links you already visited on reddit for a week
// @include         *.reddit.com/*
// @exclude         *.reddit.com/r/*/comments/*
// @exclude         *.reddit.com/user/*
// @exclude         *.reddit.com/message/*
// @exclude         *.reddit.com/reddits/*
// @exclude         *.reddit.com/prefs/*

// ==/UserScript==

// Keyboard Shortcuts:
// 
// - h: Open first unread post
// - j: Mark first unread post as read (+minimize)
// - k: Open comments of first unread post
// - u: up vote first unread post
// - m: down vote first unread post
// 
// - shift + h: Open last read post
// - shift + k: Open comments of last read post
// - shift + u: up vote last read post
// - shift + m: down vote last read post
// 
// - f: highlight read posts


var cached_links_time = 60*60*24*2; // Two days - how long should visited links be saved
var cached_links_count = 1000; // Only save this amount of links (due to performance reasons)
var fade_time = 1000; // time it takes until the visited link is completely invisible
var show_footer = true; // show how many links are currently cached at the buttom of reddit.com
var toggle_links_button = true; // show button to show / hide links (hide_links has to be true)
var hide_links = true; // removes links completely (after the next page reload)
var add_manual_hide_link = true; // adds a link to the frontpage to manually hide posts 

// ----------------------------------------------------------

if (toggle_links_button && hide_links) {
    $("body").append ('<center><div id="show_links" class="show_links"><button>Toggle links</button></div> <br></center>');
}

if (add_manual_hide_link) {
    $('ul.flat-list.buttons').append('<li><a class="manHideLink" href="#">mark as read</a></li>');
}

var stateMachine;
window.addEventListener ("load", function () {
        //console.log("Ping");
        stateMachine = new GM_LinkTrack();

        if (show_footer) {
            var numLinks    = stateMachine.GetVisitedLinkCount();
            $("body").append ('<center><p>' + numLinks + ' links cached. (max '+ cached_links_count + ')</p><br></center>');
        }
    },
    false
);

var isBlinking = 0;
document.addEventListener("keypress", function(e) {
    
    if(!e) e=window.event;

    var isShift = e.shiftKey;

    var key = e.keyCode ? e.keyCode : e.which;

    if ( key == 102 ) { // f key

        if (isBlinking === 0) {
            isBlinking = 1;
            blinking($(".shrinked"));
        } else {
            isBlinking = 0;
            clearInterval(timer);
            $(".shrinked").css({'opacity': '0.4'});
        }

    } else if (key == 106) { // j key
        // shrink next unshrinked link
        stateMachine.LinkIsNewPub(getFirstUnreadLink());
    } else if (key == 104) { // h key
        // open next unshrinked link
        var elm = getFirstUnreadLink();
        stateMachine.LinkIsNewPub(elm);
        openLink(elm);
    } else if (key == 117) { // u key
        // up vote next unshrinked link
        upVote(getFirstUnreadLink());
    } else if (key == 109) { // m key
        // down vote next unshrinked link
        downVote(getFirstUnreadLink());
    } else if (key == 107) { // k key
        // open comments of next unshrinked link
        openLinkComments(getFirstUnreadLink());

    } else if ( (key == 72) && isShift ) { // shift + h key
        // open last shrinked link
        openLink(getPreviousUnreadLink());
    }else if ( (key == 85) && isShift ) { // shift + u key
        // up vote last shrinked link
        upVote(getPreviousUnreadLink());
    } else if ( (key == 77) && isShift ) { // shift + m key
        // down vote last shrinked link
        downVote(getPreviousUnreadLink());
    } else if ( (key == 75) && isShift ) { // shift + k key
        // open comments of last shrinked link
        openLinkComments(getPreviousUnreadLink());
    }

}, true);

function blinking(elm) {
    blink();
    timer = setInterval(blink, 1000);
    function blink() {
        elm.animate({opacity:0},300,"linear",function(){
            elm.animate({opacity:1},300);
        });
    }
}

function getFirstUnreadLink() {
    var currentElement;
    $('#siteTable a.title').each(function() {
        if ( ($(this).closest('div.thing').hasClass('shrinked') === false) && ($(this).closest('div.thing').is(":hidden") === false) )  {
            currentElement = $(this);
            return false;
        }
    });
    return currentElement;
}

function getPreviousUnreadLink() {
    var previousElement;
    $('#siteTable a.title').each(function() {
        if ( ($(this).closest('div.thing').hasClass('shrinked') === true) && ($(this).closest('div.thing').is(":hidden") === false) )  {
            previousElement = $(this);
        }
    });
    return previousElement;
}

function openLink(elm) {
    var href = elm.attr('href');
    //window.location = href;
    window.open(href, '_blank');
}

function openLinkComments(elm) {
    var href = elm.closest('div.thing').find("a.comments").attr('href');
    //window.location = href;
    window.open(href, '_blank');
}

function upVote(elm) {
    elm.closest('div.thing').find("div.up, div.upmod").click();
}

function downVote(elm) {
    elm.closest('div.thing').find("div.down, div.downmod").click();
}

function GM_LinkTrack () {
    var visitedLinkArry = [];
    var numVisitedLinks = 0;
    var link_count = 0;
    var current_timestamp = new Date().getTime();

    var sortedLocalStorage = SortLocalStorage();

    // Get visited link-list from storage.
    for (var J = sortedLocalStorage.length - 1;  J >= 0;  --J) {

        var item = sortedLocalStorage[J];

        var four_weeks = cached_links_time*1000;

        // Get saved links
        if (/^Visited_\d+.*/i.test (item) ) {
            
            var regex = /^Visited_(\d+).*/;
            var old_timestamp = regex.exec(item)[1];

            var regex2 = /^Visited_\d+_(.*)/;
            var value = regex2.exec(item)[1];

            var regex3 = /^(Visited_\d+)_.*/;
            var itemName = regex3.exec(item)[1];

            //console.log(numVisitedLinks + " " + item+ " t: " + old_timestamp + " v: " + value + " n: " + itemName);

            if (value == '#') {
                localStorage.removeItem (itemName);
                break;
            }

            if (link_count >= cached_links_count) {
                localStorage.removeItem (itemName);
                //console.log(numVisitedLinks + " " + value + "t: " + timeConverter(old_timestamp));
            }
            link_count++;

            // check link age
            if ( (current_timestamp - old_timestamp) < four_weeks ) {
                visitedLinkArry.push (value);
                numVisitedLinks++;

                //console.log(numVisitedLinks + " " + localStorage[itemName] + "t: " +old_timestamp[1]);

                if (hide_links) {
                    $('a[href="' + value + '"]').closest('div.thing').fadeOut(fade_time);
                } else {
                    //$('a[href="' + localStorage[itemName] + '"]').closest('div').fadeOut(fade_time);
                    shrinkLinks($('a[href="' + value + '"]'));
                }

            } else {
                // too old, remove from storage 
                localStorage.removeItem (itemName);
            }
        }
    }

    function SortLocalStorage() {

        var localStorageArray = [];

        if(localStorage.length > 0) {
            for (i=0; i<localStorage.length; i++){
                localStorageArray[i] = localStorage.key(i)+ "_" +localStorage.getItem(localStorage.key(i));
            }
        }

        return localStorageArray.sort();
    }

    function timeConverter(UNIX_timestamp) {
     var a = new Date(UNIX_timestamp*1000);
     var months = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
         var year = a.getFullYear();
         var month = months[a.getMonth()];
         var date = a.getDate();
         var hour = a.getHours();
         var min = a.getMinutes();
         var sec = a.getSeconds();
         var time = date+','+month+' '+year+' '+hour+':'+min+':'+sec ;
         return time;
    }

    function ShowLinks () {
        for (var J = localStorage.length - 1;  J >= 0;  --J) {
            var itemName    = localStorage.key (J);
            //console.log("Ping");
       
            // Get saved links
            if (/^Visited_\d+$/i.test (itemName) ) {
                
                $('a[href="' + localStorage[itemName] + '"]').closest('div.thing').fadeToggle(fade_time);
            
            }
        }
    }

    this.LinkIsNewPub = function (linkObj) {
        LinkIsNew(linkObj);
    };

    function LinkIsNew (linkObj) {
        var href = linkObj.attr('href');

        if (visitedLinkArry.indexOf (href) == -1) {
            visitedLinkArry.push (href);
        
            var timestamp = new Date().getTime();

            var itemName    = 'Visited_' + timestamp;
            localStorage.setItem (itemName, href);
            numVisitedLinks++;
            
            // Hide links imideately after klicked. Makes it impossible to see commenst afterward.
            //$('a[href="' + href + '"]').closest('div').fadeOut(fade_time);

            shrinkLinks(linkObj);

            return true;
        } else {
            console.log(visitedLinkArry.indexOf (href));
        }
        return false;
    }

    function shrinkLinks (linkObj) {

        // Alter the look of clicked links imideately
        var mainLinkElement = linkObj.closest('div.thing');

        // Remove elements that are nor needed in the smll view
        mainLinkElement.find('p.tagline').remove();
        mainLinkElement.find('a.thumbnail').hide(fade_time, function () {
            $(this).remove();
        });
        mainLinkElement.find('span.domain').remove();
        mainLinkElement.find('div.expando-button').remove();

        mainLinkElement.find('li a.manHideLink').remove();


        // Realign elements for the small view
        var animObj = {"queue": false, "duration": fade_time};

        mainLinkElement.find('p.title').css({'float': 'left', 'font-size': '9px', 'margin-left': '10px', 'font-weight': 'normal', 'margin-top': '4px'});

        mainLinkElement.find('a.title').animate({'font-size': '9px'}, animObj);
        mainLinkElement.find('ul.flat-list.buttons').animate({'margin-left': '10px', 'font-size': '9px', 'margin-top': '3px'}, animObj);
        mainLinkElement.find('span.rank').animate({'margin-top': '1px', 'font-size': '10px'}, animObj);

        mainLinkElement.find('div.midcol').animate({'width': '90px'}, animObj);
        mainLinkElement.find('div.arrow').css({'float': 'left'});

        mainLinkElement.find('div.score').css({'float': 'left'});
        mainLinkElement.find('div.score').animate({'font-size': '10px', 'padding-left': '10px', 'padding-right': '10px', 'margin-top': '3px', 'width': '30px'}, animObj);

        mainLinkElement.css({'padding-left': '50px', 'opacity': '0.4', 'margin': '2px'});

        mainLinkElement.addClass('shrinked');

        return true;
    }
    
    this.GetVisitedLinkCount = function () {
        return numVisitedLinks;
    };
    
    $('a.title').click(function() {
        LinkIsNew($(this));
    });
    
    if (toggle_links_button && hide_links) {
        $('#show_links button').click (function() {
            ShowLinks();
        });
    }

    if (add_manual_hide_link) {
        $('a.manHideLink').click (function(event) {
            event.preventDefault();
            var $titleLink = $(this).closest('div.thing').find('a.title');

            LinkIsNew($titleLink);
        });
    }
}