Sakuto / Unique Post

// ==UserScript==
// @name        Unique Post
// @author      Sakuto
// @namespace   http://www.sakuto.be
// @description This userscript will allow you to stop showing multiple time thread in "Your Posts"
// @include     *hackforums.net/*
// @version     0.54

// @grant       GM_xmlhttpRequest
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_notification
// @grant       GM_openInTab
// @grant       GM_addStyle

// @require     https://raw.github.com/sizzlemctwizzle/GM_config/master/gm_config.js
// @require     http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js
// ==/UserScript==

// == To do List == 
// - Supprimer le tupple dans addink
// - Ajouter liens sur les listes li
// - Fixer le bug du lien quand point en dernier
// - Optimiser chargement des resultats via un buffer
// - Ignorer certaines catégories
// - Ignorer les sujets fermés
// - Ajout de template de post automatique
//      - Afficher les templates au dessus de la zone de post
// - Scammer database -> Application directement sur la userbar
// - Implémenter bouton de dons ?
// == Fin To Do ==  

var predefinedStyle = "\
    #HFU_config {background:#333; color:#CCC; font-size:14px; } \
	#HFU_config_header {color:#FFF; padding-bottom: 20px;} \
    #HFU_config .section_desc {background:#072948; color:#FFF; border:none; font-size:14px;} \
    #HFU_config .section_header {display:none !important;} \
    #HFU_config .config_var {text-align:left;} \
    #HFU_config .field_label {font-size:14px; font-weight:normal} \
    #HFU_config * {font-family:Verdana, Arial, Sans-Serif; font-weight:normal}\
	#HFU_config label { display: inline-block; width: 400px;}\
";

var linkList = [];
var storedLine = [];

GM_config.init(
{
    'id': 'HFU_config',
    'title': 'HF Unique Post - Configuration',
    'fields':
    {
        'numberOfPageToRetrieve':
        {
            'label': 'Number of Page To retrieve (5 maximum)', 
            'type': 'int', 
            'default': 4,
            'max': 5
        },
        'delayForReputationCheck':
        {
            'label': 'Number of minutes between check on reputation',
            'type': 'int',
            'default': 2, 
            'min': 1
        }
    },
    'css': predefinedStyle
});

// Main function
$(function() {
    var dateObject = new Date();
    if(GM_getValue('reputationTimeout') === undefined) {
        GM_setValue('reputationTimeout', dateObject.getTime());    
    }
    initVariable();
        
    // Check the character
    if(window.location.href.indexOf('showthread') > 0) addCounterForCharacters('#message');    
    if(window.location.href.indexOf('newreply') > 0) addCounterForCharacters('#message_new', '.messageEditor');
    
    // Check the reputation
    if(dateObject.getTime() + (60 * GM_config.get('delayForReputationCheck')) > GM_getValue('reputationTimeout')) {
        GM_setValue('reputationTimeout', dateObject.getTime());
        checkReputation();
    }

    $("#panel a:contains('Log Out')").after(' — <a href="#" id="HFUConfig">HFU Config</a>');
    
    // Capture click on configuration
    $("#HFUConfig").on('click', function() {
        GM_config.open(); 
    });

    // Default action if the user is on reputation page.
    if(window.location.href.indexOf('reputation.php') > 0) {
        $("[class^=trow_reputation_]").each(function() {
            this.innerHTML = transformIntoUrl(this.innerHTML);
        });
    }
    
    // Default action if user is on the result page
    if(window.location.href.indexOf('action=results') > 0) {
        var actualPage = (getDataFromUrl('page')) ? getDataFromUrl('page') : 1;
        var promiseArray = [];
        
        $("table:nth-child(2) tr:gt(1)").empty();
        
        for(var page = ((actualPage*GM_config.get('numberOfPageToRetrieve')) - GM_config.get('numberOfPageToRetrieve')); page < actualPage * GM_config.get('numberOfPageToRetrieve'); page++) {
            promiseArray.push(retrieveContentFromUrl(window.location.href + "&page=" + page));
        }

        Promise.all(promiseArray).then(function(results) {
            for(var page = 0; page < results.length; page++) {
                retrieveLinkFromContent($(results[page]));    
            }  
        });
    }
});

// Init some global variables for the script
function initVariable() {
    if(GM_getValue('userId') === undefined) {
        GM_setValue('userId', getDataFromUrl('uid', $("#panel a:first").attr('href')));
    }
}

// Retrieve all the link from a content given.
function retrieveLinkFromContent(content, adresse) {
    var clonedLink;
    
    $("table:nth-child(2) tr:gt(1)", content).each(function() {
        clonedLink = $(this).clone();    
        this.remove();
        
        if(addList($("td:nth-child(3) a:nth-child(1)", this).text(), $("td:nth-child(3) a:nth-child(1)", this).attr('href')) === 0) {
            if($(" > * ", clonedLink).length > 1) {
                $("table:nth-child(2)").append(changeLinkToLastPost(clonedLink));
            }
        }
    });
}

// Add a link to the list if it's not yet in it.
function addList(title, link) {
    for(var j = 0; j < linkList.length; j++) {
        if(linkList[j].urlTitle === title) {
            return 1;   
        }
    }
    
    linkList.push({urlTitle: title, urlLink: link});
    return 0;
}

// Return Promise of the content of the passed URL
function retrieveContentFromUrl(url) {
    return new Promise(function(resolve, request) {
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(response) {
                resolve(response.responseText);
            }
        });    
	});
}

function checkReputation() {
    var reputationPage = retrieveContentFromUrl(window.location.origin + "/reputation.php?uid=" + GM_getValue('userId'), 1);
    reputationPage.then(function(result) {
        var lastReputationReceived = $("td [class^=trow_reputation_]", result).first().parent().parent();
        
        var userReputation   = $(".repvoteleft", lastReputationReceived).text();
        var reasonReputation = $(".repvotemid", lastReputationReceived).text();
        var dateReputation   = $(".repvoteright", lastReputationReceived).text();
        
        if(GM_getValue('lastReputation') != reasonReputation) {
        	GM_notification(reasonReputation + "\r\n" + dateReputation, "You received a new Reputation from " + userReputation, null, function() { GM_openInTab(window.location.origin +"/reputation.php?uid=" + GM_getValue('userId')) });
            GM_setValue('lastReputation', reasonReputation);
        }
    });
}

function addCounterForCharacters(textarea, divToAppend) {
    divToAppend = (divToAppend == null) ? textarea : divToAppend;
    $(divToAppend).after('<div id="messageCounter"><span>0</span>/35 Characteres needed</div><br>');
    
    $(textarea).on('keyup', function(e) {
        $("#messageCounter span").html(this.value.length);   
    });    
}

/******************************/
/*     Global Function       */
/****************************/

// Add the lastPost action to the url on the node passed
function changeLinkToLastPost(elementNode) {
    var _href = $("td:nth-child(3) a:nth-child(1)", elementNode).attr('href');
    $("td:nth-child(3) a:nth-child(1)", elementNode).attr('href', _href + "&action=lastpost");
    return elementNode;
}

// Allow you to retrieve get parameter from URL
function getDataFromUrl(VarSearch, url){
    var SearchString = (url == null) ? window.location.search.substring(1) : url;
    
    var VariableArray = SearchString.split('&');
    for(var i = 0; i < VariableArray.length; i++){
        var KeyValuePair = VariableArray[i].split('=');
        if(KeyValuePair[0] == VarSearch){
            return KeyValuePair[1];
        }
    }
}

// Detect and transform into a clickable link every valid URL in a passed content
function transformIntoUrl(text) {
    if(text.indexOf('img src') > 0) {
        return text;    
    }
    
    var urlRegex = /(https?:\/\/[^\s]+)/g;
    return text.replace(urlRegex, '<a href="$1">$1</a>');
}