· 6 years ago · Jan 24, 2020, 03:34 PM
1from discord.ext import tasks, commands
2
3import requests
4import json
5import datetime
6
7
8
9
10class unupc(commands.Cog):
11 def __init__(self, bot):
12
13 self.bot = bot
14 self.refreshprices_loop.start() # pylint: disable=no-member
15
16 def refreshprices_func(self): #updates the unusual prices, writes them to a file
17
18 with open('commands/cogs/unupc/api_key.txt', 'r') as api_key: #opens the file containing the api key (remember the core bot file is in a higher directory)
19 key = api_key.read() #reads the file and assings to a var
20 payload = {'key': key} #formats the request payload
21 print('Connecting to Backpack.tf API')
22
23 request = requests.get('https://backpack.tf/api/IGetPrices/v4?', params=payload) #requests from the API with the given params
24 response = request.json() #formats the json retrieved from the API
25 if response['response']['success'] == 0: #if the request is unsuccsessful
26 print('Request failed')
27 with open('api responses/backpacktf_igetpricesv4_response.json', 'w+') as backpacktf_response: #writes the api response to a file
28 json.dump(response, backpacktf_response)
29
30 print(f"Prices updated at {datetime.datetime.now()}")
31
32
33 @tasks.loop(hours=2.0) #updates the prices every 2 hours
34 async def refreshprices_loop(self):
35 self.refreshprices_func()
36
37 @refreshprices_loop.before_loop
38 async def before_refreshprices(self):
39 await self.bot.wait_until_ready()
40
41
42 @commands.command()
43 async def refreshprices(self, ctx):
44 self.refreshprices_func()
45 await ctx.send('Prices updated!')
46
47
48 @commands.command() #the main unupc command
49 async def unupc(self, ctx, item_input): #defines the command itself itself
50
51 def getPrices(): #calls the api and formats it for unusual price checking. returns a list of possible unusual items if successful, returns None if not
52 with open('api responses/backpacktf_igetpricesv4_response.json', 'r') as response_raw:
53 response = json.load(response_raw)
54
55 if response['response']['success'] == 0: #if the request was unsuccessful
56 return None #doesn't need to send a message to say the request was unsuccessful, because the API will be called automatically every 2 hours
57 else: #if the request was successful
58 unusual_item_list = [] #adds every item that be unusual to a list
59 for item in response['response']['items']: #iterates through every single item
60 for quality in response['response']['items'][item]['prices'].keys(): #iterates through every possible quality of the item
61 if quality == '5': #if the item has can have the unusual quality (5)
62 unusual_item_list.append(item) #adds the item to the list of items that can be unusual
63
64 unusual_item_list.sort() #sorts the list of items that can be unusual, alphabetically. helps make the command more predictable in cases where several hats start with the given hat name
65 return unusual_item_list, response #returns both the list of items that can be unusual (for the hat finding), and the full response (for pricing), as a tuple
66
67 if '.' not in ctx.message.content: #if the message doesn't contain a period
68 await ctx.send("Invalid command syntax: correct syntax is ``effect.hat``")
69 return
70
71 item_input = item_input.split('.') #splits the params of the command at a period (correct syntax is effect.hat), to create a list with 2 entries
72 print(item_input) #for debugging
73
74 getPrices_result = getPrices() #needs to be assigned like this to avoid calling the function several times
75 unusual_item_list = getPrices_result[0] #the list of items that can be unusual
76 response = getPrices_result[1] #the full response from the API
77
78 if unusual_item_list == None:
79 await ctx.send("Couldn't call backpack.tf's API, something has gone mighty wrong")
80 return #leaves the function if it can't call the api
81
82
83
84 #hat autocomplete
85 item_hat = None
86 for item in unusual_item_list: #cycles through the list of items that can be unusual
87 if item_input[1].lower() in item.lower(): #if the hat string is in the name of the item
88 item_hat = item #sets the item_hat (base item of the hat/taunt/whatever in question) to the matching entry
89 break
90
91 if item_hat == None: #if a matching hat name isn't found, the var remains as None
92 await ctx.send("Couldn't find a hat with that name. Make sure you're using correct syntax (``effect.hat``)")
93 return #leaves the function
94
95
96
97 #effect autocomplete
98 item_effect = None
99 effects_dict = {"Nebula":"99","Burning Flames":"13","Spellbound":"74","It's A Secret To Everybody":"46","Scorching Flames":"14","Harvest Moon":"45","Arcana":"73","Abduction":"91","Sunbeams":"17","Darkblaze":"79","Bonzo The All-Gnawing":"81","Poisoned Shadows":"76","Knifestorm":"43","Stormy 13th Hour":"47","Hellfire":"78","Cloudy Moon":"38","Energy Orb":"704","Misty Skull":"44","Anti-Freeze":"69","Chiroptera Venenata":"75","Roboactive":"72","Demonflame":"80","Atomic":"92","Something Burning This Way Comes":"77","Galactic Codex":"97","Voltaic Hat Protector":"96","Purple Energy":"10","Death by Disco":"100","Green Energy":"9","Ether Trail":"103","Frostbite":"87","Subatomic":"93","Death at Dusk":"90","Ancient Codex":"98","Time Warp":"70","Cool":"703","Morning Glory":"89","Green Black Hole":"71","Amaranthine":"82","Magnetic Hat Protector":"95","Ghastly Ghosts Jr":"85","The Ooze":"84","Haunted Phantasm Jr":"86","Circling Heart":"19","Sulphurous":"64","Electric Hat Protector":"94","Eldritch Flame":"106","Cauldron Bubbles":"39","Stare From Beyond":"83","Haunted Ghosts":"8","Nether Trail":"104","It's a mystery to everyone":"101","Phosphorous":"63","Ancient Eldritch":"105","Flaming Lantern":"37","Hot":"701","Isotope":"702","It's a puzzle to me":"102","Vivid Plasma":"16","Molten Mallard":"88","Tesla Coil":"108","Eerie Orbiting Fire":"40","Haunted Phantasm":"3011","Searing Plasma":"15","Disco Beat Down":"62","Ghastly Ghosts":"3012","Starstorm Insomnia":"109","Starstorm Slumber":"110","Power Surge":"68","Circling Peace Sign":"18","Cloud 9":"58","Electrostatic":"67","Neutron Star":"107","Blizzardy Storm":"30","Circling TF Logo":"11","Infernal Flames":"3015","Infernal Smoke":"3016","Purple Confetti":"7","Stormy Storm":"29","Spectral Swirl":"3014","Holy Grail":"3003","Screaming Tiger":"3006","Miami Nights":"61","Green Confetti":"6","Fountain of Delight":"3005","Memory Leak":"65","Hellish Inferno":"3013","Showstopper":"3001","Terror-Watt":"57","Orbiting Fire":"33","Overclocked":"66","Kill-a-Watt":"56","Massed Flies":"12","Smoking":"35","Bubbling":"34","Steaming":"36","Orbiting Planets":"32","Dead Presidents":"60","Nuts n' Bolts":"31","'72":"3004","Aces High":"59","Skill Gotten Gains":"3007","Mega Strike":"3010","Silver Cyclone":"3009","Midnight Whirlwind":"3008"}
100 #some exceptions (effects that won't work on their own when entered)
101
102 if item_input[0].lower() == 'orbiting fire': #item_effect will otherwise be set to Eerie orbiting fire, even when using the full name
103 item_effect = 'Orbiting Fire'
104 else:
105 print(item_input[0]) #for debugging
106 for effect in effects_dict.keys(): #cycles through every effect in the dict
107 print(effect) #for debugging
108 if item_input[0].lower() in effect.lower(): #if the key name matches the given effect name
109 item_effect = effect #sets the given item's effect to the current one
110
111 if item_effect == None: #if the specified effect couldn't be found in the dict
112 await ctx.send("Couldn't find an effect with that name. Make sure you're using correct syntax (``effect.hat``)")
113 return #quits the function
114
115 print(item_effect, item_hat) #for... wait for it... debugging
116 print(effects_dict[item_effect]) #guess
117
118 try:
119 price_currency = response['response']['items'][item_hat]['prices']['5']['Tradable']['Craftable'][effects_dict[item_effect]]['currency']
120 price_low = response['response']['items'][item_hat]['prices']['5']['Tradable']['Craftable'][effects_dict[item_effect]]['value']
121
122 try: #if the item has a high value, uses that
123 price_high = response['response']['items'][item_hat]['prices']['5']['Tradable']['Craftable'][effects_dict[item_effect]]['value_high']
124 price_average = (price_low + price_high)/2 #calculates the price average off the low and high values
125 if '.' in str(price_average) and str(price_average)[-1] == '0': #if the average price has a comma in it, but ends in a 0, converts it to int to remove the unnecessary decimal
126 price_average = int(price_average)
127
128 price_message = f"The {item_effect} {item_hat} is priced at {price_low}-{price_high} {price_currency} ({price_average})"
129
130 except KeyError: #if the item does not have a high value, uses a different format for the output message
131 price_message = f"The {item_effect} {item_hat} is priced at {price_low} {price_currency}"
132
133 except KeyError: #if a hat with the specified effect can't be found
134 await ctx.send("An error occured: This item is either unpriced, or doesn't exist")
135 return
136
137 await ctx.send(price_message)
138
139 def cog_unload(self):
140 self.refreshprices_loop.cancel()
141
142
143#consider making things more object based
144
145
146def setup(bot): #runs when the extension is loaded
147 bot.add_cog(unupc(bot))
148 print("Cog unupc loaded!")