· 6 years ago · Mar 24, 2020, 03:08 PM
1import configparser
2import operator
3import os
4import webbrowser
5from datetime import datetime, timedelta
6from time import time
7
8import pushbullet
9import pyperclip
10import requests
11import win32api
12import win32con
13import win32gui
14from PIL import ImageGrab
15from playsound import playsound
16
17# ADDED MULTIACCOUNT SUPPORT
18
19def Avg(lst):
20 return sum(lst) / len(lst)
21
22
23# noinspection PyShadowingNames
24def enum_cb(hwnd, results):
25 winlist.append((hwnd, win32gui.GetWindowText(hwnd)))
26
27
28def write(message, add_time=True, push=0, push_now=False):
29 if message:
30 if add_time:
31 m = datetime.now().strftime("%H:%M:%S") + ": " + str(message)
32 else:
33 m = message
34 print(m)
35
36 if push >= 3:
37 global note
38 if message:
39 note = note + m + "\n"
40 if push_now:
41 device.push_note("CSGO AUTO ACCEPT", note)
42 note = ""
43
44
45def click(x, y):
46 win32api.SetCursorPos((x, y))
47 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, x, y, 0, 0)
48 win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, x, y, 0, 0)
49
50
51# noinspection PyShadowingNames,PyShadowingNames
52def relate_list(l_org, l1, l2=[], relate=operator.le):
53 if not l_org:
54 return False
55 truth_list, l3 = [], []
56 for i, val in enumerate(l1, start=0):
57 l3.append(relate(l_org[i], val))
58 truth_list.append(all(l3))
59 l3 = []
60 if l2:
61 for i, val in enumerate(l2, start=3):
62 l3.append(relate(l_org[i], val))
63 truth_list.append(all(l3))
64 return any(truth_list)
65
66
67# noinspection PyShadowingNames,PyShadowingNames
68def color_average(image, compare_list):
69 average = []
70 r, g, b = [], [], []
71 data = image.getdata()
72 for i in data:
73 r.append(i[0])
74 g.append(i[1])
75 b.append(i[2])
76
77 rgb = [Avg(r), Avg(g), Avg(b)] * int(len(compare_list) / 3)
78
79 for i, val in enumerate(compare_list, start=0):
80 average.append(val - rgb[i])
81 average = list(map(abs, average))
82
83 return average
84
85
86# noinspection PyShadowingNames,PyShadowingNames
87def getScreenShot(window_id, area=(0, 0, 0, 0)):
88 area = list(area)
89 scaled_area = [screen_width / 2560, screen_height / 1440]
90 scaled_area = 2 * scaled_area
91 for i, _ in enumerate(area[-2:], start=len(area) - 2):
92 area[i] += 1
93 for i, val in enumerate(area, start=0):
94 scaled_area[i] = scaled_area[i] * val
95 scaled_area = list(map(int, scaled_area))
96 win32gui.ShowWindow(window_id, win32con.SW_MAXIMIZE)
97 image = ImageGrab.grab(scaled_area)
98 return image
99
100
101# noinspection PyShadowingNames
102def getOldSharecodes(num=-1):
103 try:
104 last_game = open("last_game_"+accounts[current_account]["steam_id"]+".txt", "r")
105 games = last_game.readlines()
106 last_game.close()
107 except FileNotFoundError:
108 last_game = open("last_game_"+accounts[current_account]["steam_id"]+".txt", "w")
109 last_game.write(accounts[current_account]["match_token"] + "\n")
110 games = [accounts[current_account]["match_token"]]
111 last_game.close()
112 last_game = open("last_game_"+accounts[current_account]["steam_id"]+".txt", "w")
113 games = games[-200:]
114 for i, val in enumerate(games):
115 games[i] = "CSGO" + val.strip("\n").split("CSGO")[1]
116 last_game.write(games[i] + "\n")
117 last_game.close()
118 return games[num:]
119
120
121def getNewCSGOMatches(game_id):
122 sharecodes = []
123 next_code = game_id
124 last_game = open("last_game_"+accounts[current_account]["steam_id"]+".txt", "a")
125 while next_code != "n/a":
126 steam_url = "https://api.steampowered.com/ICSGOPlayers_730/GetNextMatchSharingCode/v1?key=" + steam_api_key + "&steamid=" + accounts[current_account]["steam_id"] + "&steamidkey=" + accounts[current_account]["auth_code"] + "&knowncode=" + game_id
127 try:
128 next_code = (requests.get(steam_url).json()["result"]["nextcode"])
129 except KeyError:
130 write("WRONG GAME_CODE, GAME_ID or STEAM_ID ")
131 return 0
132
133 if next_code:
134 if next_code != "n/a":
135 sharecodes.append(next_code)
136 game_id = next_code
137 last_game.write(next_code + "\n")
138 if sharecodes:
139 return sharecodes
140 else:
141 return [game_id]
142
143
144# noinspection PyShadowingNames
145def UpdateCSGOstats(sharecodes, num_completed=1):
146 completed_games, analyze_games = [], []
147 for val in sharecodes:
148 response = requests.post("https://csgostats.gg/match/upload/ajax", data={'sharecode': val, 'index': '1'})
149 if response.json()["status"] == "complete":
150 completed_games.append(response.json())
151 else:
152 analyze_games.append(response.json())
153 # TEST GAME:
154 # analyze_games = [{'status': 'complete', 'data': {'msg': 'Complete - <a href="/match/7584322">View</a>', 'index': '1', 'sharecode': 'CSGO-7NiMO-RPjvj-MZNWP-9cRdx-vzYUN', 'queue_id': 8081108, 'demo_id': 7584322, 'url': 'https://csgostats.gg/match/7584322'}, 'error': 0}]
155 output = [completed_games[num_completed * -1:], analyze_games]
156 for i in output:
157 for json_dict in i:
158 sharecode = json_dict["data"]["sharecode"]
159 game_url = json_dict["data"]["url"]
160 info = json_dict["data"]["msg"].split("<")[0].replace('-', '').rstrip(" ")
161 write('Sharecode: %s' % sharecode, add_time=False, push=push_urgency)
162 write("URL: %s" % game_url, add_time=False, push=push_urgency)
163 write("Status: %s." % info, add_time=False, push=push_urgency)
164 write(None, add_time=False, push=push_urgency, push_now=True)
165 pyperclip.copy(completed_games[-1]["data"]["url"])
166 return game_url
167
168
169def getHotKeys():
170 get_keys = [int(config.get("HotKeys", "Activate Script"), 16), int(config.get("HotKeys", "Activate Push Notification"), 16), int(config.get("HotKeys", "Get Info on newest Match"), 16),
171 int(config.get("HotKeys", "Get Info on multiple Matches"), 16), int(config.get("HotKeys", "Live Tab Key"), 16), int(config.get("HotKeys", "Switch accounts for csgostats.gg"), 16),
172 int(config.get("HotKeys", "End Script"), 16)]
173 return get_keys
174
175
176config = configparser.ConfigParser()
177config.read("config.ini")
178steam_api_key = config.get("csgostats.gg", "API Key")
179screenshot_interval = config.getint("Screenshot", "Interval")
180keys = getHotKeys()
181device = 0
182
183
184accounts, current_account = [], 0
185steam_ids = ","
186for i in config.sections():
187 if i.startswith("Account"):
188 # display_name = config.get(i, "Display Name")
189 steam_id = config.get(i, "Steam ID")
190 auth_code = config.get(i, "Authentication Code")
191 match_token = config.get(i, "Match Token")
192 steam_ids = steam_id + "," + steam_ids
193 accounts.append({"steam_id": steam_id, "auth_code": auth_code, "match_token": match_token})
194
195steam_ids = steam_ids[:-1]
196profiles = requests.get("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=" + steam_api_key + "&steamids=" + steam_ids).json()["response"]["players"]
197for i, val in enumerate(profiles):
198 accounts[i]["name"] = val["personaname"]
199
200
201screen_width, screen_height = win32api.GetSystemMetrics(0), win32api.GetSystemMetrics(1)
202toplist, winlist = [], []
203hwnd = 0
204
205test_for_live_game, test_for_success, push_urgency, testing = False, False, False, False
206# accept_avg = []
207
208note = ""
209
210start_time = time()
211write("READY")
212write("current account is: %s" % accounts[current_account]["name"], add_time=False)
213print("\n")
214
215while True:
216 if win32api.GetAsyncKeyState(keys[0]) & 1: # F9 (ACTIVATE / DEACTIVATE SCRIPT)
217 test_for_live_game = not test_for_live_game
218 write("TESTING: %s" % test_for_live_game)
219 if test_for_live_game:
220 playsound('sounds/activated.mp3')
221 time_searching = time()
222 else:
223 playsound('sounds/deactivated.mp3')
224
225 if win32api.GetAsyncKeyState(keys[1]) & 1: # F8 (ACTIVATE / DEACTIVATE PUSH NOTIFICATION)
226 if not device:
227 PushBulletDeviceName = config.get('Pushbullet', 'Device Name')
228 PushBulletAPIKey = config.get('Pushbullet', 'API Key')
229 try:
230 device = pushbullet.PushBullet(PushBulletAPIKey).get_device(PushBulletDeviceName)
231 except pushbullet.errors.PushbulletError or pushbullet.errors.InvalidKeyError:
232 write("Pushbullet is wrongly configured.\nWrong API Key or DeviceName in config.ini")
233 if device:
234 push_urgency += 1
235 if push_urgency > 3:
236 push_urgency = 0
237 push_info = ["not active", "only if accepted", "all game status related information", "all information (game status/csgostats.gg information)"]
238 write("Pushing: %s" % push_info[push_urgency])
239
240 if win32api.GetAsyncKeyState(keys[2]) & 1: # F7 Key (UPLOAD NEWEST MATCH)
241 write("Uploading / Getting status on newest match")
242 pyperclip.copy(UpdateCSGOstats(getNewCSGOMatches(getOldSharecodes()[0])))
243
244 if win32api.GetAsyncKeyState(keys[3]) & 1: # F6 Key (GET INFO ON LAST X MATCHES)
245 last_x_matches = config.getint("csgostats.gg", "Number of Requests")
246 completed_matches = config.getint("csgostats.gg", "Completed Matches")
247 write("Getting Info from last %s matches" % last_x_matches)
248 # write("Outputting %s completed match[es]" % completed_matches, add_time=False)
249 getNewCSGOMatches(getOldSharecodes()[0])
250 UpdateCSGOstats(getOldSharecodes(num=last_x_matches * -1), num_completed=completed_matches)
251
252 if win32api.GetAsyncKeyState(keys[4]) & 1: # F13 Key (OPEN WEB BROWSER ON LIVE GAME TAB)
253 webbrowser.open_new_tab("https://csgostats.gg/player/" + accounts[current_account]["steam_id"] + "#/live")
254 write("new tab opened", add_time=False)
255
256 if win32api.GetAsyncKeyState(keys[5]) & 1: # F15 (SWITCH ACCOUNTS)
257 current_account += 1
258 if current_account > len(accounts)-1:
259 current_account = 0
260 write("current account is: %s" % accounts[current_account]["name"], add_time=False)
261
262 if win32api.GetAsyncKeyState(keys[6]) & 1: # POS1/HOME Key
263 write("Exiting Script")
264 break
265
266 winlist = []
267 win32gui.EnumWindows(enum_cb, toplist)
268 csgo = [(hwnd, title) for hwnd, title in winlist if 'counter-strike: global offensive' in title.lower()]
269 if not csgo:
270 continue
271 hwnd = csgo[0][0]
272
273 # TESTING HERE
274 if win32api.GetAsyncKeyState(0x73) & 1: # F5, TEST CODE
275 print("\n")
276 write("Executing TestCode")
277 print("\n")
278 testing = not testing
279
280 if testing:
281 # start_time = time()
282 img = getScreenShot(hwnd, (2435, 65, 2555, 100))
283 not_searching_avg = color_average(img, [6, 10, 10])
284 searching_avg = color_average(img, [6, 163, 97, 4, 63, 35])
285 not_searching = relate_list(not_searching_avg, [2, 5, 5])
286 searching = relate_list(searching_avg, [2.7, 55, 35], l2=[1, 50, 35])
287 img = getScreenShot(hwnd, (467, 1409, 1300, 1417))
288 success_avg = color_average(img, [21, 123, 169])
289 success = relate_list(success_avg, [1, 8, 7])
290 # print("Took: %s " % str(timedelta(milliseconds=int(time()*1000 - start_time*1000))))
291 # TESTING ENDS HERE
292
293 if test_for_live_game:
294 if time() - start_time < screenshot_interval:
295 continue
296 start_time = time()
297 img = getScreenShot(hwnd, (1265, 760, 1295, 785))
298 if not img:
299 continue
300 accept_avg = color_average(img, [76, 176, 80, 90, 203, 95])
301
302 if relate_list(accept_avg, [1, 2, 1], l2=[1, 1, 2]):
303 write("Trying to Accept", push=push_urgency + 1)
304
305 test_for_success = True
306 test_for_live_game = False
307 accept_avg = []
308
309 for _ in range(5):
310 click(int(screen_width / 2), int(screen_height / 1.78))
311 # sleep(0.5)
312 # pass
313
314 write("Trying to catch a loading map")
315 playsound('sounds/accept_found.mp3')
316 start_time = time()
317
318 if test_for_success:
319 if time() - start_time < 40:
320 img = getScreenShot(hwnd, (2435, 65, 2555, 100))
321 not_searching_avg = color_average(img, [6, 10, 10])
322 searching_avg = color_average(img, [6, 163, 97, 4, 63, 35])
323
324 not_searching = relate_list(not_searching_avg, [2, 5, 5])
325 searching = relate_list(searching_avg, [2.7, 55, 35], l2=[1, 50, 35])
326
327 img = getScreenShot(hwnd, (467, 1409, 1300, 1417))
328 success_avg = color_average(img, [21, 123, 169])
329 success = relate_list(success_avg, [1, 8, 7])
330
331 if success:
332 write("Took %s since pressing accept." % str(timedelta(seconds=int(time() - start_time))), add_time=False, push=push_urgency + 1)
333 write("Took %s since trying to find a game." % str(timedelta(seconds=int(time() - time_searching))), add_time=False, push=push_urgency + 1)
334 write("Game should have started", push=push_urgency + 2, push_now=True)
335 test_for_success = False
336 playsound('sounds/done_testing.mp3')
337
338 if any([searching, not_searching]):
339 write("Took: %s " % str(timedelta(seconds=int(time() - start_time))), add_time=False, push=push_urgency + 1)
340 write("Game doesnt seem to have started. Continuing to search for accept Button!", push=push_urgency + 1, push_now=True)
341 playsound('sounds/back_to_testing.mp3')
342 test_for_success = False
343 test_for_live_game = True
344
345 else:
346 write("40 Seconds after accept, did not find loading map nor searching queue")
347 test_for_success = False
348 print(success_avg)
349 print(searching_avg)
350 print(not_searching_avg)
351 playsound('sounds/fail.mp3')
352 img.save(os.path.expanduser("~") + '\\Unknown Error.png')