Skip to content

Commit

Permalink
Merge pull request #36 from Its-Haze/feature/launch-league
Browse files Browse the repository at this point in the history
Feature/launch league
  • Loading branch information
Its-Haze authored Apr 29, 2024
2 parents 8859379 + d4c6909 commit be7a6fa
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 51 deletions.
28 changes: 24 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,27 @@ This is what i do, to then publish the final `leagueRPC.exe` to Github.

LeagueRPC supports various command-line arguments to enhance flexibility and user customization.

### `--client-id <discord-app-id>`
✨ Means Recommended.

### `--launch-league <location>` ✨

The `--launch-league` argument allows you to automatically launch the League of Legends client alongside leagueRPC. This feature is designed to make your experience more seamless by integrating the game launch into the RPC setup.

By default, if `--launch-league` is specified without a path, the default installation path will be used:
```plaintext
C:\Riot Games\Riot Client\RiotClientServices.exe
```
This path is correct for the majority of installations. If your League of Legends client is installed in this location, you do not need to specify the path explicitly.

If you have installed League of Legends in a non-default location, you must provide the path to the RiotClientServices.exe file when using --launch-league. For example, if your game is installed on the D drive, you can start leagueRPC with the game like this:

```powershell
.\leagueRPC.exe --launch-league "D:\Riot Games\Riot Client\RiotClientServices.exe"
```
This command tells leagueRPC to launch the League of Legends client from the specified location.


### `--client-id <discord-app-id>` ✨
Specify a custom Discord client ID for the RPC connection. Defaults to `League of Legends`
**Example** `.\leagueRPC.exe --client-id 1230607224296968303` - This will show `League of Kittens`
- **League of Kittens**: `1230607224296968303`
Expand All @@ -190,7 +210,7 @@ Hide your League rank on Discord (SoloQ/Flex/TFT/Arena) By default, this will be
**Example**: `.\leagueRPC.exe --no-rank`


### `--show-emojis`
### `--show-emojis`
Do you want to show your Online/Away status with a emoji, then add this argument. By default, this will be hidden.

**Example**: `.\leagueRPC.exe --show-emojis`
Expand All @@ -217,7 +237,7 @@ Similar to `--wait-for-league`, specify the time (in seconds) to wait for Discor
Each of these arguments can be combined to tailor the Discord RPC to your preferences.

```powershell
.\leagueRPC.exe --client-id 1194034071588851783 --no-stats --no-rank --add-process CustomDiscord --wait-for-league -1 --wait-for-discord 15 --show-emojis
.\leagueRPC.exe --client-id 1194034071588851783 --launch-league --no-stats --no-rank --add-process CustomDiscord --wait-for-league -1 --wait-for-discord 15 --show-emojis
```

🛑 All of these arguments are optional. No extra argument is needed for the script to function properly. But in case you want to change something, you now can.
Expand All @@ -231,7 +251,7 @@ Each of these arguments can be combined to tailor the Discord RPC to your prefer
5. **Precise In-Game Time Tracking**: The in-game time is calculated with precision. Even if the script stops, when restarted, it will display the correct in-game time, ensuring continuous and accurate representation of your game status.
6. **Discord Reconnection Window**: While the script only works while Discord is up and running. There are instances where discord could crash. This program will attempt to reconnect to Discord's RPC even if the app is not running. For a period of time, and only exit when too much time has passed. Default is (50) seconds to restart/reconnect Discord.
7. **Disables Native League Presence**: This application is able to detect, and disable the built in rich presence coming from league, leaving only this one active as your main Presence on discord. This was a huge issue before since it's not easy to disable. And now all you have to do is just start this application before launching the league client, and you will be good to go.
8. **Launches League of legends for you**: To avoid forgetting to start this application before league all the time, you can let the application start league for you. Please read about the `--launch-league` argument to learn more.
## Tips for Running
Expand Down
49 changes: 35 additions & 14 deletions league_rpc/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,30 @@
import threading
import time

import nest_asyncio
import pypresence
import nest_asyncio # type:ignore
import pypresence # type:ignore

from league_rpc.champion import gather_ingame_information, get_skin_asset
from league_rpc.gametime import get_current_ingame_time
from league_rpc.kda import get_creepscore, get_gold, get_kda, get_level
from league_rpc.lcu_api.lcu_connector import start_connector
from league_rpc.processes.process import (
check_discord_process,
check_league_client_process,
player_state,
)
from league_rpc.reconnect import discord_reconnect_attempt
from league_rpc.utils.color import Color
from league_rpc.utils.const import (
ALL_GAME_DATA_URL,
CHAMPION_NAME_CONVERT_MAP,
DEFAULT_CLIENT_ID,
DEFAULT_LEAGUE_CLIENT_EXE_PATH,
DISCORD_PROCESS_NAMES,
LEAGUE_OF_LEGENDS_LOGO,
SMALL_TEXT,
)
from league_rpc.gametime import get_current_ingame_time
from league_rpc.kda import get_creepscore, get_gold, get_kda, get_level
from league_rpc.lcu_api.lcu_connector import start_connector
from league_rpc.utils.polling import wait_until_exists
from league_rpc.processes.process import (
check_discord_process,
check_league_client_process,
player_state,
)
from league_rpc.reconnect import discord_reconnect_attempt

# Discord Application: League of Linux

Expand All @@ -36,7 +37,7 @@ def main(cli_args: argparse.Namespace) -> None:
"""
############################################################
## Check Discord, RiotClient & LeagueClient processes ##
check_league_client_process(wait_for_league=cli_args.wait_for_league)
check_league_client_process(cli_args)

rpc = check_discord_process(
process_names=DISCORD_PROCESS_NAMES + cli_args.add_process,
Expand Down Expand Up @@ -105,7 +106,7 @@ def main(cli_args: argparse.Namespace) -> None:
skin_id=skin_id,
)
print(
f"{Color.green}Successfully gathered all data.{Color.yellow}\nUpdating Discord Presence now!{Color.reset}"
f"{Color.green}Successfully gathered all data. Updating your Presence now!{Color.reset}"
)
while player_state() == "InGame":
rpc.update( # type:ignore
Expand All @@ -132,7 +133,7 @@ def main(cli_args: argparse.Namespace) -> None:
skin_id=skin_id,
)
print(
f"{Color.green}Successfully gathered all data.{Color.yellow}\nUpdating Discord Presence now!{Color.reset}"
f"{Color.green}Successfully gathered all data. Updating your Presence now!{Color.reset}"
)
while player_state() == "InGame":
if not champ_name or not gamemode:
Expand Down Expand Up @@ -222,6 +223,12 @@ def main(cli_args: argparse.Namespace) -> None:
default=-1,
help="Time in seconds to wait for the Discord client to start. -1 for infinite waiting, Good when you want to start this script before you've had time to start Discord.",
)
action = parser.add_argument(
"--launch-league",
type=str,
default=DEFAULT_LEAGUE_CLIENT_EXE_PATH,
help=f"Path to the League of Legends client executable. Default path is: {DEFAULT_LEAGUE_CLIENT_EXE_PATH}",
)

args: argparse.Namespace = parser.parse_args()

Expand All @@ -244,6 +251,7 @@ def main(cli_args: argparse.Namespace) -> None:
print(
f"{Color.green}Argument {Color.blue}--add-process{Color.green} detected.. Will add {Color.blue}{args.add_process}{Color.green} to the list of Discord processes to look for.{Color.reset}"
)

if args.client_id != DEFAULT_CLIENT_ID:
print(
f"{Color.green}Argument {Color.blue}--client-id{Color.green} detected.. Will try to connect by using {Color.blue}({args.client_id}){Color.reset}"
Expand All @@ -257,4 +265,17 @@ def main(cli_args: argparse.Namespace) -> None:
f"{Color.green}Argument {Color.blue}--wait-for-discord{Color.green} detected.. {Color.blue}will wait for Discord to start before continuing{Color.reset}"
)

if args.launch_league:
if args.launch_league == DEFAULT_LEAGUE_CLIENT_EXE_PATH:
print(
f"{Color.green}Attempting to launch the League client at the default location{Color.reset} {Color.blue}{args.launch_league}{Color.reset}\n"
f"{Color.green}If league is already running, it will not launch a new instance.{Color.reset}\n"
f"{Color.orange}If the League client does not launch, please specify the path manually using: --launch-league <path>{Color.reset}\n"
)
else:
print(
f"{Color.green}Detected the {Color.blue}--launch-league{Color.green} argument with a custom path. Attempting to launch the League client, from: {Color.blue}{args.launch_league}{Color.reset}\n"
f"{Color.orange}If league is already running, it will not launch a new instance.{Color.reset}\n"
)

main(cli_args=args)
14 changes: 10 additions & 4 deletions league_rpc/__version__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""Set version number of package."""

__version__ = "v2.0.0"
__version__ = "v2.1.0"
import requests

RELEASES_PAGE = "https://github.com/Its-Haze/league-rpc/releases"


def get_version_from_github() -> str:
def get_version_from_github() -> str | None:
"""
Get the latest version of the software from the GitHub repository.
Expand All @@ -17,15 +17,21 @@ def get_version_from_github() -> str:
url="https://api.github.com/repos/its-haze/league-rpc/releases/latest",
timeout=15,
)
if response.status_code != 200:
# Probably due to rate limit.. should be handled better.
return None

return response.json()["tag_name"]


def check_latest_version() -> bool:
def check_latest_version() -> bool | None:
"""
Check if the current version of the software is the latest version available.
Returns:
bool: True if the current version is not the latest version, False otherwise.
"""
latest_version: str = get_version_from_github()
latest_version: str | None = get_version_from_github()
if latest_version is None:
return None
return latest_version > __version__
6 changes: 3 additions & 3 deletions league_rpc/champion.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import requests
import urllib3

from league_rpc.kda import get_gold, get_level
from league_rpc.latest_version import get_latest_version
from league_rpc.username import get_summoner_name
from league_rpc.utils.color import Color
from league_rpc.utils.const import (
ALL_GAME_DATA_URL,
Expand All @@ -12,10 +15,7 @@
DDRAGON_CHAMPION_DATA,
GAME_MODE_CONVERT_MAP,
)
from league_rpc.kda import get_gold, get_level
from league_rpc.latest_version import get_latest_version
from league_rpc.utils.polling import wait_until_exists
from league_rpc.username import get_summoner_name

urllib3.disable_warnings()

Expand Down
4 changes: 2 additions & 2 deletions league_rpc/disable_native_rpc/disable.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ def check_and_modify_json(file_path: str) -> None:

if modify_json_data(data=data):
print(
f"{Color.orange}Native league rpc found. Will disable it now.{Color.reset}"
f"\n{Color.orange}Native league rpc found. Will disable it now.{Color.reset}"
)
save_json_file(file_path=file_path, data=data)
print(
f"{Color.green}Successfully disabled League Native Rich Presence{Color.reset}"
f"{Color.green}Successfully disabled League Native Rich Presence{Color.reset}\n"
)

# For debugging purposes only.
Expand Down
2 changes: 1 addition & 1 deletion league_rpc/kda.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import urllib3
from requests import Response

from league_rpc.utils.polling import wait_until_exists
from league_rpc.username import get_summoner_name
from league_rpc.utils.polling import wait_until_exists

urllib3.disable_warnings()

Expand Down
11 changes: 7 additions & 4 deletions league_rpc/lcu_api/lcu_connector.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import time
from argparse import Namespace
from typing import Any, Optional

from aiohttp import ClientResponse
from lcu_driver.connection import Connection
from lcu_driver.events.responses import WebsocketEventResponse
from pypresence import Presence
from lcu_driver.connection import Connection # type:ignore
from lcu_driver.events.responses import WebsocketEventResponse # type:ignore
from pypresence import Presence # type:ignore

from league_rpc.utils.color import Color
from league_rpc.disable_native_rpc.disable import check_plugin_status, find_game_path
from league_rpc.lcu_api.base_data import gather_base_data
from league_rpc.models.client_data import ArenaStats, ClientData, RankedStats, TFTStats
Expand All @@ -19,6 +19,7 @@
from league_rpc.models.lcu.current_summoner import Summoner
from league_rpc.models.module_data import ModuleData
from league_rpc.models.rpc_updater import RPCUpdater
from league_rpc.utils.color import Color

module_data = ModuleData()
rpc_updater = RPCUpdater()
Expand All @@ -29,8 +30,10 @@
@module_data.connector.ready # type:ignore
async def connect(connection: Connection) -> None:
print(f"{Color.green}Successfully connected to the League Client API.{Color.reset}")
time.sleep(2) # Give the client some time to load

print(f"\n{Color.orange}Gathering base data.{Color.reset}")
time.sleep(2)
await gather_base_data(connection=connection, module_data=module_data)

print(f"{Color.green}Successfully gathered base data.{Color.reset}")
Expand Down
12 changes: 6 additions & 6 deletions league_rpc/models/rpc_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,13 @@
from dataclasses import dataclass
from threading import Timer

from pypresence import Presence
from pypresence import Presence # type:ignore

from league_rpc.lcu_api.lcu_connector import ModuleData
from league_rpc.models.client_data import ClientData
from league_rpc.models.lcu.current_chat_status import LolChatUser
from league_rpc.models.lcu.current_ranked_stats import ArenaStats, RankedStats, TFTStats
from league_rpc.models.lcu.gameflow_phase import GameFlowPhase
from league_rpc.utils.const import (
BASE_MAP_ICON_URL,
GAME_MODE_CONVERT_MAP,
Expand All @@ -25,11 +30,6 @@
RANKED_TYPE_MAPPER,
SMALL_TEXT,
)
from league_rpc.lcu_api.lcu_connector import ModuleData
from league_rpc.models.client_data import ClientData
from league_rpc.models.lcu.current_chat_status import LolChatUser
from league_rpc.models.lcu.current_ranked_stats import ArenaStats, RankedStats, TFTStats
from league_rpc.models.lcu.gameflow_phase import GameFlowPhase


# As some events are called multiple times, we should limit the amount of updates to the RPC.
Expand Down
38 changes: 25 additions & 13 deletions league_rpc/processes/process.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import sys
import time
from argparse import Namespace

import psutil
import pypresence
import pypresence # type:ignore

from league_rpc.utils.color import Color
from league_rpc.disable_native_rpc.disable import check_and_modify_json, find_game_path
from league_rpc.utils.color import Color
from league_rpc.utils.launch_league import launch_league_client


def processes_exists(process_names: list[str]) -> bool:
Expand All @@ -29,18 +31,28 @@ def process_exists(process_name: str) -> bool:
return False


def check_league_client_process(wait_for_league: int) -> None:
def check_league_client_process(cli_args: Namespace) -> None:
"""
Checks league client processes.
"""
league_processes: list[str] = ["LeagueClient.exe", "LeagueClientUx.exe"]

print(f"{Color.yellow}Checking if LeagueClient.exe is running...")
time.sleep(1)
if wait_for_league == -1:
print(
f"{Color.yellow}Will wait {Color.green}indefinitely{Color.yellow} for League to start... Remember, forever is a long time.. use {Color.green}CTRL + C{Color.yellow} if you would like to quit.{Color.reset}"
)

if cli_args.launch_league:
# launch league if it's not already running.
if not processes_exists(league_processes):
launch_league_client(cli_args)

if not processes_exists(process_names=league_processes):
# If league process is still not running, even after launching the client.
# Then something must have gone wrong.
# Do not exit app, but rather wait for user to open the correct game..
if cli_args.wait_for_league == -1:
print(
f"{Color.yellow}Will wait {Color.green}indefinitely{Color.yellow} for League to start... Remember, forever is a long time.. use {Color.green}CTRL + C{Color.yellow} if you would like to quit.{Color.reset}"
)

wait_time = 0
while True:
Expand All @@ -54,20 +66,20 @@ def check_league_client_process(wait_for_league: int) -> None:
print(
f"{Color.red} Did not find the game path for league.. Can't disable the native RPC.{Color.reset}"
)
if wait_for_league == -1:
if cli_args.wait_for_league == -1:
continue
elif wait_time >= wait_for_league:
elif wait_time >= cli_args.wait_for_league:
print(
f"{Color.red}League Client is not running! Exiting after waiting {wait_for_league} seconds.{Color.reset}"
f"{Color.red}League Client is not running! Exiting after waiting {cli_args.wait_for_league} seconds.{Color.reset}"
)
if not wait_for_league:
if not cli_args.wait_for_league:
print(
f"{Color.green}Want to add waiting time for League? Use --wait-for-league <seconds>. (-1 = infinite, or until CTRL + C)"
)
sys.exit()
else:
print(
f"{Color.yellow}Will wait for League to start. Time left: {wait_for_league - wait_time} seconds..."
f"{Color.yellow}Will wait for League to start. Time left: {cli_args.wait_for_league - wait_time} seconds..."
)
time.sleep(5)
wait_time += 5
Expand All @@ -84,7 +96,7 @@ def check_discord_process(
Checks if discord process is running.
Connects to Discord Rich Presence if it is found.
"""
print(f"{Color.yellow}Checking if Discord is running...{Color.reset}")
print(f"\n{Color.yellow}Checking if Discord is running...{Color.reset}")

look_for_processes = f"({Color.green}{', '.join(process_names)}{Color.blue})"

Expand Down
Loading

0 comments on commit be7a6fa

Please sign in to comment.