TC Bazaar+ v2

description

  1. // ==UserScript==
  2. // @name TC Bazaar+ v2
  3. // @namespace namespace
  4. // @version 0.7
  5. // @description description
  6. // @author tos
  7. // @match *.torn.com/bazaar.php*
  8. // @match *.torn.com/bigalgunshop.php*
  9. // @match *.torn.com/index.php*
  10. // @match *.torn.com/shops.php*
  11. // @match *.torn.com/trade.php*
  12. // @grant GM_xmlhttpRequest
  13. // ==/UserScript==
  14.  
  15. const api_key = 'API_KEY_HERE'
  16.  
  17. function auto_price (lowest_price) { return lowest_price - 1 }
  18.  
  19. function lowest_market_price(itemID) {
  20. return torn_api(`market.${itemID}.bazaar,itemmarket`).then((r) => {
  21. let prices = [...r.bazaar, ...r.itemmarket].map(v => v.cost).sort((a, b) => a - b)
  22. let prices_no_dupes = [...new Set(prices)]
  23. return prices_no_dupes[1]
  24. }).catch(err => console.log(err))
  25. }
  26.  
  27.  
  28. const event = new Event('input', {bubbles: true, simulated: true})
  29.  
  30.  
  31. document.addEventListener('dblclick', (e) => {
  32. const location = window.location.pathname + window.location.hash
  33. //console.log(location, e)
  34. if (e.target?.tagName === 'INPUT') {
  35. const input = e.target
  36. switch (location) {
  37. case '/bazaar.php#/':
  38. if (input.className.includes('buyAmountInput')) max_buy(input) //other bazaar buy
  39. break
  40. case '/bazaar.php#/add':
  41. if (input.className.includes('input-money')) auto_price_add(input) //my bazaar add
  42. else if (input.className === 'clear-all') max_qty(input) //my bazaar qty add
  43. break
  44. case '/bazaar.php#/manage':
  45. if (input.className.includes('input-money')) auto_price_manage(input) //my bazaar manage
  46. else if (input.className.includes('numberInput')) max_qty_rem(input) //my bazaar qty remove
  47. break
  48. case '/bigalgunshop.php':
  49. case '/shops.php':
  50. if (input.name ==='buyAmount[]') buy_hundred(input) //city shop buy 100
  51. else if (input.id.includes('sell')) city_sell_all(input) //city shop sell all
  52. else if (input.id.includes('item')) city_sell_all(input) //bigal sell all
  53. break
  54. default:
  55. if (input.id.includes('item')) foriegn_max(input) //foreign buy
  56. else if (location.includes('trade.php') && input.name && input.name === 'amount') max_qty_trade(input)//trade qty input
  57. break
  58. }
  59. }
  60. else if (e.target?.tagName === 'LABEL') {
  61. if (e.target.className === 'marker-css') {
  62. const itemID = e.target.closest('LI[data-item]')?.getAttribute('data-item')//big al check all
  63. if (itemID) big_al_check_all(itemID) //big al check/uncheck all
  64. const itemName = e.target.closest('LI[data-group]').querySelector('img').getAttribute('alt')
  65. if (itemName) bazaar_check_all(itemName)
  66. }
  67. }
  68. })
  69.  
  70. //other bazaar buy
  71. function max_buy(input) {
  72. const max = input.closest('DIV[class^=buyMenu]').querySelector('SPAN[class^=amount]').innerText.match(/[0-9]/g).join('')
  73. let old_value = input.value
  74. set_react_input(input, max)
  75. }
  76.  
  77. //foreign buy
  78. function foriegn_max (input) {
  79. const i = document.querySelector('div.user-info div.msg').innerText.match(/(\d+).\/.(\d+)/)
  80. set_regular_input(input, parseInt(i[2]) - parseInt(i[1]))
  81. }
  82.  
  83. let torn_items = null
  84. const get_torn_items = () => torn_api('torn..items').then((r) => Object.fromEntries( Object.entries(r.items).map( ([itemID, properties]) => [properties.name, itemID] ))).catch(err => console.log(err))
  85. //my bazaar add
  86. async function auto_price_add(input) {
  87. if (!torn_items) torn_items = await get_torn_items()
  88. const item_name = input.closest('LI').querySelector('.name-wrap .t-overflow').innerText
  89. const lowest_price = await lowest_market_price(parseInt(torn_items[item_name]))
  90. set_regular_input(input, auto_price(lowest_price))
  91. }
  92.  
  93. //my bazaar manage
  94. async function auto_price_manage (input) {
  95. if (!torn_items) torn_items = await get_torn_items()
  96. const itemID = input.closest('div[class^=row]').querySelector('img').src.split('items/')[1].split('/')[0]
  97. const lowest_price = await lowest_market_price(itemID)
  98. set_react_input(input, auto_price(lowest_price))
  99. }
  100.  
  101. //my bazaar qty add
  102. function max_qty (input) {
  103. const qty = input.closest('LI').querySelector('div.name-wrap').innerText.match(/x(\d+)/)
  104. set_regular_input(input, qty ? qty[1] : 1)
  105. }
  106.  
  107. //my bazaar qty remove
  108. function max_qty_rem (input) {
  109. const qty = input.closest('div[class^=row]').querySelector('div[class^=desc]').innerText.match(/x(\d+)/)
  110. set_react_input(input, qty ? qty[1] : 1)
  111. }
  112.  
  113. //my bazaar check all
  114. function bazaar_check_all(item_name) {
  115. Array.from(document.querySelectorAll(`IMG[alt="${item_name}"]`)).map(img => img.closest('LI[data-group]').querySelector('INPUT')).forEach(checkbox => checkbox.checked = !checkbox.checked)
  116. }
  117.  
  118.  
  119. //city shop buy 100
  120. function buy_hundred(input) {
  121. set_regular_input(input, 100)
  122. }
  123.  
  124. //city shop sell all
  125. function city_sell_all(input) {
  126. const qty = input.closest('UL').querySelector('LI.desc').innerText.match(/x(\d+)/)
  127. set_regular_input(input, qty ? qty[1] : 1)
  128. }
  129.  
  130. //big al check all
  131. function big_al_check_all(item_id) {
  132. document.querySelectorAll(`LI[data-item="${item_id}"] INPUT[type=checkbox]`).forEach(checkbox => checkbox.checked = !checkbox.checked)
  133. }
  134.  
  135. //trade max qty
  136. function max_qty_trade(input) {
  137. console.log(input.closest('div.title-wrap'))//.querySelector('div.name-wrap'))
  138. }
  139.  
  140.  
  141. function set_regular_input(input, newval) {
  142. input.value = newval
  143. input.dispatchEvent(event)
  144. input.select()
  145. }
  146.  
  147. function set_react_input(input, newval) {
  148. let old_value = input.value
  149. input.value = newval
  150. input._valueTracker.setValue(old_value)
  151. input.dispatchEvent(event)
  152. input.select()
  153. }
  154.  
  155. async function torn_api(args) {
  156. const a = args.split('.')
  157. if (a.length!==3) throw(`Bad argument in torn_api(args, key): ${args}`)
  158. return new Promise((resolve, reject) => {
  159. GM_xmlhttpRequest ( {
  160. method: "POST",
  161. url: `https://api.torn.com/${a[0]}/${a[1]}?selections=${a[2]}&key=${api_key}`,
  162. headers: {
  163. "Content-Type": "application/json"
  164. },
  165. onload: (response) => {
  166. try {
  167. const resjson = JSON.parse(response.responseText)
  168. resolve(resjson)
  169. } catch(err) {
  170. reject(err)
  171. }
  172. },
  173. onerror: (err) => {
  174. reject(err)
  175. }
  176. })
  177. })
  178. }

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址