- // ==UserScript==
- // @name Giveaway Helper
- // @namespace https://github.com/Citrinate/giveawayHelper
- // @description Enhances Steam key-related giveaways
- // @author Citrinate
- // @version 2.12.9
- // @match *://*.chubbykeys.com/giveaway.php*
- // @match *://*.bananagiveaway.com/giveaway/*
- // @match *://*.dogebundle.com/index.php?page=redeem&id=*
- // @match *://*.dupedornot.com/giveaway*
- // @match *://*.embloo.net/task/*
- // @match *://*.gamecode.win/giveaway/*
- // @match *://*.gamehag.com/giveaway/*
- // @match *://*.gleam.io/*
- // @match *://*.grabfreegame.com/giveaway/*
- // @match *://*.hrkgame.com/en/giveaway/get-free-game/
- // @match *://*.keychampions.net/view.php?gid=*
- // @match *://*.marvelousga.com/giveaway/*
- // @match *://*.prys.ga/giveaway/?id=*
- // @match *://*.simplo.gg/index.php?giveaway=*
- // @match *://*.steamfriends.info/free-steam-key/
- // @match *://*.treasuregiveaways.com/*.php*
- // @match *://*.whosgamingnow.net/giveaway/*
- // @connect steamcommunity.com
- // @connect steampowered.com
- // @connect twitter.com
- // @connect twitch.tv
- // @match https://syndication.twitter.com/
- // @match https://player.twitch.tv/
- // @grant GM_getValue
- // @grant GM.getValue
- // @grant GM_setValue
- // @grant GM.setValue
- // @grant GM_deleteValue
- // @grant GM.deleteValue
- // @grant GM_addStyle
- // @grant GM_xmlhttpRequest
- // @grant GM.xmlHttpRequest
- // @require https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js
- // @require https://cdnjs.cloudflare.com/ajax/libs/crypto-js/3.1.2/rollups/md5.js
- // @run-at document-end
- // ==/UserScript==
-
- (function() {
-
- /**
- *
- */
- var setup = (function() {
- return {
- /**
- * Determine what to do for this page based on what's defined in the "config" variable
- *
- * hostname: A string
- * The hostname of the site we're setting the config for. Must be the same as what's defined
- * as @match in the metadata block above.
- *
- * helper: An object
- * The class which will determine how the do/undo buttons are added to the page. Usually this will
- * be set to basicHelper, which simply searches for links to Steam Groups and adds buttons for
- * them at the top of the page.
- *
- * domMatch: An array of strings
- * In some cases, we don't know what page a giveaway will be on. For example, Indiegala embeds
- * giveaways on various parts of their site which they want to attract attention to. Instead we
- * need to search the page for a DOM element that only appears when there is a giveaway on that
- * page. If any of the elements in this array match, then the script will be run on this page.
- *
- * urlMatch: An array of regular expressions
- * Used in conjunction with domMatch. Used for pages on the domain that we do know are relevant
- * to giveaways, and we always want to run the script on. For example, the giveaway confirmation
- * page on Indiegala. The regular expressions will be tested against the url of the pages, and if
- * any of them match, the script will be run on this page.
- *
- * cache: Boolean
- * For use with basicHelper. Some sites will remove links to Steam groups after the entry has
- * been completed. Set this to true so that any groups we find will be saved and presented later.
- *
- * offset: Array of integers
- * For use with basicHelper. Used to correct instances where the script's UI blocks parts of a
- * site. Offsets the UI by X number of pixels in the order of [top, left, right].
- * Directions that shouldn't be offset should be set to 0.
- *
- * zIndex: Integer
- * For use with basicHelper. Used to correct instances where the site's UI might overlay the
- * the script's UI and will be blocked by it.
- *
- * requires: An object: {twitch: Boolean}
- * For use with basicHelper. Some sites may have links asking you to follow a twitch channel, but
- * don't verify that you've done so. In these cases there's no need to display a "follow/unfollow"
- * button. For sites that do verify, set the value to true.
- *
- * redirect_urls: A function which returns a jQuery object
- * For use with basicHelper. Used on sites which may hide URLs behind a redirection link.
- * The jQuery object should contain the anchors that contain these links, and should be specific
- * enough so that it only contains links we know must be resolved.
- *
- * redirect_url_extract: A function which returns a string
- * For use with basicHelper and redirect_urls. Used in instances where redirections are used, but
- * the links can't be found within anchors. This function is used to extract the url from whatever
- * elements the redirect_urls function returns.
- *
- * onLoad: A function
- * For use with basicHelper. A function that executes after the page loads.
- *
- */
- run: function() {
- var found = false,
- config = [
- {
- hostname: "chubbykeys.com",
- helper: basicHelper,
- cache: false
- },
- {
- hostname: "bananagiveaway.com",
- helper: basicHelper,
- cache: true,
- redirect_urls: function() {
- return $("li:contains('Join')")
- .find("button:nth-child(1)");
- },
- redirect_url_extract: function(element) {
- return element.attr("onclick").replace("window.open('", "").replace("')", "");
- }
- },
- {
- hostname: "dogebundle.com",
- helper: basicHelper,
- cache: true,
- offset: [50, 0, 0]
- },
- {
- hostname: "dupedornot.com",
- helper: basicHelper,
- cache: false,
- requires: {twitch: true}
- },
- {
- hostname: "embloo.net",
- helper: basicHelper,
- cache: true
- },
- {
- hostname: "gamecode.win",
- helper: basicHelper,
- cache: true,
- requires: {twitch: true}
- },
- {
- hostname: "gamehag.com",
- helper: basicHelper,
- cache: true,
- offset: [80, 0, 300],
- zIndex: 80,
- redirect_urls: function() {
- return $(".element-list .task-content:contains('Steam Community group')")
- .find("a[href*='/giveaway/click/']");
- }
- },
- {
- hostname: "gleam.io",
- helper: gleamHelper,
- cache: false
- },
- {
- hostname: "grabfreegame.com",
- helper: basicHelper,
- cache: true,
- offset: [56, 0, 0],
- redirect_urls: function() {
- return $("li p:contains('Steam Group')").parent()
- .find("button:contains('To do')");
- },
- redirect_url_extract: function(element) {
- return element.attr("onclick").replace("window.open('", "").replace("')", "");
- }
- },
- {
- hostname: "hrkgame.com",
- helper: basicHelper,
- cache: false
- },
- {
- hostname: "keychampions.net",
- helper: basicHelper,
- cache: true,
- offset: [0, 120, 0]
- },
- {
- hostname: "marvelousga.com",
- helper: basicHelper,
- cache: false,
- zIndex: 1,
- requires: {twitch: true}
- },
- {
- hostname: "prys.ga",
- helper: basicHelper,
- cache: false,
- offset: [50, 0, 0],
- zIndex: 1029
- },
- {
- hostname: "simplo.gg",
- helper: basicHelper,
- cache: true
- },
- {
- hostname: "steamfriends.info",
- helper: basicHelper,
- cache: false
- },
- {
- hostname: "treasuregiveaways.com",
- helper: basicHelper,
- cache: true,
- offset: [50, 0, 0],
- zIndex: 1029
- },
- {
- hostname: "whosgamingnow.net",
- helper: basicHelper,
- cache: true
- }
- ];
-
- for(var i = 0; i < config.length; i++) {
- var site = config[i];
-
- if(document.location.hostname.split(".").splice(-2).join(".") == site.hostname) {
- found = true;
-
- // determine whether to run the script based on the content of the page
- if(typeof site.domMatch !== "undefined" ||
- typeof site.urlMatch !== "undefined"
- ) {
- var match_found = false;
-
- // check the DOM for matches as defined by domMatch
- if(typeof site.domMatch !== "undefined") {
- for(var k = 0; k < site.domMatch.length; k++) {
- if($(site.domMatch[k]).length !== 0) {
- match_found = true;
- break;
- }
- }
- }
-
- // check the URL for matches as defined by urlMatch
- if(typeof site.urlMatch !== "undefined") {
- for(var l = 0; l < site.urlMatch.length; l++) {
- var reg = new RegExp(site.urlMatch[l]);
-
- if(reg.test(location.href)) {
- match_found = true;
- break;
- }
- }
- }
-
- if(!match_found) break;
- }
-
- giveawayHelperUI.loadUI(site.zIndex, site.onLoad);
- site.helper.init(site.cache, site.cache_id, site.offset, site.requires, site.redirect_urls,
- site.redirect_url_extract);
- }
- }
-
- if(!found) {
- commandHub.init();
- }
- }
- };
- })();
-
- /**
- *
- */
- var gleamHelper = (function() {
- var gleam = null,
- authentications = { steam: false, twitter: false, twitch: false };
-
- /**
- * Check to see what accounts the user has linked to gleam
- */
- function checkAuthentications() {
- if(gleam.contestantState.contestant.authentications) {
- var authentication_data = gleam.contestantState.contestant.authentications;
-
- for(var i = 0; i < authentication_data.length; i++) {
- var current_authentication = authentication_data[i];
- authentications[current_authentication.provider == "twitchtv" ? "twitch" : current_authentication.provider] = current_authentication;
- }
- }
- }
-
- /**
- * Decide what to do for each of the entries
- */
- function handleEntries() {
- var entries = $(".entry-method");
-
- for(var i = 0; i < entries.length; i++) {
- var entry_element = entries[i],
- entry = unsafeWindow.angular.element(entry_element).scope();
-
- switch(entry.entry_method.entry_type) {
- case "steam_join_group":
- createSteamButton(entry, entry_element);
- break;
-
- case "twitter_follow":
- case "twitter_retweet":
- case "twitter_tweet":
- case "twitter_hashtags":
- //createTwitterButton(entry, entry_element);
- break;
-
- case "twitchtv_follow":
- createTwitchButton(entry, entry_element);
- break;
-
- default:
- break;
- }
- }
- }
-
- /**
- *
- */
- function handleReward() {
- var temp_interval = setInterval(function() {
- if(gleam.bestCouponCode() !== null) {
- clearInterval(temp_interval);
- SteamHandler.getInstance().findKeys(addRedeemButton, gleam.bestCouponCode(), false);
- }
- }, 100);
- }
-
- /**
- * Places the button onto the page
- */
- function addButton(entry_element) {
- return function(new_button) {
- new_button.addClass("btn btn-embossed btn-info");
- $(entry_element).find(">a").first().append(new_button);
- };
- }
-
- /**
- *
- */
- function addRedeemButton(new_button) {
- new_button.find("button").first().addClass("btn btn-embossed btn-success");
- $(".redeem-container").first().after(new_button);
- }
-
- /**
- * Returns true when an entry has been completed
- */
- function isCompleted(entry) {
- return function() {
- return gleam.isEntered(entry.entry_method) && !gleam.canEnter(entry.entry_method);
- };
- }
-
- /**
- *
- */
- function createSteamButton(entry, entry_element) {
- SteamHandler.getInstance().handleEntry({
- group_name: entry.entry_method.config3.toLowerCase(),
- group_id: entry.entry_method.config4
- },
- addButton(entry_element),
- false,
- authentications.steam === false ? false : {
- user_id: authentications.steam.uid
- }
- );
- }
-
- /**
- *
- */
- function createTwitterButton(entry, entry_element) {
- // Don't do anything for a tweet entry that's already been completed
- if(isCompleted(entry)() &&
- (entry.entry_method.entry_type == "twitter_tweet" ||
- entry.entry_method.entry_type == "twitter_hashtags")) {
-
- return;
- }
-
- TwitterHandler.getInstance().handleEntry({
- action: entry.entry_method.entry_type,
- id: entry.entry_method.config1
- },
- addButton(entry_element),
- isCompleted(entry),
- false,
- authentications.twitter === false ? false : {
- user_id: authentications.twitter.uid,
- user_handle: authentications.twitter.reference
- }
- );
- }
-
- /**
- *
- */
- function createTwitchButton(entry, entry_element) {
- TwitchHandler.getInstance().handleEntry(
- entry.entry_method.config1,
- addButton(entry_element),
- isCompleted(entry),
- false,
- authentications.twitch === false ? false : {
- user_handle: authentications.twitch.reference
- }
- );
- }
-
- return {
- /**
- *
- */
- init: function() {
- MKY.addStyle(`
- .${giveawayHelperUI.gh_button} {
- bottom: 0px;
- height: 32px;
- margin: auto;
- padding: 6px;
- position: absolute;
- right: 64px;
- top: 0px;
- z-index: 9999999999;
- }
-
- .${giveawayHelperUI.gh_redeem_button} {
- margin-bottom: 32px;
- position: static;
- }
- `);
-
- // Show exact end date when hovering over any times
- $("[data-ends]").each(function() {
- $(this).attr("title", new Date(parseInt($(this).attr("data-ends")) * 1000));
- });
-
- // wait for gleam to finish loading
- var temp_interval = setInterval(function() {
- if($(".popup-blocks-container") !== null) {
- clearInterval(temp_interval);
- gleam = unsafeWindow.angular.element($(".popup-blocks-container").get(0)).scope();
-
- // wait for gleam to fully finish loading
- var another_temp_interval = setInterval(function() {
- if(typeof gleam.campaign.entry_count !== "undefined") {
- clearInterval(another_temp_interval);
- checkAuthentications();
- handleReward();
-
- if(!gleam.showPromotionEnded()) {
- handleEntries();
- }
- }
- }, 100);
- }
- }, 100);
- }
- };
- })();
-
- /**
- *
- */
- var basicHelper = (function() {
- return {
- /**
- *
- */
- init: function(do_cache, cache_id, offset, requires, redirect_urls, redirect_url_extract) {
- if(typeof do_cache !== "undefined" && do_cache) {
- if(typeof cache_id === "undefined") {
- cache_id = document.location.hostname + document.location.pathname + document.location.search;
- }
-
- cache_id = `cache_${CryptoJS.MD5(cache_id)}`;
- } else {
- do_cache = false;
- }
-
- giveawayHelperUI.defaultButtonSetup(offset);
-
- // Some sites load the giveaway data dynamically. Check every second for changes
- setInterval(function() {
- // Add Steam buttons
- SteamHandler.getInstance().findGroups(
- giveawayHelperUI.addButton,
- $("body").html(),
- true,
- do_cache,
- cache_id
- );
-
- // Add Steam Key redeem buttons
- SteamHandler.getInstance().findKeys(giveawayHelperUI.addButton, $("body").html(), true);
-
- if(typeof requires !== "undefined") {
- if(typeof requires.twitch !== "undefined" && requires.twitch === true) {
- // Add Twitch buttons
- TwitchHandler.getInstance().findChannels(
- giveawayHelperUI.addButton,
- $("body").html(),
- true,
- do_cache,
- `twitch_${cache_id}`
- );
- }
-
- if(typeof requires.steam_curators !== "undefined" && requires.steam_curators === true) {
- // Add Steam Curator buttons
- SteamCuratorHandler.getInstance().findCurators(
- giveawayHelperUI.addButton,
- $("body").html(),
- true,
- do_cache,
- `steam_curators_${cache_id}`
- );
- }
- }
-
- // Check for redirects
- if(typeof redirect_urls !== "undefined") {
- redirect_urls().each(function() {
- var redirect_url;
-
- if(typeof redirect_url_extract !== "undefined") {
- redirect_url = redirect_url_extract($(this));
- } else {
- redirect_url = $(this).attr("href");
- }
-
- giveawayHelperUI.resolveUrl(redirect_url, function(url) {
- // Add Steam button
- SteamHandler.getInstance().findGroups(
- giveawayHelperUI.addButton,
- url,
- true,
- do_cache,
- cache_id
- );
-
- if(typeof requires !== "undefined") {
- if(typeof requires.twitch !== "undefined" && requires.twitch === true) {
- // Add Twitch button
- TwitchHandler.getInstance().findChannels(
- giveawayHelperUI.addButton,
- url,
- true,
- do_cache,
- `twitch_${cache_id}`
- );
- }
-
- if(typeof requires.steam_curators !== "undefined" && requires.steam_curators === true) {
- // Steam Curator buttons
- SteamCuratorHandler.getInstance().findCurators(
- giveawayHelperUI.addButton,
- url,
- true,
- do_cache,
- `steam_curators_${cache_id}`
- );
- }
- }
- });
- });
- }
- }, 1000);
- },
- };
- })();
-
- /**
- * Handles Steam group buttons
- */
- var SteamHandler = (function() {
- function init() {
- var re_group_name = /steamcommunity\.com\/groups\/([a-zA-Z0-9\-\_]{2,32})/g,
- re_group_id = /steamcommunity.com\/gid\/(([0-9]+)|\[g:[0-9]:([0-9]+)\])/g,
- re_steam_key = /([A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5}|[A-Z0-9]{5}-[A-Z0-9]{5}-[A-Z0-9]{5})/g,
- redeem_key_url = "https://store.steampowered.com/account/registerkey?key=",
- user_id = null,
- session_id = null,
- process_url = null,
- active_groups = [],
- button_count = 1,
- handled_group_names = [],
- handled_group_ids = [],
- handled_keys = [],
- ready = false;
-
- // Get all the user data we'll need to make join/leave group requests
- MKY.xmlHttpRequest({
- url: "https://steamcommunity.com/my/groups",
- method: "GET",
- onload: function(response) {
- user_id = response.responseText.match(/g_steamID = \"(.+?)\";/);
- session_id = response.responseText.match(/g_sessionID = \"(.+?)\";/);
- process_url = response.responseText.match(/steamcommunity.com\/(id\/.+?|profiles\/[0-9]+)\/friends\//);
- user_id = user_id === null ? null : user_id[1];
- session_id = session_id === null ? null : session_id[1];
- process_url = process_url === null ? null : "https://steamcommunity.com/" + process_url[1] + "/home_process";
-
- $(response.responseText).find("a[href^='https://steamcommunity.com/groups/']").each(function() {
- var group_name = $(this).attr("href").replace("https://steamcommunity.com/groups/", "");
-
- if(group_name.indexOf("/") == -1) {
- active_groups.push(group_name.toLowerCase());
- }
- });
-
- active_groups = giveawayHelperUI.removeDuplicates(active_groups);
- ready = true;
- }
- });
-
- function verifyLogin(expected_user) {
- if(typeof expected_user !== "undefined" && !expected_user) {
- // The user doesn't have a Steam account linked, do nothing
- } else if(user_id === null || session_id === null || process_url === null) {
- // We're not logged in
- giveawayHelperUI.showError(`You must be logged into
- <a href="https://steamcommunity.com/login" target="_blank">steamcommunity.com</a>`);
- } else if(typeof expected_user !== "undefined" && expected_user.user_id != user_id) {
- // We're logged in as the wrong user
- giveawayHelperUI.showError(`You must be logged into the linked Steam account:
- <a href="https://steamcommunity.com/profiles/${expected_user.user_id}" target="_blank">
- https://steamcommunity.com/profiles/${expected_user.user_id}</a>`);
- } else if(active_groups === null) {
- // Couldn't get user's group data
- giveawayHelperUI.showError("Unable to determine what Steam groups you're a member of");
- } else {
- return true;
- }
-
- return false;
- }
-
- /**
- *
- */
- function prepCreateButton(group_data, button_callback, show_name, expected_user) {
- if(typeof group_data.group_id == "undefined") {
- // Group ID is missing
- getGroupID(group_data.group_name, function(group_id) {
- group_data.group_id = group_id;
- createButton(group_data, button_callback, show_name, expected_user);
- });
- } else if(typeof group_data.group_name == "undefined") {
- // Group name is missing
- getGroupName(group_data.group_id, function(group_name) {
- group_data.group_name = group_name;
-
- // Fetch a separate numeric group id that we'll need
- getGroupID(group_data.group_name, function(group_id) {
- group_data.group_id = group_id;
- createButton(group_data, button_callback, show_name, expected_user);
- });
- });
- } else {
- createButton(group_data, button_callback, show_name, expected_user);
- }
- }
-
- /**
- * Create a join/leave toggle button
- */
- function createButton(group_data, button_callback, show_name, expected_user) {
- if(verifyLogin(expected_user)) {
- // Create the button
- var group_name = group_data.group_name,
- group_id = group_data.group_id,
- in_group = active_groups.indexOf(group_name) != -1,
- button_id = "steam_button_" + button_count++,
- label = in_group ?
- `Leave ${show_name ? group_name : "Group"}`
- : `Join ${show_name ? group_name : "Group"}`;
-
- button_callback(
- giveawayHelperUI.buildButton(button_id, label, in_group, function() {
- toggleGroupStatus(button_id, group_name, group_id, show_name);
- giveawayHelperUI.showButtonLoading(button_id);
- })
- );
- }
- }
-
-
- /**
- * Toggle group status between "joined" and "left"
- */
- function toggleGroupStatus(button_id, group_name, group_id, show_name) {
- var steam_community_down_error = `
- The Steam Community is experiencing issues. Please handle any remaining Steam entries manually, or reload the page and try again.
- `;
-
- if(active_groups.indexOf(group_name) == -1) {
- joinSteamGroup(group_name, group_id, function(success) {
- if(success) {
- active_groups.push(group_name);
- giveawayHelperUI.toggleButtonClass(button_id);
- giveawayHelperUI.setButtonLabel(button_id, `Leave ${show_name ? group_name : "Group"}`);
- } else {
- giveawayHelperUI.showError(steam_community_down_error);
- }
-
- giveawayHelperUI.hideButtonLoading(button_id);
- });
- } else {
- leaveSteamGroup(group_name, group_id, function(success) {
- if(success) {
- active_groups.splice(active_groups.indexOf(group_name), 1);
- giveawayHelperUI.toggleButtonClass(button_id);
- giveawayHelperUI.setButtonLabel(button_id, `Join ${show_name ? group_name : "Group"}`);
- } else {
- giveawayHelperUI.showError(steam_community_down_error);
- }
-
- giveawayHelperUI.hideButtonLoading(button_id);
- });
- }
- }
-
- /**
- * Join a steam group
- */
- function joinSteamGroup(group_name, group_id, callback) {
- MKY.xmlHttpRequest({
- url: "https://steamcommunity.com/groups/" + group_name,
- method: "POST",
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- data: $.param({ action: "join", sessionID: session_id }),
- onload: function(response) {
- MKY.xmlHttpRequest({
- url: "https://steamcommunity.com/my/groups",
- method: "GET",
- onload: function(response) {
- if(typeof callback == "function") {
- if($(response.responseText.toLowerCase()).find(
- `a[href='https://steamcommunity.com/groups/${group_name}']`).length === 0) {
-
- // Failed to join the group, Steam Community is probably down
- callback(false);
- } else {
- callback(true);
- }
- }
- }
- });
- }
- });
- }
-
- /**
- * Leave a steam group
- */
- function leaveSteamGroup(group_name, group_id, callback) {
- MKY.xmlHttpRequest({
- url: process_url,
- method: "POST",
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- data: $.param({ sessionID: session_id, action: "leaveGroup", groupId: group_id }),
- onload: function(response) {
- if(typeof callback == "function") {
- if($(response.responseText.toLowerCase()).find(
- `a[href='https://steamcommunity.com/groups/${group_name}']`).length !== 0) {
-
- // Failed to leave the group, Steam Community is probably down
- callback(false);
- } else {
- callback(true);
- }
- }
- }
- });
- }
-
- /**
- * Get the numeric ID for a Steam group
- */
- function getGroupID(group_name, callback) {
- MKY.xmlHttpRequest({
- url: "https://steamcommunity.com/groups/" + group_name,
- method: "GET",
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- onload: function(response) {
- var group_id = response.responseText.match(/OpenGroupChat\( \'([0-9]+)\'/);
- group_id = group_id === null ? null : group_id[1];
-
- callback(group_id);
- }
- });
- }
-
- /**
- * Get the name for a Steam group given the numeric ID
- */
- function getGroupName(group_id, callback) {
- MKY.xmlHttpRequest({
- url: "https://steamcommunity.com/gid/" + group_id,
- method: "GET",
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- onload: function(response) {
- var group_name = response.finalUrl.match(/steamcommunity\.com\/groups\/([a-zA-Z0-9\-\_]{2,32})/);
- group_name = group_name === null ? null : group_name[1];
-
- callback(group_name.toLowerCase());
- }
- });
- }
-
- return {
- /**
- *
- */
- handleEntry: function(group_data, button_callback, show_name, expected_user) {
- if(ready) {
- prepCreateButton(group_data, button_callback, show_name, expected_user);
- } else {
- // Wait for the command hub to load
- var temp_interval = setInterval(function() {
- if(ready) {
- clearInterval(temp_interval);
- prepCreateButton(group_data, button_callback, show_name, expected_user);
- }
- }, 100);
- }
- },
-
- /**
- *
- */
- findGroups: function(button_callback, target, show_name, do_cache, cache_id) {
- var self = this;
-
- giveawayHelperUI.restoreCachedLinks(cache_id).then(function(group_names) {
- giveawayHelperUI.restoreCachedLinks(cache_id + "_ids").then(function(group_ids) {
- var match;
-
- if(!do_cache) {
- group_names = [];
- group_ids = [];
- }
-
- // Look for any links containing steam group names
- while((match = re_group_name.exec(target)) !== null) {
- group_names.push(match[1].toLowerCase());
- }
-
- // Look for any links containing steam group ids
- while((match = re_group_id.exec(target)) !== null) {
- if(typeof match[2] !== "undefined") {
- group_ids.push(match[2].toLowerCase());
- } else {
- group_ids.push(match[3].toLowerCase());
- }
- }
-
- group_names = giveawayHelperUI.removeDuplicates(group_names);
- group_ids = giveawayHelperUI.removeDuplicates(group_ids);
-
- // Cache the results
- if(do_cache) {
- giveawayHelperUI.cacheLinks(group_names, cache_id);
- giveawayHelperUI.cacheLinks(group_ids, cache_id + "_ids");
- }
-
- // Create the buttons
- for(var i = 0; i < group_names.length; i++) {
- if($.inArray(group_names[i], handled_group_names) == -1) {
- handled_group_names.push(group_names[i]);
- self.handleEntry({ group_name: group_names[i] }, button_callback, show_name);
- }
- }
-
- for(var j = 0; j < group_ids.length; j++) {
- if($.inArray(group_ids[i], handled_group_ids) == -1) {
- handled_group_ids.push(group_ids[i]);
- self.handleEntry({ group_id: group_ids[j] }, button_callback, show_name);
- }
- }
- });
- });
- },
-
- /**
- *
- */
- findKeys: function(button_callback, target, show_key) {
- var keys = [],
- match;
-
- while((match = re_steam_key.exec(target)) !== null) {
- keys.push(match[1]);
- }
-
- for(var i = 0; i < keys.length; i++) {
- if($.inArray(keys[i], handled_keys) == -1) {
- var steam_key = keys[i],
- button_id = 'redeem_' + handled_keys.length,
- label = show_key ? `Redeem ${steam_key}` : "Redeem Key",
- redeem_url = `${redeem_key_url}${steam_key}`;
-
- handled_keys.push(steam_key);
- button_callback(
- giveawayHelperUI.buildRedeemButton(button_id, label, redeem_url)
- );
- }
- }
- }
- };
- }
-
- var instance;
- return {
- getInstance: function() {
- if(!instance) instance = init();
- return instance;
- }
- };
- })();
-
-
-
- /**
- * Handles Steam curator buttons
- */
- var SteamCuratorHandler = (function() {
- function init() {
- var re_curator_id = /steampowered.com\/curator\/([0-9]+)/g,
- session_id = null,
- active_curators = [],
- button_count = 1,
- handled_curator_ids = [],
- ready = false;
- curator_ready_status = 0;
-
- // Get all the user data we'll need to make follow/unfollow curator requests
- MKY.xmlHttpRequest({
- url: "https://store.steampowered.com",
- method: "GET",
- onload: function(response) {
- session_id = response.responseText.match(/g_sessionID = \"(.+?)\";/);
- session_id = session_id === null ? null : session_id[1];
-
- MKY.xmlHttpRequest({
- url: "https://store.steampowered.com/curators/ajaxgetcurators//?query=&start=0&count=1000&filter=mycurators",
- method: "GET",
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- onload: function(response) {
- var curator_urls_completed = 1;
-
- try {
- var data = JSON.parse(response.responseText);
-
- if(typeof data.success != "undefined" && typeof data.pagesize != "undefined" && typeof data.total_count != "undefined" && data.success == true) {
- parseActiveCurators(data);
-
- for(var i = 1; i < Math.ceil(data.total_count/data.pagesize); i++) {
- setTimeout(function(page_num) {
- if(ready) return;
-
- MKY.xmlHttpRequest({
- url: "https://store.steampowered.com/curators/ajaxgetcurators//?query=&start=" + (page_num * data.pagesize) + "&count=1000&filter=mycurators",
- method: "GET",
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- onload: function(response) {
- try {
- var data = JSON.parse(response.responseText);
-
- if(typeof data.success != "undefined" && data.success == true) {
- parseActiveCurators(data);
- } else {
- ready = true;
- active_curators = null;
- }
-
- curator_urls_completed++;
- } catch(e) {
- ready = true;
- active_curators = null;
- }
- }
- });
- }, i * 500, i);
- }
-
- var temp_interval = setInterval(function() {
- if(curator_urls_completed >= Math.ceil(data.total_count/data.pagesize)) {
- clearInterval(temp_interval);
- ready = true;
- }
- }, 100)
- }
- } catch(e) {
- ready = true;
- active_curators = null;
- }
- }
- });
- }
- });
-
- function verifyLogin(expected_user) {
- if(typeof expected_user !== "undefined" && !expected_user) {
- // The user doesn't have a Steam account linked, do nothing
- } else if(session_id === null) {
- // We're not logged in
- giveawayHelperUI.showError(`You must be logged into
- <a href="https://steamcommunity.com/login" target="_blank">steamcommunity.com</a>`);
- } else if(active_curators === null) {
- // Couldn't get user's group data
- giveawayHelperUI.showError("Unable to determine what Steam curators you're following");
- } else {
- return true;
- }
-
- return false;
- }
-
- /**
- *
- */
- function parseActiveCurators(data) {
- if(typeof data.results_html == "undefined") {
- curator_ready_status = 2;
- active_curators = null;
- return;
- }
-
- var re_curator_results_id = /\"clanID\":\"([0-9]+)\"/g;
-
- while((match = re_curator_results_id.exec(data.results_html)) !== null) {
- active_curators.push(match[1]);
- }
-
- return;
- }
-
- /**
- * Create a join/leave Curator toggle button
- */
- function createButton(curator_id, button_callback, show_name, expected_user) {
- if(verifyLogin(expected_user)) {
- // Create the button
- var is_following = active_curators.indexOf(curator_id) != -1,
- button_id = "steam_curator_button_" + button_count++,
- label = is_following ?
- `Unfollow ${show_name ? curator_id : "Curator"}`
- : `Follow ${show_name ? curator_id : "Curator"}`;
-
- button_callback(
- giveawayHelperUI.buildButton(button_id, label, is_following, function() {
- toggleCuratorStatus(button_id, curator_id, show_name);
- giveawayHelperUI.showButtonLoading(button_id);
- })
- );
- }
- }
-
-
- /**
- * Toggle steam curator status between "following" and "not following"
- */
- function toggleCuratorStatus(button_id, curator_id, show_name) {
- var steam_community_down_error = `
- The Steam Community is experiencing issues. Please handle any remaining Steam entries manually, or reload the page and try again.
- `;
-
- if(active_curators.indexOf(curator_id) == -1) {
- followCurator(curator_id, function(success) {
- if(success) {
- active_curators.push(curator_id);
- giveawayHelperUI.toggleButtonClass(button_id);
- giveawayHelperUI.setButtonLabel(button_id, `Unfollow ${show_name ? curator_id : "Curator"}`);
- } else {
- giveawayHelperUI.showError(steam_community_down_error);
- }
-
- giveawayHelperUI.hideButtonLoading(button_id);
- });
- } else {
- unfollowCurator(curator_id, function(success) {
- if(success) {
- active_curators.splice(active_curators.indexOf(curator_id), 1);
- giveawayHelperUI.toggleButtonClass(button_id);
- giveawayHelperUI.setButtonLabel(button_id, `Follow ${show_name ? curator_id : "Curator"}`);
- } else {
- giveawayHelperUI.showError(steam_community_down_error);
- }
-
- giveawayHelperUI.hideButtonLoading(button_id);
- });
- }
- }
-
- /**
- * Follow a steam curator
- */
- function followCurator(curator_id, callback) {
- MKY.xmlHttpRequest({
- url: "https://store.steampowered.com/curators/ajaxfollow",
- method: "POST",
- data: $.param({ clanid: curator_id, sessionid: session_id, follow: "1" }),
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- onload: function(response) {
- try {
- var data = JSON.parse(response.responseText);
-
- if(typeof data.success.success != "undefined" && data.success.success == 1) {
- callback(true);
- } else {
- callback(false);
- }
- } catch(e) {
- callback(false)
- }
- }
- });
- }
-
- /**
- * Unfollow a steam curator
- */
- function unfollowCurator(curator_id, callback) {
- MKY.xmlHttpRequest({
- url: "https://store.steampowered.com/curators/ajaxfollow",
- method: "POST",
- data: $.param({ clanid: curator_id, sessionid: session_id, follow: "0" }),
- headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
- onload: function(response) {
- try {
- var data = JSON.parse(response.responseText);
-
- if(typeof data.success.success != "undefined" && data.success.success == 1) {
- callback(true);
- } else {
- callback(false);
- }
- } catch(e) {
- callback(false)
- }
- }
- });
- }
-
- return {
- /**
- *
- */
- handleEntry: function(curator_id, button_callback, show_name, expected_user) {
- if(ready) {
- createButton(curator_id, button_callback, show_name, expected_user);
- } else {
- // Wait for the command hub to load
- var temp_interval = setInterval(function() {
- if(ready) {
- clearInterval(temp_interval);
- createButton(curator_id, button_callback, show_name, expected_user);
- }
- }, 100);
- }
- },
-
- /**
- *
- */
- findCurators: function(button_callback, target, show_name, do_cache, cache_id) {
- var self = this;
-
- giveawayHelperUI.restoreCachedLinks(cache_id).then(function(curator_ids) {
- var match;
-
- if(!do_cache) {
- curator_ids = [];
- }
-
- // Look for any links containing steam curator ids
- while((match = re_curator_id.exec(target)) !== null) {
- curator_ids.push(match[1].toLowerCase());
- }
-
- curator_ids = giveawayHelperUI.removeDuplicates(curator_ids);
-
- // Cache the results
- if(do_cache) {
- giveawayHelperUI.cacheLinks(curator_ids, cache_id);
- }
-
- // Create the buttons
- for(var i = 0; i < curator_ids.length; i++) {
- if($.inArray(curator_ids[i], handled_curator_ids) == -1) {
- handled_curator_ids.push(curator_ids[i]);
- self.handleEntry(curator_ids[i], button_callback, show_name);
- }
- }
- });
- }
- };
- }
-
- var instance;
- return {
- getInstance: function() {
- if(!instance) instance = init();
- return instance;
- }
- };
- })();
-
- /**
- * Handles Twitter undo buttons
- */
- var TwitterHandler = (function() {
- function init() {
- var command_hub_url = "https://syndication.twitter.com/",
- command_hub_host = "syndication.twitter.com",
- auth_token = null,
- csrf_token = null,
- user_handle = null,
- user_id = null,
- start_time = +new Date(),
- deleted_tweets = [], // used to make sure we dont try to delete the same (re)tweet more than once
- button_count = 1,
- ready_a = false;
- ready_b = false;
-
- // Get all the user data we'll need to undo twitter entries
- commandHub.load(
- command_hub_url,
- command_hub_host,
- function() {
- return {
- csrf_token: getCookie("ct0")
- };
- },
- function(data) {
- csrf_token = data.csrf_token;
- ready_a = true;
- }
- );
-
- MKY.xmlHttpRequest({
- url: "https://twitter.com",
- method: "GET",
- onload: function(response) {
- auth_token = $($(response.responseText)
- .find("input[id='authenticity_token']").get(0))
- .attr("value");
- user_handle = $(response.responseText)
- .find(".current-user a")
- .attr("href");
- user_id = $(response.responseText)
- .find("#current-user-id")
- .attr("value");
-
- auth_token = typeof auth_token == "undefined" ? null : auth_token;
- user_handle = typeof user_handle == "undefined" ? null : user_handle.replace("/", "");
- user_id = typeof user_id == "undefined" ? null : user_id;
-
- ready_b = true;
- }
- });
-
- /**
- * Get ready to create an item
- */
- function prepCreateButton(action_data, button_callback, ready_check, show_name, expected_user) {
- // Wait until the entry is completed before showing the button
- var temp_interval = setInterval(function() {
- if(ready_check()) {
- clearInterval(temp_interval);
- createButton(action_data, button_callback, show_name, expected_user, +new Date());
- }
- }, 100);
- }
-
- /**
- * Create the button
- */
- function createButton(action_data, button_callback, show_name, expected_user, end_time) {
- if(!expected_user) {
- // The user doesn't have a Twitter account linked, do nothing
- } else if(auth_token === null || user_handle === null || csrf_token === null) {
- // We're not logged in
- giveawayHelperUI.showError(`You must be logged into
- <a href="https://twitter.com/login" target="_blank">twitter.com</a>`);
- } else if(expected_user.user_id != user_id) {
- // We're logged in as the wrong user
- giveawayHelperUI.showError(`You must be logged into the Twitter account linked to Gleam.io:
- <a href="https://twitter.com/${expected_user.user_handle}" target="_blank">
- https://twitter.com/${expected_user.user_handle}</a>`);
- } else {
- // Create the button
- var button_id = "twitter_button_" + button_count++;
-
- if(action_data.action == "twitter_follow") {
- // Unfollow button
- var twitter_handle = action_data.id;
-
- button_callback(
- giveawayHelperUI.buildButton(button_id, `Unfollow${show_name ? ` ${twitter_handle}` : ""}`,
- false,
- function() {
- giveawayHelperUI.removeButton(button_id);
-
- // Get user's Twitter ID
- getTwitterUserData(twitter_handle, function(twitter_id, is_following) {
- deleteTwitterFollow(twitter_handle, twitter_id);
- });
- })
- );
- } else if(action_data.action == "twitter_retweet") {
- // Delete Retweet button
- button_callback(
- giveawayHelperUI.buildButton(button_id, "Delete Retweet", false, function() {
- giveawayHelperUI.removeButton(button_id);
- deleteTwitterRetweet(action_data.id.match(/\/([0-9]+)/)[1]);
- })
- );
- } else if(action_data.action == "twitter_tweet" || action_data.action == "twitter_hashtags") {
- // Delete Tweet button
- button_callback(
- giveawayHelperUI.buildButton(button_id, "Delete Tweet", false, function() {
- giveawayHelperUI.removeButton(button_id);
-
- /* We don't have an id for the tweet, so instead delete the first tweet we can find
- that was posted after we handled the entry, but before it was marked completed. */
- getTwitterTweet(end_time, function(tweet_id) {
- if(tweet_id === false) {
- giveawayHelperUI.showError(`Failed to find
- <a href="https://twitter.com/${user_handle}" target="_blank">Tweet</a>`);
- } else {
- deleteTwitterTweet(tweet_id);
- }
- });
- })
- );
- }
- }
- }
-
- /**
- * @return {String} twitter_id - Twitter id for this handle
- * @return {Boolean} is_following - True for "following", false for "not following"
- */
- function getTwitterUserData(twitter_handle, callback) {
- MKY.xmlHttpRequest({
- url: "https://twitter.com/" + twitter_handle,
- method: "GET",
- onload: function(response) {
- var twitter_id = $($(response.responseText.toLowerCase()).find(
- `[data-screen-name='${twitter_handle.toLowerCase()}'][data-user-id]`).get(0)).attr(
- "data-user-id"),
- is_following = $($(response.responseText.toLowerCase()).find(
- `[data-screen-name='${twitter_handle.toLowerCase()}'][data-you-follow]`).get(0)).attr(
- "data-you-follow");
-
- if(typeof twitter_id !== "undefined" && typeof is_following !== "undefined") {
- callback(twitter_id, is_following !== "false");
- } else {
- callback(null, null);
- }
- }
- });
- }
-
- /**
- * We don't have an id for the tweet, so instead delete the first tweet we can find
- * that was posted after we handled the entry, but before it was marked completed.
- *
- * @param {Number} end_time - Unix timestamp in ms
- * @return {Array|Boolean} tweet_id - The oldest (re)tweet id between start and end time, false if not found
- */
- function getTwitterTweet(end_time, callback) {
- /* Tweets are instantly posted to our profile, but there's a delay before they're made
- public (a few seconds). Increase the range by a few seconds to compensate. */
- end_time += (60 * 1000);
-
- MKY.xmlHttpRequest({
- url: "https://twitter.com/" + user_handle,
- method: "GET",
- onload: function(response) {
- var found_tweet = false,
- now = +new Date();
-
- // reverse the order so that we're looking at oldest to newest
- $($(response.responseText.toLowerCase()).find(
- `a[href*='${user_handle.toLowerCase()}/status/']`).get().reverse()).each(function() {
-
- var tweet_time = $(this).find("span").attr("data-time-ms"),
- tweet_id = $(this).attr("href").match(/\/([0-9]+)/);
-
- if(typeof tweet_time != "undefined" && tweet_id !== null) {
- if(deleted_tweets.indexOf(tweet_id[1]) == -1 &&
- tweet_time > start_time &&
- (tweet_time < end_time || tweet_time > now)) {
-
- // return the first match
- found_tweet = true;
- deleted_tweets.push(tweet_id[1]);
- callback(tweet_id[1]);
- return false;
- }
- }
- });
-
- // couldn't find any tweets between the two times
- if(!found_tweet) {
- callback(false);
- }
- }
- });
- }
-
- /**
- * Unfollow a twitter user
- */
- function deleteTwitterFollow(twitter_handle, twitter_id) {
- if(twitter_id === null) {
- giveawayHelperUI.showError(`Failed to unfollow Twitter user:
- <a href="https://twitter.com/${twitter_handle}" target="_blank">${twitter_handle}</a>`);
- } else {
- MKY.xmlHttpRequest({
- url: "https://api.twitter.com/1.1/friendships/destroy.json",
- method: "POST",
- headers: {
- "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
- "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAAPYXBAAAAAAACLXUNDekMxqa8h%2F40K4moUkGsoc%3DTYfbDKbT3jJPCEVnMYqilB28NHfOPqkca3qaAxGfsyKCs0wRbw",
- "x-csrf-token": csrf_token,
- },
- data: $.param({ user_id: twitter_id }),
- onload: function(response) {
- if(response.status != 200) {
- giveawayHelperUI.showError(`Failed to unfollow Twitter user:
- <a href="https://twitter.com/${twitter_handle}" target="_blank">
- ${twitter_handle}
- </a>`);
- }
- }
- });
- }
- }
-
- /**
- * Delete a tweet
- * @param {Array} tweet_id - A single tweet ID
- */
- function deleteTwitterTweet(tweet_id) {
- MKY.xmlHttpRequest({
- url: "https://twitter.com/i/tweet/destroy",
- method: "POST",
- headers: {
- "Origin": "https://twitter.com",
- "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8"
- },
- data: $.param({ _method: "DELETE", authenticity_token: auth_token, id: tweet_id }),
- onload: function(response) {
- if(response.status != 200) {
- giveawayHelperUI.showError(`Failed to delete
- <a href="https://twitter.com/${user_handle}" target="_blank">Tweet}</a>`);
- }
- }
- });
- }
-
- /**
- * Delete a retweet
- * @param {Array} tweet_id - A single retweet ID
- */
- function deleteTwitterRetweet(tweet_id) {
- MKY.xmlHttpRequest({
- url: "https://api.twitter.com/1.1/statuses/unretweet.json",
- method: "POST",
- headers: {
- "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
- "authorization": "Bearer AAAAAAAAAAAAAAAAAAAAAPYXBAAAAAAACLXUNDekMxqa8h%2F40K4moUkGsoc%3DTYfbDKbT3jJPCEVnMYqilB28NHfOPqkca3qaAxGfsyKCs0wRbw",
- "x-csrf-token": csrf_token,
- },
- data: $.param({ _method: "DELETE", id: tweet_id }),
- onload: function(response) {
- if(response.status != 200) {
- giveawayHelperUI.showError(`Failed to delete
- <a href="https://twitter.com/${user_handle}" target="_blank">Retweet</a>`);
- }
- }
- });
- }
-
- return {
- /**
- *
- */
- handleEntry: function(action_data, button_callback, ready_check, show_name, expected_user) {
- if(ready_a && ready_b) {
- prepCreateButton(action_data, button_callback, ready_check, show_name, expected_user);
- } else {
- // Wait for the command hub to load
- var temp_interval = setInterval(function() {
- if(ready_a && ready_b) {
- clearInterval(temp_interval);
- prepCreateButton(action_data, button_callback, ready_check, show_name, expected_user);
- }
- }, 100);
- }
- }
- };
- }
-
- var instance;
- return {
- getInstance: function() {
- if(!instance) instance = init();
- return instance;
- }
- };
- })();
-
- /**
- * Handles all Twitch entries that may need to interact with Twitch
- */
- var TwitchHandler = (function() {
- function init() {
- var command_hub_url = "https://player.twitch.tv/",
- command_hub_host = "player.twitch.tv",
- user_handle = null,
- api_token = null,
- button_count = 1,
- following_status = {},
- handled_channels = [],
- ready = false;
-
- // Get all the user data we'll need to undo twitch entries
- commandHub.load(
- command_hub_url,
- command_hub_host,
- function() {
- return {
- user_handle: getCookie("login"),
- api_token: getCookie("auth-token")
- };
- },
- function(data) {
- user_handle = data.user_handle;
- api_token = data.api_token;
- ready = true;
- }
- );
-
- /**
- * Get ready to create an item
- */
- function prepCreateButton(twitch_handle, button_callback, ready_check, show_name, expected_user) {
- // Wait until the entry is completed before showing the button
- var temp_interval = setInterval(function() {
- if(ready_check === null || ready_check()) {
- clearInterval(temp_interval);
- createButton(twitch_handle, button_callback, show_name, expected_user, ready_check === null);
- }
- }, 100);
- }
-
- /**
- * Create the button
- */
- function createButton(twitch_handle, button_callback, show_name, expected_user, toggle_button) {
- if(typeof expected_user !== "undefined" && !expected_user) {
- // The user doesn't have a Twitter account linked, do nothing
- } else if(user_handle === null || api_token === null) {
- // We're not logged in
- giveawayHelperUI.showError(`You must be logged into
- <a href="https://www.twitch.tv/login" target="_blank">twitch.tv</a>`);
- } else if(typeof expected_user !== "undefined" && expected_user.user_handle != user_handle) {
- // We're logged in as the wrong user
- giveawayHelperUI.showError(`You must be logged into the Twitch account linked to Gleam.io:
- <a href="https://twitch.tv/${expected_user.user_handle}" target="_blank">
- https://twitch.tv/${expected_user.user_handle}</a>`);
- } else {
- // Create the button
- var button_id = "twitch_button_" + button_count++;
-
- if(toggle_button) {
- getTwitchUserData(twitch_handle, function(is_following) {
- var label = is_following ? `Unfollow ${twitch_handle}` : `Follow ${twitch_handle}`;
-
- following_status[twitch_handle] = is_following;
-
- button_callback(
- giveawayHelperUI.buildButton(button_id, label, is_following, function() {
- toggleFollowStatus(button_id, twitch_handle);
- giveawayHelperUI.showButtonLoading(button_id);
- })
- );
- });
- } else {
- var label = `Unfollow${(show_name ? ` ${twitch_handle}` : "")}`;
-
- button_callback(
- giveawayHelperUI.buildButton(button_id, label, false, function() {
- giveawayHelperUI.removeButton(button_id);
- deleteTwitchFollow(twitch_handle);
- })
- );
- }
- }
- }
-
- /**
- *
- */
- function deleteTwitchFollow(twitch_handle, callback) {
- MKY.xmlHttpRequest({
- url: "https://api.twitch.tv/kraken/users/" + user_handle + "/follows/channels/" + twitch_handle,
- method: "DELETE",
- headers: { "Authorization": "OAuth " + api_token },
- onload: function(response) {
- if(response.status != 204 && response.status != 200) {
- giveawayHelperUI.showError(`Failed to unfollow Twitch user:
- <a href="https://twitch.tv/${twitch_handle}" target="_blank">${twitch_handle}</a>`);
-
- if(typeof callback == "function") callback(false);
- } else {
- if(typeof callback == "function") callback(true);
- }
- }
- });
- }
-
- /**
- *
- */
- function twitchFollow(twitch_handle, callback) {
- MKY.xmlHttpRequest({
- url: "https://api.twitch.tv/kraken/users/" + user_handle + "/follows/channels/" + twitch_handle,
- method: "PUT",
- headers: { "Authorization": "OAuth " + api_token },
- onload: function(response) {
- if(response.status != 204 && response.status != 200) {
- giveawayHelperUI.showError(`Failed to follow Twitch user:
- <a href="https://twitch.tv/${twitch_handle}" target="_blank">${twitch_handle}</a>`);
-
- callback(false);
- } else {
- callback(true);
- }
- }
- });
- }
-
- /**
- * @return {Boolean} is_follow - True for "following", false for "not following"
- */
- function getTwitchUserData(twitch_handle, callback) {
- MKY.xmlHttpRequest({
- url: "https://api.twitch.tv/kraken/users/" + user_handle + "/follows/channels/" + twitch_handle,
- method: "GET",
- headers: { "Authorization": "OAuth " + api_token },
- onload: function(response) {
- if(response.status === 404) {
- callback(false);
- } else if(response.status != 204 && response.status != 200) {
- giveawayHelperUI.showError(`Failed to determine follow status of Twtich user`);
- } else {
- callback(true);
- }
- }
- });
- }
-
- /**
- *
- */
- function toggleFollowStatus(button_id, twitch_handle) {
- if(following_status[twitch_handle]) {
- deleteTwitchFollow(twitch_handle, function(success) {
- if(success) {
- following_status[twitch_handle] = false;
- giveawayHelperUI.toggleButtonClass(button_id);
- giveawayHelperUI.setButtonLabel(button_id, `Follow ${twitch_handle}`);
- }
-
- giveawayHelperUI.hideButtonLoading(button_id);
- });
- } else {
- twitchFollow(twitch_handle, function(success) {
- if(success) {
- following_status[twitch_handle] = true;
- giveawayHelperUI.toggleButtonClass(button_id);
- giveawayHelperUI.setButtonLabel(button_id, `Unfollow ${twitch_handle}`);
- }
-
- giveawayHelperUI.hideButtonLoading(button_id);
- });
- }
- }
-
- return {
- /**
- *
- */
- handleEntry: function(twitch_handle, button_callback, ready_check, show_name, expected_user) {
- if(ready) {
- prepCreateButton(twitch_handle, button_callback, ready_check, show_name, expected_user);
- } else {
- // Wait for the command hub to load
- var temp_interval = setInterval(function() {
- if(ready) {
- clearInterval(temp_interval);
- prepCreateButton(twitch_handle, button_callback, ready_check, show_name, expected_user);
- }
- }, 100);
- }
- },
-
- /**
- *
- */
- findChannels: function(button_callback, target, show_name, do_cache, cache_id) {
- var self = this;
-
- giveawayHelperUI.restoreCachedLinks(cache_id).then(function(channels) {
- var re = /twitch\.tv\/([a-zA-Z0-9_]{2,25})/g,
- match;
-
- if(!do_cache) {
- channels = [];
- }
-
- while((match = re.exec(target)) !== null) {
- channels.push(match[1].toLowerCase());
- }
-
- channels = giveawayHelperUI.removeDuplicates(channels);
- if(do_cache) giveawayHelperUI.cacheLinks(channels, cache_id);
-
- for(var i = 0; i < channels.length; i++) {
- if(channels[i] == "login") continue;
-
- if($.inArray(channels[i], handled_channels) == -1) {
- handled_channels.push(channels[i]);
- self.handleEntry(channels[i], button_callback, null, show_name);
- }
- }
- });
- }
- };
- }
-
- var instance;
- return {
- getInstance: function() {
- if(!instance) instance = init();
- return instance;
- }
- };
- })();
-
- /**
- *
- */
- var giveawayHelperUI = (function() {
- var active_errors = [],
- active_buttons = {},
- gh_main_container = randomString(10),
- gh_button_container = randomString(10),
- gh_button_title = randomString(10),
- gh_button_loading = randomString(10),
- gh_spin = randomString(10),
- gh_notification_container = randomString(10),
- gh_notification = randomString(10),
- gh_error = randomString(10),
- gh_close = randomString(10),
- main_container = $("<div>", { class: gh_main_container }),
- button_container = $("<span>"),
- resolved_urls = [],
- offset_top = 0;
-
- /**
- * Generate a random alphanumeric string
- * http://stackoverflow.com/questions/10726909/random-alpha-numeric-string-in-javascript
- */
- function randomString(length) {
- var result = '';
- var chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
-
- for(var i = length; i > 0; --i) {
- result += chars[Math.floor(Math.random() * chars.length)];
- }
-
- return result;
- }
-
- /**
- * Push the page down to make room for notifications
- */
- function updateTopMargin() {
- var new_margin_top = main_container.outerHeight() + main_container.position().top - offset_top;
-
- $("html").css("margin-top", main_container.is(":visible") ? new_margin_top : 0);
- }
-
- return {
- gh_button: randomString(10),
- gh_button_on: randomString(10),
- gh_button_off: randomString(10),
- gh_redeem_button: randomString(10),
-
- /**
- * Print the UI
- */
- loadUI: function(zIndex, onLoad) {
- zIndex = typeof zIndex == "undefined" ? 9999999999 : zIndex;
-
- if(typeof onLoad == "function") onLoad();
-
- MKY.addStyle(`
- html {
- overflow-y: scroll !important;
- }
-
- .${gh_main_container} {
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
- font-size: 16.5px;
- left: 0px;
- line-height: 21px;
- position: fixed;
- text-align: left;
- top: 0px;
- right: 0px;
- z-index: ${zIndex};
- }
-
- .${gh_button_container} {
- background-color: #000;
- border-top: 1px solid rgba(52, 152, 219, .5);
- box-shadow: 0px 2px 10px rgba(0, 0, 0, .5);
- box-sizing: border-box;
- color: #3498db;
- padding: 8px;
- }
-
- .${gh_button_title} {
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
- padding: 10px 15px;
- margin-right:8px;
- }
-
- .${gh_button_loading} {
- -webkit-animation: ${gh_spin} 2s infinite linear;
- animation: ${gh_spin} 2s infinite linear;
- display: inline-block;
- font: normal normal normal 14px/1;
- transform-origin: 45% 55%;
- }
-
- .${gh_button_loading}:before {
- content: "\\21B7";
- }
-
- @-webkit-keyframes ${gh_spin} {
- 0% {
- -webkit-transform:rotate(0deg);
- transform:rotate(0deg);
- }
- 100%{
- -webkit-transform:rotate(359deg);
- transform:rotate(359deg);
- }
- }
-
- @keyframes ${gh_spin} {
- 0% {
- -webkit-transform:rotate(0deg);
- transform:rotate(0deg);
- }
- 100% {
- -webkit-transform:rotate(359deg);
- transform:rotate(359deg);
- }
- }
-
- .${gh_notification} {
- box-sizing: border-box;
- padding: 8px;
- }
-
- .${gh_error} {
- background: #f2dede;
- box-shadow: 0px 2px 10px rgba(231, 76, 60, .5);
- color: #a94442;
- }
-
- .${gh_error} a {
- color: #a94442;
- font-weight: 700;
- }
-
- .${gh_close} {
- color: #000;
- background: 0 0;
- border: 0;
- cursor: pointer;
- display: block;
- float: right;
- font-size: 21px;
- font-weight: 700;
- height: auto;
- line-height: 1;
- margin: 0px;
- opacity: .2;
- padding: 0px;
- text-shadow: 0 1px 0 #fff;
- width: auto;
- }
-
- .${gh_close}:hover {
- opacity: .5;
- }
- `);
-
- $("body").append(main_container);
- },
-
- /**
- *
- */
- defaultButtonSetup: function(offset) {
- MKY.addStyle(`
- .${this.gh_button} {
- background-image:none;
- border: 1px solid transparent;
- border-radius: 3px !important;
- cursor: pointer;
- display: inline-block;
- font-family: "Helvetica Neue",Helvetica,Arial,sans-serif;
- font-size: 12px;
- font-weight: 400;
- height: 30px;
- line-height: 1.5 !important;
- margin: 4px 8px 4px 0px;
- padding: 5px 10px;
- text-align: center;
- vertical-align: middle;
- white-space: nowrap;
- }
-
- .${this.gh_button}:active {
- box-shadow: inset 0 3px 5px rgba(0,0,0,.125);
- outline: 0;
- }
-
- .${this.gh_button_on} {
- background-color: #337ab7;
- border-color: #2e6da4;
- color: #fff;
- }
-
- .${this.gh_button_on}:hover {
- background-color: #286090;
- border-color: #204d74;
- color: #fff;
- }
-
- .${this.gh_button_off} {
- background-color: #d9534f;
- border-color: #d43f3a;
- color: #fff;
- }
-
- .${this.gh_button_off}:hover {
- background-color: #c9302c;
- border-color: #ac2925;
- color: #fff;
- }
-
- .${this.gh_redeem_button} {
- background-color: #5cb85c;
- border-color: #4cae4c;
- color: #fff;
- }
- `);
-
- if(typeof offset !== "undefined") {
- main_container.css({top: offset[0], left: offset[1], right: offset[2]});
- offset_top = offset[0];
- }
-
- main_container.append(
- $("<div>", { class: gh_button_container }).append(
- $("<span>", { class: gh_button_title }).html("Giveaway Helper v" + MKY.info.script.version)
- ).append(button_container)
- );
-
- updateTopMargin();
- },
-
- /**
- *
- */
- addButton: function(new_button) {
- button_container.append(new_button);
- new_button.width(new_button.outerWidth());
- updateTopMargin();
- },
-
- /**
- *
- */
- buildButton: function(button_id, label, button_on, click_function) {
- var new_button =
- $("<button>", { type: "button",
- class: `${this.gh_button} ${button_on ? this.gh_button_on : this.gh_button_off}`
- }).append(
- $("<span>").append(label)).append(
- $("<span>", { class: gh_button_loading, css: { display: "none" }})
- ).click(function(e) {
- e.stopPropagation();
- if(!active_buttons[button_id].find(`.${gh_button_loading}`).is(":visible")) {
- click_function();
- }
- });
-
- active_buttons[button_id] = new_button;
- return new_button;
- },
-
- /**
- *
- */
- buildRedeemButton: function(button_id, label, redeem_url) {
- var new_button =
- $("<a>", { href: redeem_url, target: "_blank" }).append(
- $("<button>", { type: "button",
- class: `${this.gh_button} ${this.gh_redeem_button}`
- }).append(
- $("<span>").append(label)
- )
- );
-
- active_buttons[button_id] = new_button;
- return new_button;
- },
-
-
-
- /**
- *
- */
- removeButton: function(button_id) {
- active_buttons[button_id].remove();
- delete active_buttons[button_id];
- },
-
- /**
- *
- */
- setButtonLabel: function(button_id, label, color) {
- active_buttons[button_id].find("span").first().text(label);
-
- if(color !== undefined) {
- active_buttons[button_id].css("background-color", color);
- active_buttons[button_id].css("border-color", color);
- }
- },
-
- /**
- *
- */
- toggleButtonClass: function(button_id) {
- active_buttons[button_id].toggleClass(this.gh_button_on);
- active_buttons[button_id].toggleClass(this.gh_button_off);
- },
-
- /**
- *
- */
- showButtonLoading: function(button_id) {
- active_buttons[button_id].find("span").first().hide();
- active_buttons[button_id].find(`.${gh_button_loading}`).show();
- },
-
- /**
- *
- */
- hideButtonLoading: function(button_id) {
- active_buttons[button_id].find("span").first().show();
- active_buttons[button_id].find(`.${gh_button_loading}`).hide();
- },
-
- /**
- * Print an error
- */
- showError: function(msg) {
- // Don't print the same error multiple times
- if(active_errors.indexOf(msg) != -1) return;
-
- var self = this;
-
- active_errors.push(msg);
- main_container.append(
- $("<div>", { class: `${gh_notification} ${gh_error}` }).append(
- $("<button>", { class: gh_close}).append(
- $("<span>").html("×")
- ).click(function() {
- $(this).unbind("click");
- $(this).parent().slideUp(400, function() {
- active_errors.splice(active_errors.indexOf(msg), 1);
- $(this).remove();
- updateTopMargin();
- });
- })
- ).append(
- $("<strong>").html("Giveaway Helper Error: ")
- ).append(msg)
- );
-
- updateTopMargin();
- },
-
- /**
- * Remove duplicate items from an array
- */
- removeDuplicates: function(arr) {
- var out = [];
-
- for(var i = 0; i < arr.length; i++) {
- if (out.indexOf(arr[i]) == -1) {
- out.push(arr[i]);
- }
- }
-
- return out;
- },
-
- /**
- * Some sites remove links to a group after you get your reward, remember which links we've seen where
- */
- cacheLinks: function(data, id) {
- MKY.setValue(id, JSON.stringify(data));
- },
-
- /**
- *
- */
- restoreCachedLinks: function(id) {
- return MKY.getValue(id, JSON.stringify([])).then(function(value) {
- return JSON.parse(value);
- });
- },
-
- /**
- *
- */
- resolveUrl: function(url, callback) {
- var self = this,
- cached_url_id = `cache_${MKY.info.script.version.replace(/\./g,"_")}_${CryptoJS.MD5(url)}`;
-
- self.restoreCachedLinks(cached_url_id).then(function(value){
- if(value.length !== 0) {
- callback(value[0]);
- } else {
- self.cacheLinks([false], cached_url_id);
-
- MKY.xmlHttpRequest({
- url: url,
- method: "GET",
- onload: function(response) {
- if(response.status == 200 && response.finalUrl !== null) {
- self.cacheLinks([response.finalUrl], cached_url_id);
- }
-
- self.restoreCachedLinks(cached_url_id).then(function(final_url){
- callback(final_url);
- });
- }
- });
- }
- });
- }
- };
- })();
-
- /**
- * Used to communicate with and run code on a different domain
- * Usualy with the intent to grab necessary cookies
- */
- var commandHub = (function() {
- /**
- * http://stackoverflow.com/a/15724300
- */
- function getCookie(name) {
- var value = "; " + document.cookie,
- parts = value.split("; " + name + "=");
-
- if(parts.length == 2) {
- return parts.pop().split(";").shift();
- } else {
- return null;
- }
- }
-
- return {
- /**
- * Load an iframe so that we can run code on a different domain
- * @param {String} url - The url to be loaded into the iframe
- * @param {Function} data_func - The code that we're going to run inside the iframe
- * @param {Function} callback - Runs after data_func returns
- */
- load: function(url, hostname, data_func, callback) {
- var command_hub = document.createElement('iframe');
-
- command_hub.style.display = "none";
- command_hub.src = url;
- document.body.appendChild(command_hub);
-
- hostname = hostname.replace(/\./g, "_");
-
- var funcvar = `command_hub_func_${hostname}`,
- retvar = `command_hub_return_${hostname}`;
-
- window.addEventListener("message", function(event) {
- if(event.source == command_hub.contentWindow) {
- if(event.data.status == "ready") {
- // the iframe has finished loading, tell it what to do
- MKY.setValue(funcvar, encodeURI(data_func.toString()));
- command_hub.contentWindow.postMessage({ status: "run" }, "*");
- } else if(event.data.status == "finished") {
- // wait until the values have been set
- var temp_interval = setInterval(function() {
- MKY.getValue(retvar).then(function(value) {
- if(typeof value !== "undefined") {
- clearInterval(temp_interval);
-
- // the iframe has finished, send the data to the callback and close the frame
- document.body.removeChild(command_hub);
- callback(value);
- MKY.deleteValue(retvar);
- }
- });
- }, 100);
- }
- }
- });
- },
-
- /**
- *
- */
- init: function() {
- var hostname = document.location.hostname.replace(/\./g, "_"),
- funcvar = `command_hub_func_${hostname}`,
- retvar = `command_hub_return_${hostname}`;
-
- // wait for our parent to tell us what to do
- window.addEventListener("message", function(event) {
- if(event.source == parent) {
- if(event.data.status == "run") {
- // wait until the values have been set
- var temp_interval = setInterval(function() {
- MKY.getValue(funcvar).then(function(value) {
- if(typeof value !== "undefined") {
- clearInterval(temp_interval);
- MKY.setValue(retvar, eval(`(${decodeURI(value)})`)());
- MKY.deleteValue(funcvar);
- parent.postMessage({ status: "finished" }, "*");
- }
- });
- }, 100);
- }
- }
- });
-
- // let the parent know the iframe is ready
- parent.postMessage({status: "ready"}, "*");
- }
- };
- })();
-
- // Greasemonkey 4 polyfill
- // https://arantius.com/misc/greasemonkey/imports/greasemonkey4-polyfill.js
-
- var MKY = typeof GM !== "undefined" ? GM : {
- 'info': GM_info,
- 'addStyle': GM_addStyle,
- 'xmlHttpRequest': GM_xmlhttpRequest,
- 'deleteValue': GM_deleteValue,
- 'setValue': GM_setValue,
- 'getValue': function () {
- return new Promise((resolve, reject) => {
- try {
- resolve(GM_getValue.apply(this, arguments));
- } catch (e) {
- reject(e);
- }
- });
- }
- };
-
- if(typeof GM_addStyle == 'undefined' || typeof MKY.addStyle == 'undefined') {
- MKY.addStyle = function(aCss) {
- 'use strict';
- let head = document.getElementsByTagName('head')[0];
- if(head) {
- let style = document.createElement('style');
- style.setAttribute('type', 'text/css');
- style.textContent = aCss;
- head.appendChild(style);
- return style;
- }
- return null;
- };
- }
-
- setup.run();
- })();