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