Enhanced Barter

This userscript aims to enhance your experience at barter.vg

目前為 2017-08-05 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Enhanced Barter
// @icon         https://bartervg.com/imgs/ico/barter/favicon-32x32.png
// @namespace    Royalgamer06
// @author       Royalgamer06
// @version      0.9.4.1
// @description  This userscript aims to enhance your experience at barter.vg
// @include      https://barter.vg/*
// @include      https://www.steamtrades.com/user/*?do=postcomments&message=*
// @connect      steamcommunity.com
// @connect      store.steampowered.com
// @connect      steamtrades.com
// @connect      royalgamer06.ga
// @grant        GM_xmlhttpRequest
// @grant        GM_setClipboard
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        unsafeWindow
// @require      https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js
// @homepageURL  https://github.com/Royalgamer06/EnhancedBarter/
// @supportURL   https://github.com/Royalgamer06/EnhancedBarter/issues
// ==/UserScript==

this.$ = this.jQuery = jQuery.noConflict(true);
$.fn.serializeObject = function() {
    var o = {};
    var a = this.serializeArray();
    $.each(a, function() {
        if (o[this.name] !== undefined) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || "");
        } else {
            o[this.name] = this.value || "";
        }
    });
    return o;
};
$.fn.zip = function(s) {
    var o = $(s);
    return this.map(function(i, e) {
        return $(e).add($(o[i]));
    });
};
var myuid, mysid;
$(document).ready(function() {
    if (location.host == "barter.vg") {
        myuid = $("#signin").attr("href").split("/")[4];
        mysid = $("abbr+ a:has(.icon)").length > 0 ? $("abbr+ a:has(.icon)").attr("href").split("/")[4] : 0;
        unsafeWindow.cancelOffers = cancelOffers;
        unsafeWindow.remindPendingOffers = remindPendingOffers;
        unsafeWindow.remindCompletedOffers = remindCompletedOffers;
        unsafeWindow.fixIgnored = fixIgnored;
        unsafeWindow.showIgnored = showIgnored;
        unsafeWindow.findIgnored = findIgnored;
        unsafeWindow.findAllIgnored = findAllIgnored;
        unsafeWindow.syncLibrary = syncLibrary;
        unsafeWindow.extendExpiry = extendExpiry;
        unsafeWindow.massSendOffers = massSendOffers;
        unsafeWindow.massSendMutualOffers = massSendMutualOffers;
        unsafeWindow.removeOwnedGamesFromPending = removeOwnedGamesFromPending;
        $("[name=offer_message]").removeAttr("maxlength");
        if (location.href.indexOf("/u/") > -1) {
            if (location.href.indexOf("/o/") > -1) {
                if (location.href.indexOf(myuid) > -1 && $("input[value='Completed Offer']").length > 0) {
                    console.log("Found 'Completed Offer'");
                    $("input[value='Completed Offer']").click(function(ev) {
                        ev.preventDefault();
                        var steamid = $("a[href*='/steamcommunity.com/profiles/']:not([href*=" + mysid + "])").attr("href").split("/")[4];
                        var name = $("th:contains('Next Step')+ > a[href*='/steamcommunity.com/profiles/']").text().replace(" on Steam", "");
                        var msg = "+REP " + name + " is an amazing trader, recommended! We successfully completed this trade: " + location.href + ". Thanks a lot for the trade!";
                        leaveFeedback(this, msg, steamid);
                    });
                } else if (location.href.indexOf(myuid) > -1 && $(".activity").length > 0) {
                    $(".activity").first().before("<br><strong>Or...  </strong><input id=automatedoffer type=submit value='Begin Automated Offer'></input><input id=removeowned type=submit value='Remove Owned Games From Pending Offers' style='float:right;'></input>");
                    $("#automatedoffer").click(function() {
                        var want_name = prompt("Offering:", "Exact Game Title");
                        var offering_to_group = prompt("Make offers to group:", "wishlist, unowned").split(",").map(Function.prototype.call, String.prototype.trim); //tradable, wishlist, unowned, library, blacklist
                        var max_trades = prompt("Maximum number of trades you want to send (no limit = all):", "all");
                        var want_from_group = prompt("I want games/DLC from group:", "wishlist, unowned").split(",").map(Function.prototype.call, String.prototype.trim); //tradable, wishlist, unowned, library
                        var max_want = prompt("Maximum number of games/DLC I want to ask (no limit = all):", "25");
                        var ratio = prompt("Ratio of offering (mine) against want (yours):", "all:1");
                        var expire_days = parseInt(prompt("Days until offer expires (max = 15):", "15"));
                        var trading_cards_only = confirm("Do you only want games with trading cards? (cancel = no)");
                        var unbundled_only = confirm("Do you only want unbundled games/DLC? (cancel = no)");
                        var exclude_givenaway = confirm("Do you want to exclude given away (free) games? (cancel = no)");
                        //var exclude_combined = confirm("Do you want to exclude combined games (bundles, packs)?");
                        var exclude_rating_lower_than = parseInt(prompt("Minimum game/dlc rating (unrated games/DLC will be included):", "0"));
                        if (exclude_rating_lower_than === null || isNaN(exclude_rating_lower_than) || !isFinite(exclude_rating_lower_than)) {
                            exclude_rating_lower_than = false;
                        }
                        var exclude_title_containing = prompt("Exclude games/DLC containing the term(s):", "DLC, pack");
                        if (exclude_title_containing !== null && exclude_title_containing !== "") {
                            exclude_title_containing = exclude_title_containing.split(",").map(Function.prototype.call, String.prototype.trim);
                        } else {
                            exclude_title_containing = false;
                        }
                        if (confirm("Are you sure you want to send this automated offer?\nBeware that this may cause traders to add you to their ignore list!")) {
                            console.log("Sending mass offers...",
                                        want_name,
                                        offering_to_group,
                                        max_trades,
                                        want_from_group,
                                        max_want,
                                        ratio,
                                        expire_days,
                                        trading_cards_only,
                                        unbundled_only,
                                        exclude_givenaway,
                                        exclude_rating_lower_than,
                                        exclude_title_containing);
                            massSendOffers(want_name,
                                           offering_to_group,
                                           max_trades,
                                           want_from_group,
                                           max_want,
                                           ratio,
                                           expire_days,
                                           trading_cards_only,
                                           unbundled_only,
                                           exclude_givenaway,
                                           exclude_rating_lower_than,
                                           exclude_title_containing);
                            alert("Initiated process of sending automated offers!\nCheck the javascript console (F12) and network tab for details.\nPlease don't close this tab until all offers have finished sending.\nThis may take a few minutes.");
                        }
                    });
                    $("#removeowned").click(function() {
                        if (confirm("Are you sure you want to remove owned games from pending offers?")) {
                            removeOwnedGamesFromPending();
                            alert("Initiated process of removing owned games from pending offers!\nCheck the javascript console (F12) for details.\nPlease don't close this tab until all offers have finished updating.");
                        }
                    });
                }
                /*$("#offerHeader > tbody > tr:nth-child(1)").append('<button style="float: right; height: 100%;" id="switchsides">Switch Sides</button>');
                $("#switchsides").click(function() {
                    var rem = $("#main > h1 > a:nth-child(2)").attr("href").split("/")[4];
                    var uids = [];
                    $("#offerHeader > tbody > tr > td:nth-child(2) > strong > a").each(function() {
                        uids.push(this.href.split("/")[4]);
                    });
                    uids.splice($.inArray(rem, uids), 1);
                    var uid = uids[0];
                    console.log(location.href.split(rem)[0] + uid + location.href.split(rem)[1]);
                    //location.href = location.href.split(rem)[0] + uid + location.href.split(rem)[1];
                });*/
                //$("select[name=expire_days] > option[selected=selected]").html("1000");
                [3, 7].forEach(function(i) {
                    $("#exchanges > fieldset:nth-child(" + i + ")").append('<input type="submit" value="Invert all checkboxes" style="width:100%;height:2em;margin-bottom:.7em;" id="checkall' + i + '">');
                    $("#checkall" + i).on("click", function() {
                        $("#exchanges > fieldset:nth-child(" + i + ") input[type=checkbox]").each(function() {
                            this.checked = !this.checked;
                        });
                        return false;
                    });
                    $("#exchanges > fieldset:nth-child(" + i + ")").append('<input type="submit" value="Enable disabled tradables" style="width:100%;height:2em;margin-bottom:.7em;" id="enable' + i + '">');
                    $("#enable" + i).on("click", function(ev) {
                        ev.preventDefault();
                        if (confirm("Are you sure you want to enable disabled tradables? Make sure the other party is okay with this!")) {
                            setTimeout(function() {
                                $("#exchanges > fieldset:nth-child(" + i + ") input[disabled]").each(function() {
                                    this.removeAttribute("disabled");
                                    this.removeAttribute("title");
                                    this.name = "add_to_offer_1[]";
                                    this.id = $(this).find("+").attr("for");
                                    this.value = $(this).parent().find("a").attr("href").split("/")[4] + "," + $(this).find("+").attr("for").replace("edit", "");
                                });
                            }, 0);
                        }
                        $("#enable").hide();
                    });
                });
            } else if ($("#profileStats").length > 0) {
                /*if ($("form[action*='/o/']").length === 0) {
                    var profileid = location.href.split("/")[4];
                    var uid = parseInt(profileid, 16);
                    GM_setValue("ignored", GM_getValue("ignored", "") + profileid + ",");
                    $("#profileStats").after('<form action="/u/' + myuid + '/o/" method="POST" class="inline" style="margin:0em 3em 0 0;"><p><input type="hidden" name="to_user_id" value="' + uid + '"><input type="hidden" name="offer_setup" value="1"><input type="submit" value="Send offer on Barter.vg (Ignored)" id="offerButton"></p></form>');
                }*/
            }
        } else if (location.href.indexOf("/i/") > -1) {
            Array.from(document.getElementById("swishlist").parentNode.getElementsByTagName("a")).forEach(function(a) {
                a.setAttribute("href", a.href.replace("w/m/", "") + "t/f/");
                a.setAttribute("target", "_blank");
                a.onclick = function() {
                    this.parentNode.parentNode.removeChild(this.parentNode);
                };
            });
        }
    } else if (location.host == "www.steamtrades.com" && getURIParam("do") == "postcomments") {
        var steamid = getURIParam("steamid");
        var msg = applySentenceCase(getURIParam("message").replace(/\+/g, ' '));
        var profile_id = $("[name=profile_id]").val();
        var xsrf_token = $("[name=xsrf_token]").val();
        if (profile_id !== undefined) {
            var obj = { do: "review_insert", xsrf_token: xsrf_token, profile_id: profile_id, rating: 1, description: msg };
            console.log(obj);
            $.ajax({
                url: "https://www.steamtrades.com/ajax.php",
                method: "POST",
                data: obj,
                success: function() {
                    unsafeWindow.close();
                }
            });
        } else {
            console.log("Already left feedback previously");
            unsafeWindow.close();
        }
    }
});

function syncLibrary(callback) {
    $.post("/u/" + myuid + "/l/", { sync_list: "↻ Sync List", type: 1 });
    var v = parseInt(GM_getValue("dsudv", 1));
    v++;
    GM_setValue("dsudv", v);
    GM_xmlhttpRequest({
        method: "GET",
        url: "http://store.steampowered.com/dynamicstore/userdata/?v=" + v,
        onload: function(response) {
            var json = JSON.parse(response.responseText);
            var ownedApps = json.rgOwnedApps;
            $.post("/u/" + myuid + "/l/e/", { bulk_AppIDs: ownedApps.join(","), add_AppIDs: "+ Add AppIDs", action: "Edit", change_attempted: 1, add_from: "AppIDs" }, function() {
                if (callback) callback();
            });
        }
    });
}

function fixIgnored() {
    var y = $.unique(GM_getValue("ignored").split(","));
    y.splice( $.inArray(myuid, y), 1 );
    GM_setValue("ignored", y.join(","));
}

function showIgnored() {
    fixIgnored();
    console.log(GM_getValue("ignored").slice(0, -1).split(","));
}

function findIgnored() {
    $.get("/u/" + myuid + "/o/", function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        var users = [];
        $("[href*='/u/']", data).each(function() {
            let url = this.href;
            if (/^https?:\/\/barter\.vg\/u\/[a-zA-Z0-9]{1,5}\/$/.test(url) && $.inArray(url, users) == -1) {
                $.get(url, function(data) {
                    data = data.replace(/src="[^"]*"/ig, "");
                    var ignored = $.unique(GM_getValue("ignored", "").split(","));
                    if ($("form[action*='/o/']", data).length === 0 && $.inArray(url.split("/")[4], ignored) == -1 && url.split("/")[4] !== myuid) {
                        GM_setValue("ignored", ignored.join(",") + url.split("/")[4] + ",");
                    }
                });
            }
        });
        fixIgnored();
    });
}

function findAllIgnored() {
    $.getJSON("https://barter.vg/u/json/", function(json) {
        for (var uid in json) {
            if (json[uid].active > -1) {
                isIgnored("https://barter.vg/u/" + uid + "/");
            }
        }
    });
}


function isIgnored(url) {
    $.get(url, function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        var ignored = $.unique(GM_getValue("ignored", "").split(","));
        if ($("form[action*='/o/']", data).length === 0 && $.inArray(url.split("/")[4], ignored) == -1 && url.split("/")[4] !== myuid) {
            GM_setValue("ignored", ignored.join(",") + url.split("/")[4] + ",");
        }
    });
}

function remindPendingOffers() {
    var reminder = "Hey, I saw that you looked at the offer. Would you please be so kind and respond to it as well? I'd appreciate that very much! Thank you!";
    $("tr.active [title*=Opened]+:contains('pending')").each(function() {
        $.post(this.href, { offer_message: reminder, offer_setup: 3 });
    });
    /*var msg = "Hello, I sent you an trade offer on barter. Could you please take a look and respond? I would appreciate that! Thank you!";
    var steamids = [];
    var ajaxDone = 0;
    $.post("/u/" + myuid + "/o/", { filter_by_status: "pending" }, function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        var count = $(".active:contains('pending')", data).length;
        $($(".active:contains('pending')", data).get().reverse()).each(function() {
            let url = $(this).find("td+ td a").attr("href");
            $.get(url, function(data) {
                data = data.replace(/src="[^"]*"/ig, "");
                var id = $("abbr+ a", data).attr("href").split("/")[4];
                steamids.push(id);
            }).always(function() {
                ajaxDone++;
                if (ajaxDone == count) {
                    postSteamComment(msg, steamids);
                }
            });
        });
    });*/
}

function remindCompletedOffers() {
    var steammsg = "Hello, please mark our trade as complete on barter. I would appreciate that! Thank you!";
    var bartermsg = "Hello, please mark our trade as complete. I would appreciate that! Thank you!";
    var steamids = [];
    var ajaxDone = 0;
    $.post("/u/" + myuid + "/o/", { filter_by_status: "completed" }, function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        var count = $(".active:contains('completed'):not(.completed)", data).length;
        $($(".active:contains('completed'):not(.completed)", data).get().reverse()).each(function() {
            let url = $(this).find("td+ td a").attr("href");
            $.post(url, { offer_message: bartermsg, offer_setup: 3 });
            /*$.get(url, function(data) {
                data = data.replace(/src="[^"]*"/ig, "");
                var id = $("abbr+ a", data).attr("href").split("/")[4];
                steamids.push(id);
            }).always(function() {
                ajaxDone++;
                if (ajaxDone == count) {
                    postSteamComment(steammsg, steamids);
                }
            });*/
        });
    });
}

function leaveFeedback(elem, msg, steamid) {
    $(elem).val("Completing trade, sending feedback and syncing library...").attr("disabled", true);
    $.post($(elem).parents("form").attr("action"), $(elem).parents("form").serializeObject());
    var steamids = [steamid];
    //postSteamComment(msg, steamids);
    postSteamTradesComment(msg, steamid);
    setPostTradeClipboard();
    syncLibrary(function() {
        location.reload();
    });
}

function setPostTradeClipboard() {
    var uids = [];
    $("#offerHeader > tbody > tr > td:nth-child(2) > strong > a").each(function() {
        uids.push(this.href.split("/")[4]);
    });
    uids.splice($.inArray(myuid, uids), 1);
    var uid = uids[0];
    var tradelink = location.href.split(myuid)[0] + uid + location.href.split(myuid)[1];
    var sgprofile = "https://www.steamtrades.com/user/" + mysid;
    var msg = "Thanks for the trade!\nI completed the trade on barter.vg and left feedback on your steamtrades profile.\nIf you haven't done so already, could you please do the same?\n" + tradelink + "\n" + sgprofile;
    GM_setClipboard(msg);
}

function postSteamTradesComment(msg, steamid, callback) {
    //$("body").append("<iframe src='https://www.steamtrades.com/user/" + steamid + "?do=postcomments&message=" + msg + "' style='display: none;' />");
    window.open("https://www.steamtrades.com/user/" + steamid + "?do=postcomments&message=" + msg, "_blank");
}

function massSendOffers(want_name,
                         offering_to_group,
                         max_trades,
                         want_from_group,
                         max_want, ratio,
                         expire_days,
                         trading_cards_only,
                         unbundled_only,
                         exclude_givenaway,
                         exclude_rating_lower_than,
                         exclude_title_containing) {
    if (!want_name) return alert("No argument \"want_name\". Example: \"The Forest\"");
    $.getJSON("/u/" + myuid + "/t/json/", function(mytradables) {
        var offering = false;
        for (var platformid in mytradables.by_platform) {
            for (var tradeid in mytradables.by_platform[platformid]) {
                let tradable = mytradables.by_platform[platformid][tradeid];
                if ((tradable.title ? tradable.title.toLowerCase() === want_name.toLowerCase() : false) ||
                    (tradable.title_alt ? tradable.title_alt.toLowerCase() === want_name.toLowerCase() : false) ||
                    (tradable.title_formatted ? tradable.title_formatted.toLowerCase() === want_name.toLowerCase() : false) ||
                    (tradable.title_extra ? tradable.title_extra.toLowerCase() === want_name.toLowerCase() : false)) {
                    console.log("Tradable:", tradable);
                    offering = tradable.item_id + "," + tradeid;
                    break;
                }
            }
        }
        if (!offering) return alert("Could not find tradable!\nPlease provide a more accurate name of your tradable and make sure this item is in your tradables list.");
        syncLibrary(function() {
            GM_xmlhttpRequest({
                method: "GET",
                url: "https://royalgamer06.ga/barter/json.php",
                onload: function(response) {
                    var optins = JSON.parse(response.responseText);
                    $.getJSON("/i/" + offering.split(",")[0] + "/json2/", function(gameinfo) {
                        /*
                    TODO:
                     - Add platform exclusion support
                     - Add tag exclusion support
                     - Add tradable-wishlist-ratio support
                     - Add counter preference support
                     - Add custom message support
                     - Add multi-offerings support
                     - Add better UI
                     */

                        //SETUP
                        offering_to_group = offering_to_group ? offering_to_group : ["wishlist"]; //tradable, wishlist, library, blacklist
                        max_trades = max_trades ? max_trades : Number.MAX_SAFE_INTEGER;
                        max_trades = parseInt(max_trades.replace(/all/gi, Number.MAX_SAFE_INTEGER));
                        want_from_group = want_from_group ? want_from_group.filter(function(group) { return !!group.toLowerCase().match(/^(tradable|wishlist|unowned|library)$/g); }) : ["wishlist"]; //tradable, wishlist, library, blacklist, unowned
                        max_want = max_want ? max_want : Number.MAX_SAFE_INTEGER;
                        max_want = parseInt(max_want.replace(/all/gi, Number.MAX_SAFE_INTEGER));
                        ratio = ratio ? ratio.toLowerCase().trim() : "all:1";
                        ratio = ratio.replace(/all/gi, "0").split(":");
                        expire_days = expire_days ? expire_days : 1000;
                        trading_cards_only = typeof trading_cards_only !== "undefined" ? trading_cards_only : false;
                        unbundled_only = typeof unbundled_only !== "undefined" ? unbundled_only : false;
                        exclude_givenaway = typeof exclude_givenaway !== "undefined" ? exclude_givenaway : false;
                        //exclude_combined = typeof exclude_combined !== "undefined" ? exclude_combined : false;
                        exclude_rating_lower_than = exclude_rating_lower_than ? exclude_rating_lower_than : 0;
                        exclude_title_containing = exclude_title_containing ? new RegExp(exclude_title_containing.join("|"), "gi") : new RegExp(".^");
                        //EXECUTION
                        var trade_count = 0;
                        shuffle(offering_to_group).forEach(function(group) {
                            group = group.toLowerCase();
                            var users = shuffle(Object.keys(gameinfo.users[group]));
                            users.forEach(function(userid) {
                                let uid = parseInt(userid);
                                let user = gameinfo.users[group][uid];
                                if ((optins.hasOwnProperty(user.steam_id64) ? optins[user.steam_id64] : true) &&
                                    user.tradeable_count >= parseInt(ratio[1]) &&
                                    trade_count <= max_trades) {
                                    $.getJSON("/u/" + uid.toString(16) + "/t/f/" + myuid + "/json/", function(tradable_groups) {
                                        $.getJSON("/u/" + uid.toString(16) + "/t/json/", function(tradables) {
                                            var ato2 = [];
                                            var platforms = shuffle(Object.keys(tradables.by_platform));
                                            platforms.forEach(function(platformid) {
                                                var tradeids = shuffle(Object.keys(tradables.by_platform[platformid]));
                                                tradeids.forEach(function(tradeid) {
                                                    let tradable = tradables.by_platform[platformid][tradeid];
                                                    if (ato2.length <= max_want &&
                                                        isInWantGroup(tradable_groups, want_from_group, tradable.item_id) &&
                                                        tradable.extra > 0 &&
                                                        (trading_cards_only ? tradable.cards > 0 : true) &&
                                                        (unbundled_only ? tradable.bundles_all === 0 : true) &&
                                                        (exclude_givenaway ? tradable.givenaway === 0: true) &&
                                                        (tradable.reviews_positive ? tradable.reviews_positive > exclude_rating_lower_than : true) &&
                                                        !((tradable.title ? !!tradable.title.match(exclude_title_containing) : false) ||
                                                          (tradable.title_alt ? !!tradable.title_alt.match(exclude_title_containing) : false) ||
                                                          (tradable.title_formatted ? !!tradable.title_formatted.match(exclude_title_containing) : false) ||
                                                          (tradable.title_extra ? !!tradable.title_extra.match(exclude_title_containing) : false))) {
                                                        ato2.push(tradable.item_id + "," + tradeid);
                                                    }
                                                });
                                            });
                                            //console.log(ato2);
                                            if (ato2.length >= parseInt(ratio[1]) && trade_count <= max_trades) {
                                                trade_count++;
                                                $.post("/u/" + myuid + "/o/json/", {
                                                    "to": uid,
                                                    "from_and_or": ratio[0],
                                                    "to_and_or": ratio[1],
                                                    "expire": expire_days,
                                                    "counter_preference": 1,
                                                    "add_to_offer_from[]": offering,
                                                    "add_to_offer_to[]": ato2,
                                                    "message": `This is an offer sent by this script: http://steamcommunity.com/groups/bartervg/discussions/6/1470841715930902039.
You may unsubscribe from anyone's automated offers here: http://royalgamer06.ga/barter.
I'm responsible for this trade (not script author)!`
                                                });
                                            }
                                        });
                                    });
                                }
                            });
                        });
                    });
                }
            });
        });
    });
}

function isInWantGroup(tradable_groups, want_from_group, item_id) {
    var isInWantGroup = false;
    want_from_group.forEach(function(group) {
        if ($.inArray(item_id, tradable_groups[group]) > -1) {
            isInWantGroup = true;
        }
    });
    return isInWantGroup;
}

function massSendMutualOffers(ratio, expire_days, trade_game, only_offer_trade_game) {
    ratio = ratio ? ratio : "all:1";
    ratio = ratio.replace(/all/g, "0").split(":");
    expire_days = expire_days ? expire_days : 1000;
    trade_game = trade_game ? trade_game : 0;
    only_offer_trade_game = only_offer_trade_game ? only_offer_trade_game : false;
    syncLibrary();
    console.log(ratio, expire_days, trade_game, only_offer_trade_game);
    $.post("/u/" + myuid + "/t/m/?", { tradeGame: trade_game, tradeUser: -2, expandAll: "on", openNewTab: "on", findMatches: "Mutual Matches" }, function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        console.log($("#mutualMatches tr:has([name=offer_setup])", data).zip("#mutualMatches tr:has([href*='/i/'])", data));
        $("#mutualMatches tr:has([name=offer_setup])", data).zip($("#mutualMatches tr:has([href*='/i/'])", data)).each(function() {
            console.log(this);
            let form = $(this).find("form:has([name=offer_setup])");
            console.log(form);
            let offering = [];
            if (only_offer_trade_game) {
                offering.push(trade_game);
            } else {
                $(this).find(".mh > a").each(function() {
                    offering.push(this.href.split("/")[4]);
                });
            }
            console.log(offering);
            let want = [];
            $(this).find(".mw > a").each(function() {
                want.push(this.href.split("/")[4]);
            });
            console.log(want);
            console.log($(form).attr("action"));
            console.log($(form).serializeObject());
            $.post($(form).attr("action"), $(form).serializeObject(), function(data) {
                data = data.replace(/src="[^"]*"/ig, "");
                let url = $("#offerForm", data).attr("action").split("#")[0];
                console.log(url);
                let ato1 = [];
                $(offering).each(function() {
                    ato1.push($("#exchanges > fieldset:nth-child(3) input[value*='" + this + ",']", data).val());
                });
                console.log(ato1);
                let ato2 = [];
                $(want).each(function() {
                    ato2.push($("#exchanges > fieldset:nth-child(7) input[value*='" + this + ",']", data).val());
                });
                console.log(ato2);
                $.post(url, { offer_setup: [3, 2, 2], "add_to_offer_1[]": ato1, "add_to_offer_2[]": ato2, add_to_offer: "+ Add to Offer" }, function() {
                    $.post(url, { offer_setup: [3, 2, 2, 3], from_and_or: parseInt(ratio[0]), to_and_or: parseInt(ratio[1]), expire_days: expire_days, counter_preference: 1, propose_offer: "Finish and Propose Offer" });
                });
            });
        });
    });
}

function cancelOffers(searchquery) {
    $.get("/u/" + myuid + "/o/", function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        if (!searchquery) return alert("No argument \"searchquery\". Example: \"creating\"");
        $("tr:has(:contains('"  + searchquery + "'))", data).each(function() {
            $.post($(this).find("a[href*='/u/" + myuid + "/o/']")[0].href, { offer_setup: 3, cancel_offer:"☒ Cancel Offer" });
        });
    });
}

function extendExpiry(expire_days) { //Old solution: SHOULD UPDATE THIS!
    $.post("/u/" + myuid + "/o/", { filter_by_status: "pending" }, function(data) {
        data = data.replace(/src="[^"]*"/ig, "");
        $(".active a:contains('pending')", data).each(function() {
            let url = this.href;
            $.post(url, { offer_setup: 3, edit_offer: "✐ Edit Offer" }, function(data) {
                data = data.replace(/src="[^"]*"/ig, "");
                var formdata = $("[name=propose_offer]", data).parents("form").serializeObject();
                formdata.expire_days = expire_days ? expire_days : 1000;
                formdata.propose_offer = "Finish and Propose Offer";
                $.post(url, formdata);
            });
        });
    });
}


function removeOwnedGamesFromPending() {
    syncLibrary(function() {
        $.post("/u/" + myuid + "/o/", { filter_by_status: "pending" }, function(data) {
            data = data.replace(/src="[^"]*"/ig, "");
            $(".active a:contains('pending')", data).each(function() {
                let url = this.href;
                $.post(url, { offer_setup: 3, edit_offer: "✐ Edit Offer" }, function(data) {
                    data = data.replace(/src="[^"]*"/ig, "");
                    var formdata = $("[name=propose_offer]", data).parents("form").serializeObject();
                    to_remove = [];
                    $(".bold+ li , div~ .tradables .tradables_items_list li:nth-child(1)", data).each(function() {
                        if ($(this).find("[alt*=avatar]:first").nextUntil("[alt*=avatar]").text().indexOf("library") > -1) {
                            to_remove.push($(this).find("[name='checked[]']").val());
                        }
                    });
                    if (to_remove.length > 0) {
                        if ($(".bold+ li , div+ .tradables .tradables_items_list li:nth-child(1)", data).length <= to_remove.length) {
                            $.post(url, { offer_setup: 3, cancel_offer:"☒ Cancel Offer" });
                        } else {
                            formdata.remove_offer_items = "➖ Remove Selected Tradables";
                            formdata["checked[]"] = to_remove;
                            $.post(url, formdata, function() {
                                formdata.propose_offer = "Finish and Propose Offer";
                                $.post(url, formdata);
                            });
                        }
                    } else {
                        formdata.propose_offer = "Finish and Propose Offer";
                        $.post(url, formdata);
                    }
                });
            });
        });
    });
}

function shuffle(array) {
    var currentIndex = array.length, temporaryValue, randomIndex;
    while (0 !== currentIndex) {
        randomIndex = Math.floor(Math.random() * currentIndex);
        currentIndex -= 1;
        temporaryValue = array[currentIndex];
        array[currentIndex] = array[randomIndex];
        array[randomIndex] = temporaryValue;
    }
    return array;
}

function getURIParam(sParam) {
    var sPageURL = decodeURIComponent(window.location.search.substring(1)),
        sURLVariables = sPageURL.split("&"),
        sParameterName,
        i;
    for (i = 0; i < sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split("=");
        if (sParameterName[0].toLowerCase() === sParam) {
            return sParameterName[1] === undefined ? true : sParameterName[1];
        }
    }
    return false;
}

function applySentenceCase(str) {
    return str.replace(/.+?[\.\?\!](\s|$)/g, function (txt) {
        return txt.charAt(0).toUpperCase() + txt.substr(1);
    });
}