Skip to content

Instantly share code, notes, and snippets.

@NanoAi
Last active April 3, 2022 08:08
Show Gist options
  • Save NanoAi/cbc79b2fa694a079bdc2588c46746681 to your computer and use it in GitHub Desktop.
Save NanoAi/cbc79b2fa694a079bdc2588c46746681 to your computer and use it in GitHub Desktop.
A Python Script that uses League APIs to attempt to close the process when the game ends, without playing out the ending animation. Because alt+f4 is now disabled... READ THE FIRST COMMENT!
from lcu_driver import Connector
import requests, webbrowser, psutil, asyncio, re
# This will automatically open porofessor & League of Graphs in champ select.
# -- ALSO --
# This will poll the League In-Game API, and watch the GameFlow sockets
# to automatically end the process of your game when the game ends.
### Comment out as you see fit!
## However: I still think using autohotkey to just kill the process with a key
## press is better...
# Set your League Directory Here.
LEAGUE_DIR = 'C:\\Riot Games\\League of Legends\\'
# Make sure to escape your backslashes by doubling them up `\` = `\\`.
# There must be a `\\` at the end of the path.
# Set this to `False` if you don't want the game to try to autoclose when it ends.
ENABLE_AUTOCLOSE = True
# This will also fix any issues with process hanging.
# I think pressing alt+f4 or using autohotkey is faster.
LOCALHOST = 'localhost'
GAME_STATUS = ''
GOT_LOBBY = False
HAS_PICKED = False
GAME_PROCESS_ID = False
GET_TASK = False
lolLock = open(LEAGUE_DIR + 'lockfile', 'r')
GAMEAPI_LOCK = lolLock.read().rsplit(':')
GAMEAPI_PORT = GAMEAPI_LOCK[2]
lolLock.close()
print('Detected Port: ' + GAMEAPI_PORT)
def killProcessId():
global GAME_PROCESS_ID
if GAME_PROCESS_ID:
proc = psutil.Process(GAME_PROCESS_ID)
proc.terminate()
proc.kill()
GAME_PROCESS_ID = False
return
async def getInGameAPI():
global GAME_PROCESS_ID, GAMEAPI_PORT
while( GAMEAPI_PORT == '' ):
await asyncio.sleep(5)
for proc in psutil.process_iter(['pid', 'name']):
try:
if proc.is_running and 'League of Legends' in proc.name():
for connection in proc.connections():
if connection.status == psutil.CONN_LISTEN:
GAMEAPI_PORT = str(connection.laddr.port)
GAME_PROCESS_ID = proc.pid
except (psutil.NoSuchProcess, psutil.AccessDenied, psutil.ZombieProcess):
pass
return GAMEAPI_PORT
async def getInGameEvents():
global GAME_PROCESS_ID
while( True ):
await asyncio.sleep(0.5)
try:
response = requests.get(f'https://{LOCALHOST}:{GAMEAPI_PORT}' + '/liveclientdata/eventdata', verify=False)
print("REQ_STATUS: " + str(response.status_code), flush=True)
if response.status_code == requests.codes.ok:
for event in response.json()['Events']:
if event['EventName'] == 'GameEnd':
print(event, flush=True)
killProcessId()
GET_TASK.cancel()
break
except (ConnectionRefusedError):
print("\n!!!!!CLOSING!!!!", flush=True)
GET_TASK.cancel()
return
conn = Connector()
# fired when League Client is closed (or disconnected from websocket)
@conn.close
async def disconnect(_):
await conn.stop()
quit()
# START - LeagueOfGraphs
@conn.ws.register('/lol-champ-select/v1/session', event_types=('UPDATE',))
async def champSelectSession(connection, event):
global GOT_LOBBY, HAS_PICKED, BROWSER
lolGraphsURL = 'https://www.leagueofgraphs.com/champions/probuilds/'
teamSearchURL = 'https://na.op.gg/multi/query='
allyNames = ''
if not HAS_PICKED:
pick = await connection.request('get', '/lol-champ-select/v1/summoners/' + str(event.data['localPlayerCellId']))
if pick.status == 200:
outputJson = await pick.json()
if outputJson['isDonePicking'] == True:
print('CHAMPION PICKED: ' + outputJson['championName'], flush=True)
webbrowser.open( lolGraphsURL + re.sub(r'[^\w]', '', outputJson['championName']).strip().lower(), new=0, autoraise=False )
HAS_PICKED = True
if GOT_LOBBY == True: return
userIds = []
summonerNames = []
for player in event.data['myTeam']:
GOT_LOBBY = True
userIds.append(str(player['summonerId']))
userIdsStringify = ','.join(map(str, userIds))
summoner = await connection.request('get', f'/lol-summoner/v2/summoner-names?ids=[{userIdsStringify}]')
if summoner.status == 200:
for summonerInfo in await summoner.json():
summonerNames.append(summonerInfo['displayName'])
allyNames = ','.join(map(str, summonerNames))
print( 'TEAM:', allyNames, flush=True )
# webbrowser.open( 'https://porofessor.gg/pregame/na/' + allyNames )
webbrowser.open( teamSearchURL + allyNames, new=1, autoraise=False )
# END - LeagueOfGraphs
@conn.ws.register('/lol-gameflow/v1/gameflow-phase', event_types=('UPDATE',))
async def gameFlowStateChange(connection, event):
global GAME_STATUS, GET_TASK, GAME_PROCESS_ID, GOT_LOBBY, HAS_PICKED
global ENABLE_AUTOCLOSE
GAME_STATUS = event.data
print('GAME STATE: ' + event.data, flush=True)
# Waits for the game to be in progress and starts the InGameAPI polling
# Comment set `ENABLE_AUTOCLOSE` to `False` to disable.
if ENABLE_AUTOCLOSE and GAME_STATUS == "InProgress":
await asyncio.sleep(10)
GAMEAPI_PORT = await getInGameAPI()
print('GAMEAPI_PORT: ' + GAMEAPI_PORT, flush=True)
print('LISTENER: Starting Tasks', flush=True)
GET_TASK = asyncio.create_task(getInGameEvents())
if GAME_STATUS == 'WaitingForStats' or GAME_STATUS == 'None':
GOT_LOBBY = False
HAS_PICKED = False
if GAME_PROCESS_ID:
killProcessId()
if GET_TASK and GET_TASK.done():
print('\nLISTENER: Closing Tasks', flush=True)
GET_TASK.cancel()
# starts the connector
conn.start()
@Avnsx
Copy link

Avnsx commented Apr 3, 2022

As soon as the the ingame client starts I only keep getting REQ_STATUS: 404 @NanoAi

@Avnsx
Copy link

Avnsx commented Apr 3, 2022

Has this ever worked?

response = requests.get(f'https://{LOCALHOST}:{GAMEAPI_PORT}' + '/liveclientdata/eventdata', verify=False)

Because nowadays the ingame client is hardset to port 2999, but I was trying to use this code in hopes that you were somehow able to communicate with the league ingame client on a different port @NanoAi

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment