· 6 years ago · Mar 27, 2020, 01:52 AM
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
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 scaled_area = [screen_width / 2560, screen_height / 1440]
89 scaled_area = 2 * scaled_area
90 for i, _ in enumerate(area[-2:], start=len(area) - 2):
91 area[i] += 1
92 for i, val in enumerate(area, start=0):
93 scaled_area[i] = scaled_area[i] * val
94 scaled_area = list(map(int, scaled_area))
95 win32gui.ShowWindow(window_id, win32con.SW_MAXIMIZE)
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 #
155
156 queued_games = [game for game in not_completed_games if game["status"] != "retrying"]
157 retrying_games = [game["data"]["sharecode"] for game in not_completed_games if game["status"] == "retrying"]
158
159 output = [completed_games[num_completed * -1:], queued_games]
160 for i in output:
161 for json_dict in i:
162 sharecode = json_dict["data"]["sharecode"]
163 game_url = json_dict["data"]["url"]
164 info = json_dict["data"]["msg"].split("<")[0].replace('-', '').rstrip(" ")
165 " ".join(info.split())
166 write('Sharecode: %s' % sharecode, add_time=False, push=push_urgency)
167 write("URL: %s" % game_url, add_time=False, push=push_urgency)
168 write("Status: %s." % info, add_time=False, push=push_urgency)
169 write(None, add_time=False, push=push_urgency, push_now=True)
170
171 if completed_games:
172 pyperclip.copy(completed_games[-1]["data"]["url"])
173
174 if retrying_games:
175 write("%s game[s] will be rechecked after 45 seconds" % len(retrying_games))
176
177
178def getHotKeys():
179 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),
180 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),
181 int(config.get("HotKeys", "End Script"), 16)]
182 return get_keys
183
184
185config = configparser.ConfigParser()
186config.read("config.ini")
187steam_api_key = config.get("csgostats.gg", "API Key")
188screenshot_interval = config.getint("Screenshot", "Interval")
189keys = getHotKeys()
190device = 0
191
192
193accounts, current_account = [], 0
194steam_ids = ","
195for i in config.sections():
196 if i.startswith("Account"):
197 steam_id = config.get(i, "Steam ID")
198 auth_code = config.get(i, "Authentication Code")
199 match_token = config.get(i, "Match Token")
200 steam_ids += steam_id + ","
201 accounts.append({"steam_id": steam_id, "auth_code": auth_code, "match_token": match_token})
202
203steam_ids = steam_ids.lstrip(",").rstrip(",")
204profiles = requests.get("http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=" + steam_api_key + "&steamids=" + steam_ids).json()["response"]["players"]
205for i in profiles:
206 for n in accounts:
207 if n["steam_id"] == i["steamid"]:
208 n["name"] = i["personaname"]
209 break
210
211screen_width, screen_height = win32api.GetSystemMetrics(0), win32api.GetSystemMetrics(1)
212toplist, winlist = [], []
213hwnd = 0
214
215test_for_live_game, test_for_success, push_urgency, testing = False, False, False, False
216retrying_games = []
217
218note = ""
219
220screenshot_time, error_check_time = time(), time()
221write("READY")
222write("current account is: %s" % accounts[current_account]["name"], add_time=False)
223print("\n")
224
225while True:
226 if win32api.GetAsyncKeyState(keys[0]) & 1: # F9 (ACTIVATE / DEACTIVATE SCRIPT)
227 test_for_live_game = not test_for_live_game
228 write("TESTING: %s" % test_for_live_game)
229 if test_for_live_game:
230 playsound('sounds/activated.mp3')
231 time_searching = time()
232 else:
233 playsound('sounds/deactivated.mp3')
234
235 if win32api.GetAsyncKeyState(keys[1]) & 1: # F8 (ACTIVATE / DEACTIVATE PUSH NOTIFICATION)
236 if not device:
237 PushBulletDeviceName = config.get('Pushbullet', 'Device Name')
238 PushBulletAPIKey = config.get('Pushbullet', 'API Key')
239 try:
240 device = pushbullet.PushBullet(PushBulletAPIKey).get_device(PushBulletDeviceName)
241 except pushbullet.errors.PushbulletError or pushbullet.errors.InvalidKeyError:
242 write("Pushbullet is wrongly configured.\nWrong API Key or DeviceName in config.ini")
243 if device:
244 push_urgency += 1
245 if push_urgency > 3:
246 push_urgency = 0
247 push_info = ["not active", "only if accepted", "all game status related information", "all information (game status/csgostats.gg information)"]
248 write("Pushing: %s" % push_info[push_urgency])
249
250 if win32api.GetAsyncKeyState(keys[2]) & 1: # F7 Key (UPLOAD NEWEST MATCH)
251 write("Uploading / Getting status on newest match")
252 UpdateCSGOstats(getNewCSGOMatches(getOldSharecodes()[0]))
253
254 if win32api.GetAsyncKeyState(keys[3]) & 1: # F6 Key (GET INFO ON LAST X MATCHES)
255 last_x_matches = config.getint("csgostats.gg", "Number of Requests")
256 completed_matches = config.getint("csgostats.gg", "Completed Matches")
257 write("Getting Info from last %s matches" % last_x_matches)
258 # write("Outputting %s completed match[es]" % completed_matches, add_time=False)
259 getNewCSGOMatches(getOldSharecodes()[0])
260 UpdateCSGOstats(getOldSharecodes(num=last_x_matches * -1), num_completed=completed_matches)
261
262 if win32api.GetAsyncKeyState(keys[4]) & 1: # F13 Key (OPEN WEB BROWSER ON LIVE GAME TAB)
263 webbrowser.open_new_tab("https://csgostats.gg/player/" + accounts[current_account]["steam_id"] + "#/live")
264 write("new tab opened", add_time=False)
265
266 if win32api.GetAsyncKeyState(keys[5]) & 1: # F15 (SWITCH ACCOUNTS)
267 current_account += 1
268 if current_account > len(accounts)-1:
269 current_account = 0
270 print(current_account)
271 write("current account is: %s" % accounts[current_account]["name"], add_time=False)
272
273 if win32api.GetAsyncKeyState(keys[6]) & 1: # POS1/HOME Key
274 write("Exiting Script")
275 break
276
277 winlist = []
278 win32gui.EnumWindows(enum_cb, toplist)
279 csgo = [(hwnd, title) for hwnd, title in winlist if 'counter-strike: global offensive' in title.lower()]
280
281 if retrying_games:
282 if time() - error_check_time > 45:
283 error_check_time = time()
284 UpdateCSGOstats(retrying_games, num_completed=len(retrying_games))
285
286
287
288 # ONLY CONTINUING IF CSGO IS RUNNING
289 if not csgo:
290 continue
291 hwnd = csgo[0][0]
292
293 # TESTING HERE
294 if win32api.GetAsyncKeyState(0) & 1: # F5, TEST CODE
295 print("\n")
296 write("Executing TestCode")
297 print("\n")
298 testing = not testing
299
300 if testing:
301 # screenshot_time = time()
302 img = getScreenShot(hwnd, (2435, 65, 2555, 100))
303 not_searching_avg = color_average(img, [6, 10, 10])
304 searching_avg = color_average(img, [6, 163, 97, 4, 63, 35])
305 not_searching = relate_list(not_searching_avg, [2, 5, 5])
306 searching = relate_list(searching_avg, [2.7, 55, 35], l2=[1, 50, 35])
307 img = getScreenShot(hwnd, (467, 1409, 1300, 1417))
308 success_avg = color_average(img, [21, 123, 169])
309 success = relate_list(success_avg, [1, 8, 7])
310 # print("Took: %s " % str(timedelta(milliseconds=int(time()*1000 - screenshot_time*1000))))
311 # TESTING ENDS HERE
312
313 if test_for_live_game:
314 if time() - screenshot_time < screenshot_interval:
315 continue
316 screenshot_time = time()
317 img = getScreenShot(hwnd, (1265, 760, 1295, 785))
318 if not img:
319 continue
320 accept_avg = color_average(img, [76, 176, 80, 90, 203, 95])
321
322 if relate_list(accept_avg, [1, 2, 1], l2=[1, 1, 2]):
323 write("Trying to Accept", push=push_urgency + 1)
324
325 test_for_success = True
326 test_for_live_game = False
327 accept_avg = []
328
329 for _ in range(5):
330 click(int(screen_width / 2), int(screen_height / 1.78))
331 # sleep(0.5)
332 # pass
333
334 write("Trying to catch a loading map")
335 playsound('sounds/accept_found.mp3')
336 screenshot_time = time()
337
338 if test_for_success:
339 if time() - screenshot_time < 40:
340 img = getScreenShot(hwnd, (2435, 65, 2555, 100))
341 not_searching_avg = color_average(img, [6, 10, 10])
342 searching_avg = color_average(img, [6, 163, 97, 4, 63, 35])
343
344 not_searching = relate_list(not_searching_avg, [2, 5, 5])
345 searching = relate_list(searching_avg, [2.7, 55, 35], l2=[1, 50, 35])
346
347 img = getScreenShot(hwnd, (467, 1409, 1300, 1417))
348 success_avg = color_average(img, [21, 123, 169])
349 success = relate_list(success_avg, [1, 8, 7])
350
351 if success:
352 write("Took %s since pressing accept." % str(timedelta(seconds=int(time() - screenshot_time))), add_time=False, push=push_urgency + 1)
353 write("Took %s since trying to find a game." % str(timedelta(seconds=int(time() - time_searching))), add_time=False, push=push_urgency + 1)
354 write("Game should have started", push=push_urgency + 2, push_now=True)
355 test_for_success = False
356 playsound('sounds/done_testing.mp3')
357
358 if any([searching, not_searching]):
359 write("Took: %s " % str(timedelta(seconds=int(time() - screenshot_time))), add_time=False, push=push_urgency + 1)
360 write("Game doesnt seem to have started. Continuing to search for accept Button!", push=push_urgency + 1, push_now=True)
361 playsound('sounds/back_to_testing.mp3')
362 test_for_success = False
363 test_for_live_game = True
364
365 else:
366 write("40 Seconds after accept, did not find loading map nor searching queue")
367 test_for_success = False
368 print(success_avg)
369 print(searching_avg)
370 print(not_searching_avg)
371 playsound('sounds/fail.mp3')
372 img.save(os.path.expanduser("~") + '\\Unknown Error.png')