AutoJoin IndieGala Giveaways (improved)

AutoJoin for IndieGala Giveaways!

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Greasemonkey lub Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana jest instalacje jednego z następujących rozszerzeń: Tampermonkey, Violentmonkey.

Aby zainstalować ten skrypt, wymagana będzie instalacja rozszerzenia Tampermonkey lub Userscripts.

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

Aby zainstalować ten skrypt, musisz zainstalować rozszerzenie menedżera skryptów użytkownika.

(Mam już menedżera skryptów użytkownika, pozwól mi to zainstalować!)

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.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Będziesz musiał zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

Musisz zainstalować rozszerzenie menedżera stylów użytkownika, aby zainstalować ten styl.

(Mam już menedżera stylów użytkownika, pozwól mi to zainstalować!)

// ==UserScript==
// @name         AutoJoin IndieGala Giveaways (improved)
// @namespace    http://gdorn.circuitlocution.com
// @version      0.2
// @description  AutoJoin for IndieGala Giveaways!
// @author       George Dorn (@GDorn) and Sergio Susa (http://sergiosusa.com)
// @match        https://www.indiegala.com/giveaways*
// @grant        none
// ==/UserScript==

var reloading = 3 * 60 * 1000; // 3 minutes; delay encountered when out of points
var trying = 10 * 1000; // 10 seconds; delay before loading next page
var min_coins = 25; // number of points to save
var coins_per_page = 10; // number of extra points to save per page, to avoid wasting points on contests hours in the future; cycles to page one after exceeding
var timeBetweenClicks = 2 * 1000; // 2 seconds; delay between clicking on ticket stubs
var max_page = 10; // maximum page number; cycles to page 1 after this
var start_delay = 5 * 1000; // wait this long on page load, for 'match_games_in_steam_library' to finish.
var max_level = 0; // maximum contest level to try to enter; set to higher if you are a higher level.
var max_participants = 200; // skip contests with more participants than this
var skip_already_owned = true; // skip contests for games you already own (according to indiegala)

if (!skip_already_owned){
    start_delay = 50; //if we don't care about winning games we own, we can run a little faster
}

var autoEnter = function() {
    'use strict';

    console.log("Starting auto-entry.");

    if(skip_already_owned){
        removeAlreadyHave();
    }

    var coins = parseInt($(".coins-amount strong").html());
    console.log("Have this many coins: ", coins);    
    if ( coins < min_coins ) {
        console.log("Not enough coins, reloading...")
        reloadPage(randomize(reloading));
        return;
    }

    // add more delay for every stub we need to wait to click on
    var next_page_delay = trying;

    var contests = $('div.tickets-col');

    console.log("Got ", contests.length, " contests: ", contests);

    // iterate through contests on the page, scheduling clicks on stubs if they meet our criteria
    for (var i = 0; i < contests.length; i++){
        // if we spent all our coins, bail
        if (coins < min_coins){
            console.log("Not enough coins to continue");
            break;
        }

        var contest = contests[i];
        console.log("Considering contest:", contest);
        
        var name = $(contest).find('div.ticket-right').find('h2').text().trim();
        var price = parseInt($(contest).find('div.ticket-price')[0].textContent);
        var level = get_level(contest);
        var participants = get_participants(contest);
        console.log("Name: ", name, " Price: ", price, " Level: ", level, " Participants: ", participants);
        
        var stub = contest.getElementsByTagName("aside")[0];
        if (!stub){
            console.log("Skipping ", name, " because can't find stub?  Maybe already entered?");
            continue;
        }
        if (price > coins){
            console.log("Skipping ", name, " because price (", price, ") exceeds coins (", coins, ")");
            continue;
        }

        if (level > max_level){
            console.log("Skipping ", name, " because required level (", level, ") is greater than max_level,", max_level);
            continue;
        }
        
        if (participants > max_participants){
            console.log("Skipping ", name, " because ", participants, " users participating, greater than the allowed ", max_participants);
            continue;
        }

        // if we're here, all checks passed, go ahead and click on it.
        var delay = randomize(timeBetweenClicks);
        setTimeout(function(){ stub.click(); }, delay);
        console.log("Clicking on: ", name, stub);
        next_page_delay += delay; // add the delay to the next page delay so we don't load next page before the click happens
        coins -= price; // deduct cost of contest
    }    
    
    console.log("###### Done with this page, moving on to next. ######");
    
    var next_page = calculateNextPage();

    // get updated coins now in case our coin tracking broke
    coins = parseInt($(".coins-amount strong").html());

    // avoid spending too many coins on later pages, save them for short-running giveaways with fewer entries
    var needed_coins = min_coins + coins_per_page * (next_page -1);
    if ( coins < needed_coins){
        console.log("Going back to page 1; we have ", coins , " but want at least ", needed_coins, " to continue.");
        next_page = 1;
        next_page_delay += trying; //some extra delay before loading first page again
    }

    if (next_page > max_page) {
        next_page = 1;
    }
    
    next_page_delay = randomize(next_page_delay);
    
    console.log("Going to load page ", next_page, " in about ", next_page_delay, 'ms');
    
    setTimeout(function(){

        window.location="https://www.indiegala.com/giveaways/[NUM_PAGE]/expiry/asc".replace("[NUM_PAGE]", next_page);

    }, next_page_delay);

};

$(document).ready(function(){setTimeout(autoEnter, start_delay)});

/***********************************************************
 *  Utility Functions
 **********************************************************/

function randomize(number) {
    // returns a random number somewhere between 3/4 and 5/4 of the given value.
    // maybe helps bust bot detection.
    var base = Math.floor(number * 0.75);
    var max_add = Math.floor(number * 0.5);
    var result = base + Math.floor(Math.random() * max_add);
    return result;
}
    
function removeAlreadyHave() {
    var count = 0;
    var nodes = $('.on-steam-library-corner');
    for (var i = 0; i < nodes.length; i++){
        var node = nodes[i];
        if($(node).is(':visible')){
            $(node).parents('.tickets-col').remove();
            count += 1;
        }
    }
    console.log("Removed ", count, " offers already in steam library.")
}

function get_level(contest){
    // returns the numeric level requirement for a chunk of text extracted from a ticket
    var text = contest.textContent.trim();
    var position = text.indexOf('LEVEL ') + 6;
    return parseInt(text.slice(position));
}

function get_participants(contest){
    var text = $(contest).find('.info-row').text();
    var position = text.indexOf('minutes left') + 12;
    return parseInt(text.slice(position));   
}

function calculateNextPage()
{
    var page = window.location.href.replace("https://www.indiegala.com/giveaways/","").replace("/expiry/asc","");
    return parseInt(page)+1;
}

function reloadPage(miliseconds) {
    console.log("Reloading page in ", miliseconds, " ms");
    setTimeout(function(){
        window.location.reload();
    }, miliseconds);
}

/***********************************************************
 *  Override Functions
 **********************************************************/
window.confirm = function (message, callback, caption) {
    return true;
};