AutoJoin for IndieGala Giveaways!
// ==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 r###lt = base + Math.floor(Math.random() * max_add); return r###lt; } 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; };