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