Advertisement
Guest User

poggiue

a guest
Feb 16th, 2020
321
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.71 KB | None | 0 0
  1. # coding: utf-8
  2.  
  3. # In[1]:
  4.  
  5.  
  6. import requests
  7. import os
  8. import json
  9. import math
  10. import multiprocessing
  11. import itertools as it
  12. from pprint import pprint
  13.  
  14.  
  15. if os.name == 'nt':
  16. import win32api, win32process, win32con
  17. pid = win32api.GetCurrentProcessId()
  18. handle = win32api.OpenProcess(win32con.PROCESS_ALL_ACCESS, True, pid)
  19. win32process.SetPriorityClass(handle, win32process.BELOW_NORMAL_PRIORITY_CLASS)
  20.  
  21.  
  22. # In[2]:
  23.  
  24.  
  25. auction_data_path = "D:\\AuctionData"
  26. os.makedirs(auction_data_path, exist_ok=True)
  27.  
  28.  
  29. # In[4]:
  30.  
  31.  
  32. # realm_list = []
  33. # connected_realm_index_response = requests.get(
  34. # f'https://us.api.blizzard.com/data/wow/connected-realm/index?namespace=dynamic-us&locale=en_US&access_token={access_token}'
  35. # )
  36. # for connected_realm in connected_realm_index_response.json()['connected_realms']:
  37. # connected_realm_response = requests.get(connected_realm['href'] + f'&locale=en_US&access_token={access_token}')
  38. # connected_realms = sorted(realm['slug'] for realm in connected_realm_response.json()['realms'])
  39. # realm_list.append(connected_realms[0])
  40. # realm_list.sort()
  41. # print(realm_list)
  42.  
  43.  
  44. # In[5]:
  45.  
  46.  
  47. realm_list = ['aegwynn', 'aerie-peak', 'agamaggan', 'aggramar', 'akama', 'alexstrasza', 'alleria', 'altar-of-storms', 'alterac-mountains', 'amanthul', 'andorhal', 'antonidas', 'anubarak', 'anvilmar', 'arathor', 'area-52', 'argent-dawn', 'arthas', 'arygos', 'auchindoun', 'azgalor', 'azjolnerub', 'azralon', 'azuremyst', 'baelgun', 'barthilas', 'black-dragonflight', 'blackhand', 'blackrock', 'blackwater-raiders', 'blackwing-lair', 'bladefist', 'blades-edge', 'bleeding-hollow', 'blood-furnace', 'bloodhoof', 'bloodscalp', 'borean-tundra', 'bronzebeard', 'burning-blade', 'caelestrasz', 'cairne', 'cenarion-circle', 'cenarius', 'coilfang', 'dalaran', 'darkspear', 'darrowmere', 'dathremar', 'dawnbringer', 'deathwing', 'dentarg', 'draenor', 'dragonblight', 'draka', 'drakkari', 'draktharon', 'drakthul', 'dreadmaul', 'durotan', 'earthen-ring', 'eitrigg', 'eldrethalas', 'elune', 'emerald-dream', 'eonar', 'eredar', 'exodar', 'farstriders', 'feathermoon', 'frostmane', 'frostmourne', 'frostwolf', 'gallywix', 'garona', 'garrosh', 'ghostlands', 'gnomeregan', 'goldrinn', 'greymane', 'grizzly-hills', 'gundrak', 'hellscream', 'hydraxis', 'hyjal', 'icecrown', 'illidan', 'kargath', 'kelthuzad', 'kiljaeden', 'kilrogg', 'kirin-tor', 'korgath', 'lightbringer', 'lightninghoof', 'malfurion', 'malganis', 'misha', 'moknathal', 'moon-guard', 'muradin', 'nazgrel', 'nemesis', 'proudmoore', 'queldorei', 'quelthalas', 'ragnaros', 'ravencrest', 'ravenholdt', 'runetotem', 'sargeras', 'saurfang', 'stormrage', 'stormreaver', 'thrall', 'tichondrius', 'turalyon', 'wyrmrest-accord', 'zuljin']
  48.  
  49.  
  50. # In[6]:
  51.  
  52.  
  53. def get_data_path(realm):
  54. return os.path.join(auction_data_path, f'{realm}.json')
  55.  
  56. def get_data(realm):
  57. with open(get_data_path(realm), 'r') as f:
  58. return json.load(f)
  59.  
  60. def set_data(realm, data):
  61. with open(get_data_path(realm), 'w') as f:
  62. json.dump(data, f)
  63.  
  64. def get_mtime_path(realm):
  65. return os.path.join(auction_data_path, f'{realm}.mtime')
  66.  
  67. def get_mtime(realm):
  68. try:
  69. with open(get_mtime_path(realm), 'r') as f:
  70. return int(f.read())
  71. except FileNotFoundError:
  72. return 0
  73.  
  74. def set_mtime(realm, mtime):
  75. with open(get_mtime_path(realm), 'w') as f:
  76. f.write(str(mtime))
  77.  
  78. def update_realm(realm, access_token):
  79. realm_response = requests.get(
  80. f'https://us.api.blizzard.com/wow/auction/data/{realm}?locale=en_US&access_token={access_token}'
  81. )
  82. metadata = realm_response.json()['files'][0]
  83. new_mtime = metadata['lastModified']
  84. if new_mtime > get_mtime(realm):
  85. data_response = requests.get(metadata['url'])
  86. set_data(realm, data_response.json()['auctions'])
  87. set_mtime(realm, new_mtime)
  88. return True
  89. else:
  90. return False
  91.  
  92.  
  93. # In[7]:
  94.  
  95.  
  96. def do_update_realm(param):
  97. (realm, access_token) = param
  98. try:
  99. if update_realm(realm, access_token):
  100. print(f'realm {realm} updated')
  101. else:
  102. print(f'realm {realm} already up to date')
  103. return True
  104. except Exception as e:
  105. print(f'realm {realm} update failed: {e}')
  106. return False
  107.  
  108. # def update_all_realms(realm_list):
  109. # realms_left = set(realm_list)
  110. # max_attempts = 10
  111. # for attempt_idx in range(max_attempts):
  112. # if not realms_left:
  113. # break
  114. # print(f'attempt {attempt_idx+1}/{max_attempts}, {len(realms_left)} realms left')
  115. # for realm in realms_left.copy():
  116. # try:
  117. # if update_realm(realm):
  118. # print(f'realm {realm} updated')
  119. # else:
  120. # print(f'realm {realm} already up to date')
  121. # realms_left.remove(realm)
  122. # except Exception as e:
  123. # print(f'realm {realm} update failed: {e}')
  124. # print('done')
  125.  
  126.  
  127. # In[8]:
  128.  
  129.  
  130. def get_item_bonuses(auc):
  131. if 'bonusLists' not in auc:
  132. return
  133. for b in auc['bonusLists']:
  134. yield b['bonusListId']
  135.  
  136.  
  137. def parse_item_bonuses(bonuses):
  138. item_level = 430
  139. warforge = 0
  140. socketed = False
  141. corruption = None
  142. for b in bonuses:
  143. if b == 4822: # Nya normal
  144. item_level = 445
  145. elif b == 4823: # Nya heroic
  146. item_level = 460
  147. elif b == 4824: # Nya mythic
  148. item_level = 475
  149. elif b == 4802 or b == 1808:
  150. socketed = True
  151. elif b in corruption_table:
  152. corruption = corruption_table[ b ]
  153. item_level += warforge
  154. return item_level, socketed, corruption
  155.  
  156. def get_buyout_price(auc):
  157. if 'buyout' not in auc or auc['buyout'] <= 0:
  158. return math.inf
  159. return 0.0001 * auc['buyout']
  160.  
  161.  
  162. def search_realm_for_items(realm, items):
  163. auctions = get_data(realm)
  164. for auc in auctions:
  165. if auc['item'] in items:
  166. bonuses = get_item_bonuses(auc)
  167. item_level, socketed, corruption = parse_item_bonuses(bonuses)
  168. buyout = get_buyout_price(auc)
  169. yield {
  170. 'item': auc['item'],
  171. 'realm': realm,
  172. 'item_level': item_level,
  173. 'socketed': socketed,
  174. 'corruption': corruption,
  175. # 'owner': auc['owner'],
  176. 'buyout': buyout,
  177. 'time_left': auc['timeLeft']
  178. }
  179.  
  180. def do_search_realm_for_item(param):
  181. (realm, items) = param
  182. return list(search_realm_for_items(realm, items))
  183.  
  184.  
  185. def get_access_token():
  186. token_response = requests.post(
  187. 'https://us.battle.net/oauth/token',
  188. data={'grant_type': 'client_credentials'},
  189. auth=('6e207de394fb4083a5ed10219cbf2626', '8Z4m1BDpgs62U4mqi3JTuNWdQg78YDcz') # add your API credentials here; https://develop.battle.net/documentation/guides/getting-started
  190. )
  191. return token_response.json()['access_token']
  192.  
  193. def update_all_realms(pool, access_token):
  194. realms_left = set(realm_list)
  195. for attempt in range(10):
  196. params = ((realm, access_token) for realm in realms_left)
  197. results = pool.imap_unordered(do_update_realm, params)
  198. realms_left = {realm for (realm, success) in zip(realm_list, results) if not success}
  199. if realms_left:
  200. print(f'{len(realms_left)} updates failed: {realms_left}')
  201. else:
  202. print(f'all updates succeeded')
  203.  
  204. def search_all_realms_for_items(items):
  205. best_prices = {item: {} for item in items}
  206. params = [(realm, items) for realm in realm_list]
  207. results = pool.imap_unordered(do_search_realm_for_item, params)
  208. for r in it.chain.from_iterable(results):
  209. if r['corruption'] in interesting_corruptions:
  210. bp = best_prices[r['item']]
  211. eilvl = r['item_level'] + (10 if r['socketed'] else 0)
  212. if eilvl not in bp:
  213. bp[eilvl] = []
  214. bp[eilvl].append(r)
  215. for bp in best_prices.values():
  216. for rs in bp.values():
  217. rs.sort(key=lambda r: r['buyout'])
  218. return best_prices
  219.  
  220. # uncomment the pieces and corruptions that you are looking for
  221.  
  222. interesting_items = [
  223. # (175004, "Legwraps of Horrifying Figments"), # cloth pants
  224. # (175005, "Belt of Concealed Intent"), # mail belt
  225. #(175006, "Gauntlets of Nightmare Manifest"), # plate gloves
  226. # (175007, "Footpads of Terrible Delusions"), # leather boots
  227. (175008, "Lurking Schemer's Band"), # ring
  228. # (175009, "Zealous Ritualist's Reverie"), # off hand
  229. # (175010, "Maddened Adherent's Bulwark"), # shield
  230. ]
  231.  
  232. corruption_table = {
  233. # 6474 : 'Expedient I',
  234. # 6475 : 'Expedient II',
  235. # 6476 : 'Expedient III',
  236. # 6471 : 'Masterful I',
  237. # 6472 : 'Masterful II',
  238. # 6473 : 'Masterful III',
  239. # 6480 : 'Severe I',
  240. # 6481 : 'Severe II',
  241. # 6482 : 'Severe III',
  242. # 6477 : 'Versatile I',
  243. # 6478 : 'Versatile II',
  244. # 6479 : 'Versatile III',
  245. # 6437 : 'Strikethrough I',
  246. # 6438 : 'Strikethrough II',
  247. # 6439 : 'Strikethrough III',
  248. # 6555 : 'Racing Pulse I',
  249. # 6559 : 'Racing Pulse II',
  250. # 6560 : 'Racing Pulse III',
  251. # 6556 : 'Deadly Momentum I',
  252. # 6561 : 'Deadly Momentum II',
  253. # 6562 : 'Deadly Momentum III',
  254. # 6558 : 'Surging Vitality I',
  255. # 6565 : 'Surging Vitality II',
  256. # 6566 : 'Surging Vitality III',
  257. # 6557 : 'Honed Mind I',
  258. # 6563 : 'Honed Mind II',
  259. # 6564 : 'Honed Mind III',
  260. # 6549 : 'Echoing Void I',
  261. # 6550 : 'Echoing Void II',
  262. # 6551 : 'Echoing Void III',
  263. # 6552 : 'Infinite Stars I',
  264. # 6553 : 'Infinite Stars II',
  265. # 6554 : 'Infinite Stars III',
  266. # 6547 : 'Ineffable Truth I',
  267. # 6548 : 'Ineffable Truth II',
  268. 6537 : 'Twilight Devastation I',
  269. 6538 : 'Twilight Devastation II',
  270. 6539 : 'Twilight Devastation III',
  271. # 6543 : 'Twisted Appendage I',
  272. # 6544 : 'Twisted Appendage II',
  273. # 6545 : 'Twisted Appendage III',
  274. # 6540 : 'Void Ritual I',
  275. # 6541 : 'Void Ritual II',
  276. # 6542 : 'Void Ritual III',
  277. 6573 : 'Gushing Wound',
  278. }
  279.  
  280. interesting_corruptions = dict(map(reversed, corruption_table.items()))
  281.  
  282. if __name__ == '__main__':
  283. access_token = get_access_token()
  284. print(f'access token: {access_token}')
  285. with multiprocessing.Pool(32) as pool:
  286. update_all_realms(pool, access_token)
  287. items = set(item_id for (item_id, item_name) in interesting_items)
  288. best_prices = search_all_realms_for_items(items)
  289. for item_id, item_name in interesting_items:
  290. print(f'\n========== {item_name} ==========\n')
  291. pprint(best_prices[item_id])
  292.  
  293.  
  294. # most of this is not my code; I have no idea who wrote it, but all credit goes to them
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement