- // ==UserScript==
- // @name Customizable Bazaar Filler
- // @namespace http://tampermonkey.net/
- // @version 1.71
- // @description On click, auto-fills bazaar item quantities and prices based on your preferences
- // @match https://www.torn.com/bazaar.php*
- // @require https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js
- // @grant GM_getValue
- // @grant GM_setValue
- // @grant GM_registerMenuCommand
- // @grant GM_xmlhttpRequest
- // @connect tornpal.com
- // ==/UserScript==
-
-
- (function () {
- "use strict";
-
- const styleBlock = `
- .item-toggle {
- width: 18px;
- height: 18px;
- border-radius: 4px;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
- outline: none;
- }
- @keyframes spin {
- from { transform: rotate(0deg); }
- to { transform: rotate(360deg); }
- }
- .item-toggle::after {
- content: '\\2713';
- position: absolute;
- font-size: 14px;
- top: 50%;
- left: 50%;
- transform: translate(-50%, -50%);
- display: none;
- }
- .item-toggle:checked::after {
- display: block;
- }
-
- body:not(.dark-mode) .item-toggle {
- border: 1px solid #ccc;
- background: #fff;
- }
- body:not(.dark-mode) .item-toggle:checked {
- background: #007bff;
- }
- body:not(.dark-mode) .item-toggle:checked::after {
- color: #fff;
- }
-
- body.dark-mode .item-toggle {
- border: 1px solid #4e535a;
- background: #2f3237;
- }
- body.dark-mode .item-toggle:checked {
- background: #4e535a;
- }
- body.dark-mode .item-toggle:checked::after {
- color: #fff;
- }
-
- .checkbox-wrapper {
- position: absolute;
- top: 50%;
- right: 8px;
- width: 30px;
- height: 30px;
- transform: translateY(-50%);
- cursor: pointer;
- }
- .checkbox-wrapper input.item-toggle {
- position: absolute;
- top: 6px;
- left: 6px;
- }
-
- .settings-modal-overlay {
- position: fixed;
- top: 0; left: 0;
- width: 100%; height: 100%;
- background: rgba(0,0,0,0.5);
- z-index: 9999;
- display: flex;
- align-items: center;
- justify-content: center;
- }
- .settings-modal {
- background: #fff;
- padding: 20px;
- border-radius: 8px;
- min-width: 300px;
- box-shadow: 0 2px 10px rgba(0,0,0,0.3);
- color: #000;
- }
- .settings-modal h2 {
- margin-top: 0;
- }
- .settings-modal label {
- display: block;
- margin: 10px 0 5px;
- }
- .settings-modal input, .settings-modal select {
- width: 100%;
- padding: 5px;
- box-sizing: border-box;
- }
- .settings-modal button {
- margin-top: 15px;
- padding: 5px 10px;
- }
- .settings-modal div[style*="text-align:right"] {
- text-align: right;
- }
- body.dark-mode .settings-modal {
- background: #2f3237;
- color: #fff;
- box-shadow: 0 2px 10px rgba(0,0,0,0.7);
- }
- body.dark-mode .settings-modal input,
- body.dark-mode .settings-modal select {
- background: #3c3f41;
- color: #fff;
- border: 1px solid #555;
- }
- body.dark-mode .settings-modal button {
- background: #555;
- color: #fff;
- border: none;
- }
-
- /* Black Friday mode styling */
- .black-friday-active {
- color: #28a745 !important;
- }
- .black-friday-active .black-friday-icon {
- color: #28a745 !important;
- fill: #28a745 !important;
- }
- .black-friday-icon {
- color: inherit;
- fill: currentColor;
- }
- `;
- $("<style>")
- .prop("type", "text/css")
- .html(styleBlock)
- .appendTo("head");
-
- let apiKey = GM_getValue("tornApiKey", "");
- let pricingSource = GM_getValue("pricingSource", "Market Value");
- let itemMarketOffset = GM_getValue("itemMarketOffset", -1);
- let itemMarketMarginType = GM_getValue("itemMarketMarginType", "absolute");
- let itemMarketListing = GM_getValue("itemMarketListing", 1);
- let itemMarketClamp = GM_getValue("itemMarketClamp", false);
- let marketMarginOffset = GM_getValue("marketMarginOffset", 0);
- let marketMarginType = GM_getValue("marketMarginType", "absolute");
- let bazaarCalcMethod = GM_getValue("bazaarCalcMethod", "cheapest");
- let bazaarMarginOffset = GM_getValue("bazaarMarginOffset", 0);
- let bazaarMarginType = GM_getValue("bazaarMarginType", "absolute");
- let bazaarClamp = GM_getValue("bazaarClamp", false);
- let bazaarListing = GM_getValue("bazaarListing", 1);
- let blackFridayMode = GM_getValue("blackFridayMode", false);
- const validPages = ["#/add", "#/manage"];
- let currentPage = window.location.hash;
- let itemMarketCache = {};
- let tornPalCache = { time: 0, data: null };
- let tornPalItemCache = {};
-
- console.log("Initial Bazaar Settings:", {
- bazaarCalcMethod,
- bazaarMarginOffset,
- bazaarMarginType,
- bazaarClamp,
- bazaarListing
- });
-
- function getItemIdByName(itemName) {
- const storedItems = JSON.parse(localStorage.getItem("tornItems") || "{}");
- for (const [id, info] of Object.entries(storedItems)) {
- if (info.name === itemName)
- return id;
- }
- return null;
- }
- function getPriceColor(listedPrice, marketValue) {
- if (marketValue <= 0)
- return "";
- const ratio = listedPrice / marketValue;
- const lowerBound = 0.998;
- const upperBound = 1.002;
- const isDarkMode = document.body.classList.contains("dark-mode");
- if (ratio >= lowerBound && ratio <= upperBound) {
- return "";
- }
- if (ratio < lowerBound) {
- const diff = lowerBound - ratio;
- const t = Math.min(diff / 0.05, 1.2);
- if (isDarkMode) {
- const r = Math.round(255 - t * (255 - 190));
- const g = Math.round(255 - t * (255 - 70));
- const b = Math.round(255 - t * (255 - 70));
- return `rgb(${r},${g},${b})`;
- }
- else {
- const r = Math.round(180 - t * 40);
- const g = Math.round(60 - t * 40);
- const b = Math.round(60 - t * 40);
- return `rgb(${r},${g},${b})`;
- }
- }
- else {
- const diff = ratio - upperBound;
- const t = Math.min(diff / 0.05, 1.2);
- if (isDarkMode) {
- const r = Math.round(255 - t * (255 - 70));
- const g = Math.round(255 - t * (255 - 190));
- const b = Math.round(255 - t * (255 - 70));
- return `rgb(${r},${g},${b})`;
- }
- else {
- const r = Math.round(60 - t * 40);
- const g = Math.round(160 - t * 40);
- const b = Math.round(60 - t * 40);
- return `rgb(${r},${g},${b})`;
- }
- }
- }
- async function fetchItemMarketData(itemId) {
- if (!apiKey) {
- console.error("No API key set for Item Market calls.");
- alert("No API key set. Please set your Torn API key in Bazaar Filler Settings before continuing.");
- return null;
- }
- const now = Date.now();
- if (itemMarketCache[itemId] && now - itemMarketCache[itemId].time < 30000) {
- return itemMarketCache[itemId].data;
- }
- const url = `https://api.torn.com/v2/market/${itemId}/itemmarket?comment=wBazaarFiller`;
- try {
- const res = await fetch(url, {
- headers: { Authorization: "ApiKey " + apiKey },
- });
- const data = await res.json();
- if (data.error) {
- console.error("Item Market API error:", data.error);
- alert("Item Market API error: " + data.error.error);
- return null;
- }
- itemMarketCache[itemId] = { time: now, data };
- return data;
- }
- catch (err) {
- console.error("Failed fetching Item Market data:", err);
- alert("Failed to fetch Item Market data. Check your API key or try again later.");
- return null;
- }
- }
- async function fetchTornPalData() {
- const now = Date.now();
- if (tornPalCache.data && now - tornPalCache.time < 60000) {
- return tornPalCache.data;
- }
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: "GET",
- url: "https://tornpal.com/api/v1/markets/allprices?comment=wBazaarFiller",
- onload: function (response) {
- try {
- const data = JSON.parse(response.responseText);
- tornPalCache = { time: now, data };
- resolve(data);
- }
- catch (err) {
- console.error("Parsing error:", err);
- reject(err);
- }
- },
- onerror: function (err) {
- console.error("Failed fetching TornPal data:", err);
- reject(err);
- },
- });
- });
- }
- async function fetchTornPalItemData(itemId) {
- const now = Date.now();
- if (tornPalItemCache[itemId] && now - tornPalItemCache[itemId].time < 60000) {
- return tornPalItemCache[itemId].data;
- }
- return new Promise((resolve, reject) => {
- GM_xmlhttpRequest({
- method: "GET",
- url: `https://tornpal.com/api/v1/markets/clist/${itemId}?comment=wBazaarFiller`,
- onload: function (response) {
- try {
- const data = JSON.parse(response.responseText);
- tornPalItemCache[itemId] = { time: now, data };
- resolve(data);
- }
- catch (err) {
- console.error("Parsing error:", err);
- reject(err);
- }
- },
- onerror: function (err) {
- console.error("Failed fetching TornPal item data:", err);
- reject(err);
- },
- });
- });
- }
- function updatePriceFieldColor($priceInput) {
- var _a;
- let $row = $priceInput.closest("li.clearfix");
- let itemName = "";
- if ($row.length) {
- itemName = $row.find(".name-wrap span.t-overflow").text().trim();
- }
- else {
- $row = $priceInput.closest(".item___jLJcf");
- itemName = $row.length ? $row.find(".desc___VJSNQ b").text().trim() : "";
- }
- if (!itemName)
- return;
- const storedItems = JSON.parse(localStorage.getItem("tornItems") || "{}");
- const matchedItem = Object.values(storedItems).find((i) => i.name === itemName);
- if (!matchedItem || !matchedItem.market_value)
- return;
- const raw = ((_a = $priceInput.val()) === null || _a === void 0 ? void 0 : _a.replace(/,/g, "")) || "";
- const typedPrice = Number(raw);
- if (isNaN(typedPrice)) {
- $priceInput.css("color", "");
- return;
- }
- $priceInput.css("color", getPriceColor(typedPrice, matchedItem.market_value));
- }
- function attachPriceFieldObservers() {
- $(".price input").each(function () {
- const $el = $(this);
- if ($el.data("listenerAttached"))
- return;
- $el.on("input", function () {
- updatePriceFieldColor($(this));
- });
- $el.data("listenerAttached", true);
- updatePriceFieldColor($el);
- });
- $(".price___DoKP7 .input-money-group.success input.input-money").each(function () {
- const $el = $(this);
- if ($el.data("listenerAttached"))
- return;
- $el.on("input", function () {
- updatePriceFieldColor($(this));
- });
- $el.data("listenerAttached", true);
- updatePriceFieldColor($el);
- });
- $("[class*=bottomMobileMenu___] [class*=priceMobile___] .input-money-group.success input.input-money").each(function () {
- const $el = $(this);
- if ($el.data("listenerAttached"))
- return;
- $el.on("input", function () {
- updatePriceFieldColor($(this));
- });
- $el.data("listenerAttached", true);
- updatePriceFieldColor($el);
- });
- }
-
- async function updateAddRow($row, isChecked) {
- var _a, _b;
- const $qtyInput = $row.find(".amount input").first();
- const $priceInput = $row.find(".price input").first();
- const $choiceCheckbox = $row.find("div.amount.choice-container input");
- if (!isChecked) {
- if ($choiceCheckbox.length && $choiceCheckbox.prop("checked")) {
- $choiceCheckbox.click();
- }
- if ($qtyInput.data("orig") !== undefined) {
- $qtyInput.val($qtyInput.data("orig"));
- $qtyInput.removeData("orig");
- }
- else {
- $qtyInput.val("");
- }
- $qtyInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- if ($priceInput.data("orig") !== undefined) {
- $priceInput.val($priceInput.data("orig"));
- $priceInput.removeData("orig");
- $priceInput.css("color", "");
- }
- else {
- $priceInput.val("");
- }
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- return;
- }
- if (!$qtyInput.data("orig"))
- $qtyInput.data("orig", $qtyInput.val());
- if (!$priceInput.data("orig"))
- $priceInput.data("orig", $priceInput.val());
- if (blackFridayMode) {
- if ($choiceCheckbox.length) {
- if (!$choiceCheckbox.prop("checked")) {
- $choiceCheckbox.click();
- }
- }
- else {
- const qty = $row.find(".item-amount.qty").text().trim();
- $qtyInput.val(qty);
- $qtyInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- }
- $priceInput.val("1");
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- return;
- }
- const itemName = $row.find(".name-wrap span.t-overflow").text().trim();
- const itemId = getItemIdByName(itemName);
- const storedItems = JSON.parse(localStorage.getItem("tornItems") || "{}");
- const matchedItem = Object.values(storedItems).find((i) => i.name === itemName);
- if ($choiceCheckbox.length) {
- if (!$choiceCheckbox.prop("checked")) {
- $choiceCheckbox.click();
- }
- }
- else {
- const qty = $row.find(".item-amount.qty").text().trim();
- $qtyInput.val(qty);
- $qtyInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- }
- if (pricingSource === "Market Value" && matchedItem) {
- const mv = matchedItem.market_value;
- let finalPrice = mv;
- if (marketMarginType === "absolute") {
- finalPrice += marketMarginOffset;
- }
- else if (marketMarginType === "percentage") {
- finalPrice = Math.round(mv * (1 + marketMarginOffset / 100));
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- $priceInput.css("color", getPriceColor(finalPrice, mv));
- }
- else if (pricingSource === "Item Market" && itemId) {
- const data = await fetchItemMarketData(itemId);
- if (!data || !((_b = (_a = data.itemmarket) === null || _a === void 0 ? void 0 : _a.listings) === null || _b === void 0 ? void 0 : _b.length))
- return;
- const listings = data.itemmarket.listings;
- const $checkbox = $row.find(".checkbox-wrapper input.item-toggle").first();
- const listingsText = listings
- .slice(0, 5)
- .map((x, i) => `${i + 1}) $${x.price.toLocaleString("en-US")} x${x.amount}`)
- .join("\n");
- $checkbox.attr("title", listingsText);
- setTimeout(() => {
- $checkbox.removeAttr("title");
- }, 30000);
- const baseIndex = Math.min(itemMarketListing - 1, listings.length - 1);
- const listingPrice = listings[baseIndex].price;
- let finalPrice;
- if (itemMarketMarginType === "absolute") {
- finalPrice = listingPrice + itemMarketOffset;
- }
- else if (itemMarketMarginType === "percentage") {
- finalPrice = Math.round(listingPrice * (1 + itemMarketOffset / 100));
- }
- else {
- finalPrice = listingPrice;
- }
- if (itemMarketClamp && matchedItem && matchedItem.market_value) {
- finalPrice = Math.max(finalPrice, matchedItem.market_value);
- }
- if (!$choiceCheckbox.length) {
- const qty = $row.find(".item-amount.qty").text().trim();
- $qtyInput.val(qty);
- $qtyInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- }
- else {
- if (!$choiceCheckbox.prop("checked")) {
- $choiceCheckbox.click();
- }
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- if (matchedItem && matchedItem.market_value) {
- $priceInput.css("color", getPriceColor(finalPrice, matchedItem.market_value));
- }
- }
- else if (pricingSource === "Bazaars/TornPal") {
- const data = await fetchTornPalData();
- if (!data || !data.items)
- return;
- if (!matchedItem)
- return;
- const tornPalItem = Object.values(data.items).find((item) => item.name === itemName);
- if (!tornPalItem)
- return;
- let basePrice;
- if (bazaarCalcMethod === "cheapest") {
- const itemId = getItemIdByName(itemName);
- if (itemId) {
- const itemData = await fetchTornPalItemData(itemId);
- if (itemData.listings && itemData.listings.length > 0) {
- const baseIndex = Math.min(bazaarListing - 1, itemData.listings.length - 1);
- basePrice = itemData.listings[baseIndex].price;
- } else {
- basePrice = tornPalItem.bazaar_cheapest;
- }
- } else {
- basePrice = tornPalItem.bazaar_cheapest;
- }
- }
- else {
- basePrice = tornPalItem.bazaar_weighted_average_5;
- }
- let finalPrice;
- if (bazaarMarginType === "absolute") {
- finalPrice = basePrice + bazaarMarginOffset;
- }
- else if (bazaarMarginType === "percentage") {
- finalPrice = Math.round(basePrice * (1 + bazaarMarginOffset / 100));
- }
- else {
- finalPrice = basePrice;
- }
- if (bazaarClamp && matchedItem.market_value) {
- finalPrice = Math.max(finalPrice, matchedItem.market_value);
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- $priceInput.css("color", getPriceColor(finalPrice, matchedItem.market_value));
- }
- }
- async function updateManageRow($row, isChecked) {
- var _a, _b;
- const $priceInput = $row.find(".price___DoKP7 .input-money-group.success input.input-money").first();
-
- if ($priceInput.length === 0) {
- console.warn("Price input not found in the row:", $row);
- return;
- }
-
- if (!isChecked) {
- if ($priceInput.data("orig") !== undefined) {
- $priceInput.val($priceInput.data("orig"));
- $priceInput.removeData("orig");
- $priceInput.css("color", "");
- }
- else {
- $priceInput.val("");
- }
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- return;
- }
- if (!$priceInput.data("orig"))
- $priceInput.data("orig", $priceInput.val());
- if (blackFridayMode) {
- $priceInput.val("1");
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- return;
- }
- const itemName = $row.find(".desc___VJSNQ b").text().trim();
- const itemId = getItemIdByName(itemName);
- const storedItems = JSON.parse(localStorage.getItem("tornItems") || "{}");
- const matchedItem = Object.values(storedItems).find((i) => i.name === itemName);
- if (pricingSource === "Market Value" && matchedItem) {
- const mv = matchedItem.market_value;
- let finalPrice = mv;
- if (marketMarginType === "absolute") {
- finalPrice += marketMarginOffset;
- }
- else if (marketMarginType === "percentage") {
- finalPrice = Math.round(mv * (1 + marketMarginOffset / 100));
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput.css("color", getPriceColor(finalPrice, mv));
- }
- else if (pricingSource === "Item Market" && itemId) {
- const data = await fetchItemMarketData(itemId);
- if (!data || !((_b = (_a = data.itemmarket) === null || _a === void 0 ? void 0 : _a.listings) === null || _b === void 0 ? void 0 : _b.length))
- return;
- const listings = data.itemmarket.listings;
- const $checkbox = $row.find(".checkbox-wrapper input.item-toggle").first();
- const listingsText = listings
- .slice(0, 5)
- .map((x, i) => `${i + 1}) $${x.price.toLocaleString("en-US")} x${x.amount}`)
- .join("\n");
- $checkbox.attr("title", listingsText);
- setTimeout(() => {
- $checkbox.removeAttr("title");
- }, 30000);
- const baseIndex = Math.min(itemMarketListing - 1, listings.length - 1);
- const listingPrice = listings[baseIndex].price;
- let finalPrice;
- if (itemMarketMarginType === "absolute") {
- finalPrice = listingPrice + itemMarketOffset;
- }
- else if (itemMarketMarginType === "percentage") {
- finalPrice = Math.round(listingPrice * (1 + itemMarketOffset / 100));
- }
- else {
- finalPrice = listingPrice;
- }
- if (itemMarketClamp && matchedItem && matchedItem.market_value) {
- finalPrice = Math.max(finalPrice, matchedItem.market_value);
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- if (matchedItem && matchedItem.market_value) {
- $priceInput.css("color", getPriceColor(finalPrice, matchedItem.market_value));
- }
- }
- else if (pricingSource === "Bazaars/TornPal") {
- const data = await fetchTornPalData();
- if (!data || !data.items)
- return;
- if (!matchedItem)
- return;
- const tornPalItem = Object.values(data.items).find((item) => item.name === itemName);
- if (!tornPalItem)
- return;
- let basePrice;
- if (bazaarCalcMethod === "cheapest") {
- const itemId = getItemIdByName(itemName);
- if (itemId) {
- const itemData = await fetchTornPalItemData(itemId);
- if (itemData.listings && itemData.listings.length > 0) {
- const baseIndex = Math.min(bazaarListing - 1, itemData.listings.length - 1);
- basePrice = itemData.listings[baseIndex].price;
- } else {
- basePrice = tornPalItem.bazaar_cheapest;
- }
- } else {
- basePrice = tornPalItem.bazaar_cheapest;
- }
- }
- else {
- basePrice = tornPalItem.bazaar_weighted_average_5;
- }
- let finalPrice;
- if (bazaarMarginType === "absolute") {
- finalPrice = basePrice + bazaarMarginOffset;
- }
- else if (bazaarMarginType === "percentage") {
- finalPrice = Math.round(basePrice * (1 + bazaarMarginOffset / 100));
- }
- else {
- finalPrice = basePrice;
- }
- if (bazaarClamp && matchedItem.market_value) {
- finalPrice = Math.max(finalPrice, matchedItem.market_value);
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput.css("color", getPriceColor(finalPrice, matchedItem.market_value));
- }
- }
- async function updateManageRowMobile($row, isChecked) {
- var _a, _b;
- const $priceInput = $row
- .find("[class*=bottomMobileMenu___] [class*=priceMobile___] .input-money-group.success input.input-money")
- .first();
- if (!$priceInput.length) {
- console.error("Mobile price field not found.");
- return;
- }
- if (!isChecked) {
- if ($priceInput.data("orig") !== undefined) {
- $priceInput.val($priceInput.data("orig"));
- $priceInput.removeData("orig");
- $priceInput.css("color", "");
- }
- else {
- $priceInput.val("");
- }
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- return;
- }
- if (!$priceInput.data("orig"))
- $priceInput.data("orig", $priceInput.val());
- if (blackFridayMode) {
- $priceInput.val("1");
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- return;
- }
- const itemName = $row.find(".desc___VJSNQ b").text().trim();
- const itemId = getItemIdByName(itemName);
- const storedItems = JSON.parse(localStorage.getItem("tornItems") || "{}");
- const matchedItem = Object.values(storedItems).find((i) => i.name === itemName);
- if (pricingSource === "Market Value" && matchedItem) {
- const mv = matchedItem.market_value;
- let finalPrice = mv;
- if (marketMarginType === "absolute") {
- finalPrice += marketMarginOffset;
- }
- else if (marketMarginType === "percentage") {
- finalPrice = Math.round(mv * (1 + marketMarginOffset / 100));
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput.css("color", getPriceColor(finalPrice, mv));
- }
- else if (pricingSource === "Item Market" && itemId) {
- const data = await fetchItemMarketData(itemId);
- if (!data || !((_b = (_a = data.itemmarket) === null || _a === void 0 ? void 0 : _a.listings) === null || _b === void 0 ? void 0 : _b.length))
- return;
- const listings = data.itemmarket.listings;
- const baseIndex = Math.min(itemMarketListing - 1, listings.length - 1);
- const listingPrice = listings[baseIndex].price;
- let finalPrice;
- if (itemMarketMarginType === "absolute") {
- finalPrice = listingPrice + itemMarketOffset;
- }
- else if (itemMarketMarginType === "percentage") {
- finalPrice = Math.round(listingPrice * (1 + itemMarketOffset / 100));
- }
- else {
- finalPrice = listingPrice;
- }
- if (itemMarketClamp && matchedItem && matchedItem.market_value) {
- finalPrice = Math.max(finalPrice, matchedItem.market_value);
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- if (matchedItem && matchedItem.market_value) {
- $priceInput.css("color", getPriceColor(finalPrice, matchedItem.market_value));
- }
- }
- else if (pricingSource === "Bazaars/TornPal") {
- const data = await fetchTornPalData();
- if (!data || !data.items)
- return;
- if (!matchedItem)
- return;
- const tornPalItem = Object.values(data.items).find((item) => item.name === itemName);
- if (!tornPalItem)
- return;
- let basePrice;
- if (bazaarCalcMethod === "cheapest") {
- const itemId = getItemIdByName(itemName);
- if (itemId) {
- const itemData = await fetchTornPalItemData(itemId);
- if (itemData.listings && itemData.listings.length > 0) {
- const baseIndex = Math.min(bazaarListing - 1, itemData.listings.length - 1);
- basePrice = itemData.listings[baseIndex].price;
- } else {
- basePrice = tornPalItem.bazaar_cheapest;
- }
- } else {
- basePrice = tornPalItem.bazaar_cheapest;
- }
- }
- else {
- basePrice = tornPalItem.bazaar_weighted_average_5;
- }
- let finalPrice;
- if (bazaarMarginType === "absolute") {
- finalPrice = basePrice + bazaarMarginOffset;
- }
- else if (bazaarMarginType === "percentage") {
- finalPrice = Math.round(basePrice * (1 + bazaarMarginOffset / 100));
- }
- else {
- finalPrice = basePrice;
- }
- if (bazaarClamp && matchedItem.market_value) {
- finalPrice = Math.max(finalPrice, matchedItem.market_value);
- }
- $priceInput.val(finalPrice.toLocaleString("en-US"));
- $priceInput[0].dispatchEvent(new Event("input", { bubbles: true }));
- $priceInput.css("color", getPriceColor(finalPrice, matchedItem.market_value));
- }
- }
-
- function openSettingsModal() {
- $(".settings-modal-overlay").remove();
- const $overlay = $('<div class="settings-modal-overlay"></div>');
- const $modal = $(`
- <div class="settings-modal" style="width:400px; max-width:90%; font-family:Arial, sans-serif;">
- <h2 style="margin-bottom:6px;">Bazaar Filler Settings</h2>
- <hr style="border-top:1px solid #ccc; margin:8px 0;">
- <div style="margin-bottom:15px;">
- <label for="api-key-input" style="font-weight:bold; display:block;">Torn API Key</label>
- <div style="display:flex; align-items:center; gap:8px;">
- <input id="api-key-input" type="text" placeholder="Enter API key" style="flex:1; padding:6px; box-sizing:border-box;" value="${apiKey || ''}">
- <button id="refresh-market-values" style="padding:6px; cursor:pointer; background:none; border:none;" title="Refresh Market Values">
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
- <path d="M23 4v6h-6"></path>
- <path d="M1 20v-6h6"></path>
- <path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
- </svg>
- </button>
- </div>
- </div>
- <hr style="border-top:1px solid #ccc; margin:8px 0;">
- <div style="margin-bottom:15px;">
- <label for="pricing-source-select" style="font-weight:bold; display:block;">Pricing Source</label>
- <select id="pricing-source-select" style="width:100%; padding:6px; box-sizing:border-box;">
- <option value="Market Value">Market Value</option>
- <option value="Bazaars/TornPal">Bazaars/TornPal</option>
- <option value="Item Market">Item Market</option>
- </select>
- </div>
- <div id="market-value-options" style="display:none; margin-bottom:15px;">
- <hr style="border-top:1px solid #ccc; margin:8px 0;">
- <h3 style="margin:0 0 10px 0; font-size:1em; font-weight:bold;">Market Value Options</h3>
- <div style="margin-bottom:10px;">
- <label for="market-margin-offset" style="display:block;">Margin (ie: -1 is either $1 less or 1% less depending on margin type)</label>
- <input id="market-margin-offset" type="number" style="width:100%; padding:6px; box-sizing:border-box;" value="${marketMarginOffset}">
- </div>
- <div style="margin-bottom:10px;">
- <label for="market-margin-type" style="display:block;">Margin Type</label>
- <select id="market-margin-type" style="width:100%; padding:6px; box-sizing:border-box;">
- <option value="absolute">Absolute ($)</option>
- <option value="percentage">Percentage (%)</option>
- </select>
- </div>
- </div>
- <div id="item-market-options" style="display:none; margin-bottom:15px;">
- <hr style="border-top:1px solid #ccc; margin:8px 0;">
- <h3 style="margin:0 0 10px 0; font-size:1em; font-weight:bold;">Item Market Options</h3>
- <div style="margin-bottom:10px;">
- <label for="item-market-listing" style="display:block;">Listing Index (1 = lowest, 2 = 2nd lowest, etc)</label>
- <input id="item-market-listing" type="number" style="width:100%; padding:6px; box-sizing:border-box;" value="${itemMarketListing}">
- </div>
- <div style="margin-bottom:10px;">
- <label for="item-market-offset" style="display:block;">Margin (ie: -1 is either $1 less or 1% less depending on margin type)</label>
- <input id="item-market-offset" type="number" style="width:100%; padding:6px; box-sizing:border-box;" value="${itemMarketOffset}">
- </div>
- <div style="margin-bottom:10px;">
- <label for="item-market-margin-type" style="display:block;">Margin Type</label>
- <select id="item-market-margin-type" style="width:100%; padding:6px; box-sizing:border-box;">
- <option value="absolute">Absolute ($)</option>
- <option value="percentage">Percentage (%)</option>
- </select>
- </div>
- <div style="display:inline-flex; align-items:center; margin-bottom:5px;">
- <input id="item-market-clamp" type="checkbox" style="margin-right:5px;" ${itemMarketClamp ? "checked" : ""}>
- <label for="item-market-clamp" style="margin:0; cursor:pointer;">Clamp minimum price to Market Value</label>
- </div>
- </div>
- <div id="tornpal-options" style="display:none; margin-bottom:15px;">
- <hr style="border-top:1px solid #ccc; margin:8px 0;">
- <h3 style="margin:0 0 10px 0; font-size:1em; font-weight:bold;">TornPal Options</h3>
- <div style="margin-bottom:10px;">
- <label for="tornpal-calc-method" style="display:block;">Calculation Method</label>
- <select id="tornpal-calc-method" style="width:100%; padding:6px; box-sizing:border-box;">
- <option value="cheapest">Cheapest</option>
- <option value="average">Average</option>
- </select>
- </div>
- <div id="tornpal-listing-options" style="margin-bottom:10px;">
- <label for="tornpal-listing" style="display:block;">Listing Index (1 = lowest, 2 = 2nd lowest, etc)</label>
- <input id="tornpal-listing" type="number" style="width:100%; padding:6px; box-sizing:border-box;" value="${bazaarListing || 1}">
- </div>
- <div style="margin-bottom:10px;">
- <label for="tornpal-margin-offset" style="display:block;">Margin (e.g., -1 for $1 less or 1% less)</label>
- <input id="tornpal-margin-offset" type="number" style="width:100%; padding:6px; box-sizing:border-box;" value="${bazaarMarginOffset}">
- </div>
- <div style="margin-bottom:10px;">
- <label for="tornpal-margin-type" style="display:block;">Margin Type</label>
- <select id="tornpal-margin-type" style="width:100%; padding:6px; box-sizing:border-box;">
- <option value="absolute">Absolute ($)</option>
- <option value="percentage">Percentage (%)</option>
- </select>
- </div>
- <div style="display:inline-flex; align-items:center; margin-bottom:5px;">
- <input id="tornpal-clamp" type="checkbox" style="margin-right:5px;" ${bazaarClamp ? "checked" : ""}>
- <label for="tornpal-clamp" style="margin:0; cursor:pointer;">Clamp minimum price to Market Value</label>
- </div>
- </div>
- <hr style="border-top:1px solid #ccc; margin:8px 0;">
- <div style="text-align:right;">
- <button id="settings-save" style="margin-right:8px; padding:6px 10px; cursor:pointer;">Save</button>
- <button id="settings-cancel" style="padding:6px 10px; cursor:pointer;">Cancel</button>
- </div>
- </div>
- `);
- $overlay.append($modal);
- $("body").append($overlay);
- $("#pricing-source-select").val(pricingSource);
- $("#item-market-margin-type").val(itemMarketMarginType);
- $("#market-margin-type").val(marketMarginType);
- $("#tornpal-calc-method").val(bazaarCalcMethod);
- $("#tornpal-margin-type").val(bazaarMarginType);
- function toggleFields() {
- const src = $("#pricing-source-select").val();
- $("#market-value-options").toggle(src === "Market Value");
- $("#item-market-options").toggle(src === "Item Market");
- $("#tornpal-options").toggle(src === "Bazaars/TornPal");
- }
- $("#pricing-source-select").change(toggleFields);
- toggleFields();
- $("#settings-save").click(function () {
- var _a;
- const oldPricingSource = pricingSource;
- apiKey = ((_a = $("#api-key-input").val()) === null || _a === void 0 ? void 0 : _a.trim()) || "";
- pricingSource = $("#pricing-source-select").val();
- if (oldPricingSource !== pricingSource) {
- itemMarketCache = {};
- tornPalCache = { time: 0, data: null };
- }
- if (pricingSource === "Bazaars/TornPal") {
- bazaarCalcMethod = $("#tornpal-calc-method").val();
- bazaarMarginOffset = Number($("#tornpal-margin-offset").val() || 0);
- bazaarMarginType = $("#tornpal-margin-type").val();
- bazaarClamp = $("#tornpal-clamp").is(":checked");
- bazaarListing = Number($("#tornpal-listing").val() || 1);
- console.log("Saving Bazaar Settings:", {
- bazaarCalcMethod,
- bazaarMarginOffset,
- bazaarMarginType,
- bazaarClamp,
- bazaarListing
- });
- GM_setValue("bazaarCalcMethod", bazaarCalcMethod);
- GM_setValue("bazaarMarginOffset", bazaarMarginOffset);
- GM_setValue("bazaarMarginType", bazaarMarginType);
- GM_setValue("bazaarClamp", bazaarClamp);
- GM_setValue("bazaarListing", bazaarListing);
- }
- if (pricingSource === "Market Value") {
- marketMarginOffset = Number($("#market-margin-offset").val() || 0);
- marketMarginType = $("#market-margin-type").val();
- GM_setValue("marketMarginOffset", marketMarginOffset);
- GM_setValue("marketMarginType", marketMarginType);
- }
- if (pricingSource === "Item Market") {
- itemMarketListing = Number($("#item-market-listing").val() || 1);
- itemMarketOffset = Number($("#item-market-offset").val() || -1);
- itemMarketMarginType = $("#item-market-margin-type").val();
- itemMarketClamp = $("#item-market-clamp").is(":checked");
- GM_setValue("itemMarketListing", itemMarketListing);
- GM_setValue("itemMarketOffset", itemMarketOffset);
- GM_setValue("itemMarketMarginType", itemMarketMarginType);
- GM_setValue("itemMarketClamp", itemMarketClamp);
- }
- GM_setValue("tornApiKey", apiKey);
- GM_setValue("pricingSource", pricingSource);
- $overlay.remove();
- });
- $("#settings-cancel").click(() => $overlay.remove());
-
- // Add refresh market values functionality
- $("#refresh-market-values").click(async function() {
- const $button = $(this);
- const $svg = $button.find("svg");
- const currentApiKey = $("#api-key-input").val().trim() || apiKey;
-
- if (!currentApiKey) {
- alert("Please enter a valid API key first.");
- return;
- }
-
- // Disable button and show loading state
- $button.prop("disabled", true);
- $svg.css("animation", "spin 1s linear infinite");
-
- try {
- const response = await fetch(`https://api.torn.com/torn/?key=${currentApiKey}&selections=items&comment=wBazaarFiller`);
- const data = await response.json();
-
- if (!data.items) {
- throw new Error(data.error?.error || "Failed to fetch market values");
- }
-
- const filtered = {};
- for (const [id, item] of Object.entries(data.items)) {
- if (item.tradeable) {
- filtered[id] = {
- name: item.name,
- market_value: item.market_value,
- };
- }
- }
-
- localStorage.setItem("tornItems", JSON.stringify(filtered));
- GM_setValue("lastUpdatedTime", Date.now());
-
- // Show success message
- const $successMsg = $('<div style="color: #28a745; margin-top: 5px;">Market values refreshed successfully!</div>');
- $button.after($successMsg);
- setTimeout(() => $successMsg.remove(), 3000);
- } catch (error) {
- // Show error message
- const $errorMsg = $('<div style="color: #dc3545; margin-top: 5px;">Error: ' + error.message + '</div>');
- $button.after($errorMsg);
- setTimeout(() => $errorMsg.remove(), 3000);
- } finally {
- // Re-enable button and remove loading state
- $button.prop("disabled", false);
- $svg.css("animation", "");
- }
- });
- }
- function addPricingSourceLink() {
- if (document.getElementById("pricing-source-button"))
- return;
-
- const linksContainer = document.querySelector(".linksContainer___LiOTN");
- if (!linksContainer) {
- // Retry after a short delay if container not found
- setTimeout(addPricingSourceLink, 100);
- return;
- }
-
- try {
- const link = document.createElement("a");
- link.id = "pricing-source-button";
- link.href = "#";
- link.className = "linkContainer___X16y4 inRow___VfDnd greyLineV___up8VP iconActive___oAum9";
- link.target = "_self";
- link.rel = "noreferrer";
-
- const iconSpan = document.createElement("span");
- iconSpan.className = "iconWrapper___x3ZLe iconWrapper___COKJD svgIcon___IwbJV";
- iconSpan.innerHTML = `
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
- <path d="M8 4.754a3.246 3.246 0 1 1 0 6.492 3.246 3.246 0 0 1 0-6.492zM5.754 8a2.246 2.246 0 1 0 4.492 0 2.246 2.246 0 0 0-4.492 0z"/>
- <path d="M9.796 1.343c-.527-1.79-3.065-1.79-3.592 0l-.094.319a.873.873 0 0 0-1.255.52l-.292-.16c-1.64-.892-3.433.902-2.54 2.541l.159.292a.873.873 0 0 0-.52 1.255l-.319.094c-1.79.527-1.79 3.065 0 3.592l.319.094a.873.873 0 0 0 .52 1.255l-.16.292c-.892 1.64.901 3.433 2.54 2.54l.292-.16a.873.873 0 0 0 1.255.52l.094.319c.527 1.79 3.065 1.79 3.592 0l.094-.319a.873.873 0 0 0 1.255-.52l.292.16c1.64.893 3.433-.902 2.54-2.541l-.16-.292a.873.873 0 0 0-.52-1.255l-.319-.094c1.79-.527 1.79-3.065 0-3.592l-.319-.094a.873.873 0 0 0-.52-1.255l-.16-.292c-.893-1.64-.902-3.433-2.54-2.54l-.292.16a.873.873 0 0 0-1.255-.52l-.094-.319zm-2.633.283c.246-.835 1.428-.835 1.674 0l.094.319a1.873 1.873 0 0 0 2.693 1.115l.291-.16c.764-.416 1.6.42 1.184 1.185l-.16.292a1.873 1.873 0 0 0 1.116 2.692l.318.094c.835.246.835 1.428 0 1.674l-.318.094a1.873 1.873 0 0 0-1.116 2.692l.16.292c.416.764-.42 1.6-1.185 1.184l-.291-.16a1.873 1.873 0 0 0-1.116-2.692l-.318-.094c-.835-.246-.835-1.428 0-1.674l.318-.094a1.873 1.873 0 0 0 1.116-2.692l-.16-.292c-.416-.764.42-1.6 1.185-1.184l.292.16a1.873 1.873 0 0 0 2.693-1.115l.094-.318z"/>
- </svg>
- `;
- link.appendChild(iconSpan);
-
- const textSpan = document.createElement("span");
- textSpan.className = "linkTitle____NPyM";
- textSpan.textContent = "Bazaar Filler Settings";
- link.appendChild(textSpan);
-
- link.addEventListener("click", function (e) {
- e.preventDefault();
- openSettingsModal();
- });
-
- linksContainer.insertBefore(link, linksContainer.firstChild);
- } catch (error) {
- console.error("Error adding pricing source link:", error);
- // Retry after a short delay if there was an error
- setTimeout(addPricingSourceLink, 100);
- }
- }
- function addBlackFridayToggle() {
- if (document.getElementById("black-friday-toggle"))
- return;
-
- const linksContainer = document.querySelector(".linksContainer___LiOTN");
- if (!linksContainer) {
- // Retry after a short delay if container not found
- setTimeout(addBlackFridayToggle, 100);
- return;
- }
-
- try {
- const link = document.createElement("a");
- link.id = "black-friday-toggle";
- link.href = "#";
- link.className = "linkContainer___X16y4 inRow___VfDnd greyLineV___up8VP iconActive___oAum9";
- if (blackFridayMode) {
- link.classList.add("black-friday-active");
- }
- link.target = "_self";
- link.rel = "noreferrer";
-
- const iconSpan = document.createElement("span");
- iconSpan.className = "iconWrapper___x3ZLe iconWrapper___COKJD svgIcon___IwbJV";
- iconSpan.innerHTML = `
- <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" class="black-friday-icon" style="color: ${blackFridayMode ? "#28a745" : "inherit"}; fill: ${blackFridayMode ? "#28a745" : "currentColor"};">
- <path d="M4 10.781c.148 1.667 1.513 2.85 3.591 3.003V15h1.043v-1.216c2.27-.179 3.678-1.438 3.678-3.3 0-1.59-.947-2.51-2.956-3.028l-.722-.187V3.467c1.122.11 1.879.714 2.07 1.616h1.47c-.166-1.6-1.54-2.748-3.54-2.875V1H7.591v1.233c-1.939.23-3.27 1.472-3.27 3.156 0 1.454.966 2.483 2.661 2.917l.61.162v4.031c-1.149-.17-1.94-.8-2.131-1.718H4zm3.391-3.836c-1.043-.263-1.6-.825-1.6-1.616 0-.944.704-1.641 1.8-1.828v3.495l-.2-.05zm1.591 1.872c1.287.323 1.852.859 1.852 1.769 0 1.097-.826 1.828-2.2 1.939V8.73l.348.086z"/>
- </svg>
- `;
- link.appendChild(iconSpan);
-
- const textSpan = document.createElement("span");
- textSpan.className = "linkTitle____NPyM";
- textSpan.textContent = blackFridayMode ? "Black Friday: ON" : "Black Friday: OFF";
- link.appendChild(textSpan);
-
- link.addEventListener("click", function (e) {
- e.preventDefault();
- blackFridayMode = !blackFridayMode;
- GM_setValue("blackFridayMode", blackFridayMode);
- textSpan.textContent = blackFridayMode ? "Black Friday: ON" : "Black Friday: OFF";
- const svg = this.querySelector(".black-friday-icon");
- if (svg) {
- svg.style.color = blackFridayMode ? "#28a745" : "inherit";
- svg.style.fill = blackFridayMode ? "#28a745" : "currentColor";
- }
- if (blackFridayMode) {
- link.classList.add("black-friday-active");
- }
- else {
- link.classList.remove("black-friday-active");
- }
- });
-
- const settingsButton = document.getElementById("pricing-source-button");
- if (settingsButton) {
- linksContainer.insertBefore(link, settingsButton);
- }
- else {
- linksContainer.insertBefore(link, linksContainer.firstChild);
- }
- } catch (error) {
- console.error("Error adding black friday toggle:", error);
- // Retry after a short delay if there was an error
- setTimeout(addBlackFridayToggle, 100);
- }
- }
- function addAddPageCheckboxes() {
- $(".items-cont .title-wrap").each(function () {
- const $el = $(this);
- if ($el.find(".checkbox-wrapper").length)
- return;
- $el.css("position", "relative");
- const wrapper = $('<div class="checkbox-wrapper"></div>');
- const checkbox = $("<input>", {
- type: "checkbox",
- class: "item-toggle",
- click: async function (e) {
- e.stopPropagation();
- if (!GM_getValue("tornApiKey", "")) {
- alert("No Torn API key set. Please click the 'Bazaar Filler Settings' button to enter your API key.");
- $(this).prop("checked", false);
- openSettingsModal();
- return;
- }
- await updateAddRow($(this).closest("li.clearfix"), this.checked);
- },
- });
- wrapper.append(checkbox);
- $el.append(wrapper);
- });
- $(document)
- .off("dblclick", ".amount input")
- .on("dblclick", ".amount input", function () {
- const $row = $(this).closest("li.clearfix");
- const qty = $row.find(".item-amount.qty").text().trim();
- if (qty) {
- $(this).val(qty);
- $(this)[0].dispatchEvent(new Event("input", { bubbles: true }));
- $(this)[0].dispatchEvent(new Event("keyup", { bubbles: true }));
- }
- });
-
- // Add "Select All" button if it doesn't exist yet
- if ($(".select-all-action").length === 0) {
- const $clearAllBtn = $(".clear-action");
- if ($clearAllBtn.length) {
- const $selectAllBtn = $('<span class="select-all-action t-blue h c-pointer" style="margin-left: 15px;">Select All</span>');
- $clearAllBtn.before($selectAllBtn);
-
- $selectAllBtn.on("click", async function(e) {
- e.preventDefault();
- if (!GM_getValue("tornApiKey", "")) {
- alert("No Torn API key set. Please click the 'Bazaar Filler Settings' button to enter your API key.");
- openSettingsModal();
- return;
- }
-
- // Find the active category panel (the one currently displayed)
- let $activePanel = $(".items-cont.ui-tabs-panel[style*='display: block']");
-
- // If no panel is found with display:block, try finding the active tab and its corresponding panel
- if (!$activePanel.length) {
- const $activeTab = $(".ui-tabs-active.ui-state-active");
- if ($activeTab.length) {
- const tabId = $activeTab.find("a").attr("href").replace("#", "");
- $activePanel = $(`.items-cont.ui-tabs-panel[data-reactid*='$${tabId}']`);
- }
-
- // If still no active panel, fall back to any visible panel
- if (!$activePanel.length) {
- $activePanel = $(".items-cont.ui-tabs-panel").filter(function() {
- return $(this).css("display") !== "none";
- });
- }
- }
-
- if ($activePanel.length) {
- // Find all unchecked checkboxes in that panel
- const $checkboxes = $activePanel.find("li.clearfix:not(.disabled) .checkbox-wrapper input.item-toggle:not(:checked)");
-
- if ($checkboxes.length === 0) {
- return; // No checkboxes to check
- }
-
- // Check all boxes and trigger their click handlers
- for (let i = 0; i < $checkboxes.length; i++) {
- const $checkbox = $($checkboxes[i]);
- $checkbox.prop("checked", true);
- const $row = $checkbox.closest("li.clearfix");
- await updateAddRow($row, true);
- }
- }
- });
- }
- }
- }
- function addManagePageCheckboxes() {
- $(".item___jLJcf").each(function () {
- const $row = $(this);
- const $desc = $row.find(".desc___VJSNQ");
- if (!$desc.length || $desc.find(".checkbox-wrapper").length)
- return;
- $desc.css("position", "relative");
- const wrapper = $('<div class="checkbox-wrapper"></div>');
- const checkbox = $("<input>", {
- type: "checkbox",
- class: "item-toggle",
- click: async function (e) {
- e.stopPropagation();
- if (!GM_getValue("tornApiKey", "")) {
- alert("No Torn API key set. Please click the 'Bazaar Filler Settings' button to enter your API key.");
- $(this).prop("checked", false);
- openSettingsModal();
- return;
- }
- const $row = $(this).closest(".item___jLJcf");
- if ($row.length === 0) {
- const $correctRow = $(this).closest(".item___jLJcf");
- if ($correctRow.length > 0) {
- if (window.innerWidth <= 784) {
- const $manageBtn = $correctRow.find('button[aria-label="Manage"]').first();
- if ($manageBtn.length) {
- if (!$manageBtn.find("span").hasClass("active___OTFsm")) {
- $manageBtn.click();
- }
- setTimeout(async () => {
- await updateManageRowMobile($correctRow, this.checked);
- }, 200);
- return;
- }
- }
- await updateManageRow($correctRow, this.checked);
- return;
- }
- console.warn("Row not found with either selector");
- return;
- }
- await updateManageRow($row, this.checked);
- },
- });
- wrapper.append(checkbox);
- $desc.append(wrapper);
- });
- }
-
- const storedItems = localStorage.getItem("tornItems");
- const lastUpdatedTime = GM_getValue("lastUpdatedTime", 0);
- const now = Date.now();
- const oneDayMs = 24 * 60 * 60 * 1000;
- const lastUpdatedDate = new Date(lastUpdatedTime);
- const todayUTC = new Date().toISOString().split("T")[0];
- const lastUpdatedUTC = lastUpdatedDate.toISOString().split("T")[0];
- if (apiKey &&
- (!storedItems || lastUpdatedUTC < todayUTC || now - lastUpdatedTime >= oneDayMs)) {
- fetch(`https://api.torn.com/torn/?key=${apiKey}&selections=items&comment=wBazaarFiller`)
- .then((r) => r.json())
- .then((data) => {
- if (!data.items) {
- console.error("Failed to fetch Torn items or no items found. Possibly invalid API key or rate limit.");
- return;
- }
- const filtered = {};
- for (const [id, item] of Object.entries(data.items)) {
- if (item.tradeable) {
- filtered[id] = {
- name: item.name,
- market_value: item.market_value,
- };
- }
- }
- localStorage.setItem("tornItems", JSON.stringify(filtered));
- GM_setValue("lastUpdatedTime", now);
- })
- .catch((err) => {
- console.error("Error fetching Torn items:", err);
- });
- }
- const domObserver = new MutationObserver(() => {
- try {
- if (window.location.hash === "#/add") {
- addAddPageCheckboxes();
- }
- else if (window.location.hash === "#/manage") {
- addManagePageCheckboxes();
- }
- addPricingSourceLink();
- addBlackFridayToggle();
- attachPriceFieldObservers();
- } catch (error) {
- console.error("Error in DOM observer:", error);
- // Retry after a short delay
- setTimeout(() => {
- if (window.location.hash === "#/add") {
- addAddPageCheckboxes();
- }
- else if (window.location.hash === "#/manage") {
- addManagePageCheckboxes();
- }
- addPricingSourceLink();
- addBlackFridayToggle();
- attachPriceFieldObservers();
- }, 1000);
- }
- });
-
- // Observe the entire document for changes
- domObserver.observe(document.body, {
- childList: true,
- subtree: true,
- attributes: true,
- characterData: true
- });
-
- // Initialize on page load
- window.addEventListener('load', () => {
- setTimeout(() => {
- if (window.location.hash === "#/add") {
- addAddPageCheckboxes();
- }
- else if (window.location.hash === "#/manage") {
- addManagePageCheckboxes();
- }
- addPricingSourceLink();
- addBlackFridayToggle();
- attachPriceFieldObservers();
- }, 100);
- });
-
- // Initialize on hash change
- window.addEventListener("hashchange", () => {
- currentPage = window.location.hash;
- setTimeout(() => {
- if (currentPage === "#/add") {
- addAddPageCheckboxes();
- }
- else if (currentPage === "#/manage") {
- addManagePageCheckboxes();
- }
- addPricingSourceLink();
- addBlackFridayToggle();
- attachPriceFieldObservers();
- }, 100);
- });
-
- // Add a periodic check to ensure UI elements are present
- setInterval(() => {
- const shouldHaveUI = window.location.hash === "#/add" || window.location.hash === "#/manage";
- const hasUI = $(".checkbox-wrapper").length > 0 || $("#pricing-source-button").length > 0;
-
- if (shouldHaveUI && !hasUI) {
- console.log("UI elements missing, reinitializing...");
- if (window.location.hash === "#/add") {
- addAddPageCheckboxes();
- }
- else if (window.location.hash === "#/manage") {
- addManagePageCheckboxes();
- }
- addPricingSourceLink();
- addBlackFridayToggle();
- attachPriceFieldObservers();
- }
- }, 5000);
-
- $(document).on("click", "button.undo___FTgvP", function (e) {
- e.preventDefault();
- $(".item___jLJcf .checkbox-wrapper input.item-toggle:checked").each(function () {
- $(this).prop("checked", false);
- const $row = $(this).closest(".item___jLJcf");
- updateManageRow($row, false);
- });
- });
- $(document).on("click", ".clear-action", function (e) {
- e.preventDefault();
- $("li.clearfix .checkbox-wrapper input.item-toggle:checked").each(function () {
- $(this).prop("checked", false);
- const $row = $(this).closest("li.clearfix");
- updateAddRow($row, false);
- });
- });
- $(document).ready(function () {
- itemMarketCache = {};
- tornPalCache = { time: 0, data: null };
- });
- })();