mirror of
https://github.com/Rainyy21/lol_discordbot
synced 2026-10-10 23:00:32 -04:00
fix some the signin and check recent but need to fix profile
This commit is contained in:
Binary file not shown.
@@ -150,3 +150,117 @@ Traceback (most recent call last):
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 847, in _transform_arguments
|
||||
raise CommandSignatureMismatch(self) from None
|
||||
discord.app_commands.errors.CommandSignatureMismatch: The signature for command 'login' is different from the one provided by Discord. This can happen because either your code is out of date or you have not synced the commands with Discord, causing the mismatch in data. It is recommended to sync the command tree to fix this issue.
|
||||
2026-04-22 03:44:35,358 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2026-04-22 03:44:35,358 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||
2026-04-22 03:44:35,359 [INFO] discord.client: logging in using static token
|
||||
2026-04-22 03:44:35,751 [INFO] bot: ✅ Loaded extension: commands.login
|
||||
2026-04-22 03:44:35,751 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||
2026-04-22 03:44:35,752 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||
2026-04-22 03:44:35,884 [INFO] bot: 🔄 Slash commands synced to guild 1055571472611033160
|
||||
2026-04-22 03:44:36,069 [INFO] bot: 🔄 Global slash commands synced
|
||||
2026-04-22 03:44:36,466 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: b5af520b7608ba76313f4e32f6045ed4).
|
||||
2026-04-22 03:44:38,469 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||
2026-04-22 03:44:38,470 [INFO] bot: Guilds : 1
|
||||
2026-04-22 03:44:38,470 [INFO] bot: Ping : 47ms
|
||||
2026-04-23 00:15:51,686 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2026-04-23 00:15:51,688 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||
2026-04-23 00:15:51,690 [INFO] discord.client: logging in using static token
|
||||
2026-04-23 00:15:52,218 [INFO] bot: ✅ Loaded extension: commands.login
|
||||
2026-04-23 00:15:52,220 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||
2026-04-23 00:15:52,223 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||
2026-04-23 00:15:52,333 [INFO] bot: 🔄 Slash commands synced to guild 1055571472611033160
|
||||
2026-04-23 00:15:52,674 [INFO] bot: 🔄 Global slash commands synced
|
||||
2026-04-23 00:15:53,798 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: c95d0a5504b0553dfd47d07f17ad9d72).
|
||||
2026-04-23 00:15:55,804 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||
2026-04-23 00:15:55,807 [INFO] bot: Guilds : 1
|
||||
2026-04-23 00:15:55,807 [INFO] bot: Ping : 39ms
|
||||
2026-04-23 00:23:23,262 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2026-04-23 00:23:23,263 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||
2026-04-23 00:23:23,264 [INFO] discord.client: logging in using static token
|
||||
2026-04-23 00:23:23,782 [INFO] bot: ✅ Loaded extension: commands.login
|
||||
2026-04-23 00:23:23,784 [ERROR] bot: ❌ Failed to load commands.profile: Extension 'commands.profile' raised an error: NameError: name 'aiohttp' is not defined
|
||||
2026-04-23 00:23:23,788 [ERROR] bot: ❌ Failed to load commands.recent: Extension 'commands.recent' raised an error: NameError: name 'aiohttp' is not defined
|
||||
2026-04-23 00:23:23,926 [INFO] bot: 🔄 Slash commands synced to guild 1055571472611033160
|
||||
2026-04-23 00:23:24,080 [INFO] bot: 🔄 Global slash commands synced
|
||||
2026-04-23 00:23:24,693 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: 1fe2f819a2266ec9c68c874572e3ca7c).
|
||||
2026-04-23 00:23:26,699 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||
2026-04-23 00:23:26,699 [INFO] bot: Guilds : 1
|
||||
2026-04-23 00:23:26,700 [INFO] bot: Ping : 42ms
|
||||
2026-04-23 00:25:58,295 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2026-04-23 00:25:58,295 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||
2026-04-23 00:25:58,296 [INFO] discord.client: logging in using static token
|
||||
2026-04-23 00:25:58,617 [INFO] bot: ✅ Loaded extension: commands.login
|
||||
2026-04-23 00:25:58,619 [ERROR] bot: ❌ Failed to load commands.profile: Extension 'commands.profile' raised an error: NameError: name 'aiohttp' is not defined
|
||||
2026-04-23 00:25:58,622 [ERROR] bot: ❌ Failed to load commands.recent: Extension 'commands.recent' raised an error: NameError: name 'aiohttp' is not defined
|
||||
2026-04-23 00:25:58,729 [INFO] bot: 🔄 Slash commands synced to guild 1055571472611033160
|
||||
2026-04-23 00:25:58,910 [INFO] bot: 🔄 Global slash commands synced
|
||||
2026-04-23 00:25:59,706 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: 6be4de7a798203f744639beaeeb3bc77).
|
||||
2026-04-23 00:26:01,749 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||
2026-04-23 00:26:01,760 [INFO] bot: Guilds : 1
|
||||
2026-04-23 00:26:01,761 [INFO] bot: Ping : 42ms
|
||||
2026-04-23 00:29:04,989 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2026-04-23 00:29:04,989 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||
2026-04-23 00:29:04,990 [INFO] discord.client: logging in using static token
|
||||
2026-04-23 00:29:05,366 [INFO] bot: ✅ Loaded extension: commands.login
|
||||
2026-04-23 00:29:05,370 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||
2026-04-23 00:29:05,373 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||
2026-04-23 00:29:05,663 [INFO] bot: 🔄 Slash commands synced to guild 1055571472611033160
|
||||
2026-04-23 00:29:05,860 [INFO] bot: 🔄 Global slash commands synced
|
||||
2026-04-23 00:29:06,727 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: 1caf69eb498bb76c6a22762831c789e3).
|
||||
2026-04-23 00:29:08,757 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||
2026-04-23 00:29:08,761 [INFO] bot: Guilds : 1
|
||||
2026-04-23 00:29:08,762 [INFO] bot: Ping : 43ms
|
||||
2026-04-23 00:29:22,375 [ERROR] discord.app_commands.tree: Ignoring exception in command 'profile'
|
||||
Traceback (most recent call last):
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 858, in _do_call
|
||||
return await self._callback(self.binding, interaction, **params) # type: ignore
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/simonzheng/Documents/vscode/lolBot/commands/profile.py", line 41, in profile
|
||||
summoner_id = summoner["id"]
|
||||
~~~~~~~~^^^^^^
|
||||
KeyError: 'id'
|
||||
|
||||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1302, in _call
|
||||
await command._invoke_with_namespace(interaction, namespace)
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 884, in _invoke_with_namespace
|
||||
return await self._do_call(interaction, transformed_values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 877, in _do_call
|
||||
raise CommandInvokeError(self, e) from e
|
||||
discord.app_commands.errors.CommandInvokeError: Command 'profile' raised an exception: KeyError: 'id'
|
||||
2026-04-23 00:30:43,277 [WARNING] discord.client: PyNaCl is not installed, voice will NOT be supported
|
||||
2026-04-23 00:30:43,278 [WARNING] discord.client: davey is not installed, voice will NOT be supported
|
||||
2026-04-23 00:30:43,279 [INFO] discord.client: logging in using static token
|
||||
2026-04-23 00:30:44,221 [INFO] bot: ✅ Loaded extension: commands.login
|
||||
2026-04-23 00:30:44,227 [INFO] bot: ✅ Loaded extension: commands.profile
|
||||
2026-04-23 00:30:44,231 [INFO] bot: ✅ Loaded extension: commands.recent
|
||||
2026-04-23 00:30:44,745 [INFO] bot: 🔄 Slash commands synced to guild 1055571472611033160
|
||||
2026-04-23 00:30:44,922 [INFO] bot: 🔄 Global slash commands synced
|
||||
2026-04-23 00:30:45,429 [INFO] discord.gateway: Shard ID None has connected to Gateway (Session ID: 07f28f18598c25062c3300ff0d0bf20f).
|
||||
2026-04-23 00:30:47,479 [INFO] bot: ✅ Logged in as league of legend bot#3877 (ID: 1494467149186465862)
|
||||
2026-04-23 00:30:47,481 [INFO] bot: Guilds : 1
|
||||
2026-04-23 00:30:47,481 [INFO] bot: Ping : 50ms
|
||||
2026-04-23 00:31:43,436 [ERROR] discord.app_commands.tree: Ignoring exception in command 'profile'
|
||||
Traceback (most recent call last):
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 858, in _do_call
|
||||
return await self._callback(self.binding, interaction, **params) # type: ignore
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Users/simonzheng/Documents/vscode/lolBot/commands/profile.py", line 41, in profile
|
||||
summoner_id = summoner["id"]
|
||||
~~~~~~~~^^^^^^
|
||||
KeyError: 'id'
|
||||
|
||||
The above exception was the direct cause of the following exception:
|
||||
|
||||
Traceback (most recent call last):
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/tree.py", line 1302, in _call
|
||||
await command._invoke_with_namespace(interaction, namespace)
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 884, in _invoke_with_namespace
|
||||
return await self._do_call(interaction, transformed_values)
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/Library/Frameworks/Python.framework/Versions/3.13/lib/python3.13/site-packages/discord/app_commands/commands.py", line 877, in _do_call
|
||||
raise CommandInvokeError(self, e) from e
|
||||
discord.app_commands.errors.CommandInvokeError: Command 'profile' raised an exception: KeyError: 'id'
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+23
-26
@@ -1,11 +1,9 @@
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
import aiohttp
|
||||
import os
|
||||
from database.db import save_user
|
||||
|
||||
RIOT_API_KEY = os.getenv("LEAGUEAPI")
|
||||
from services.riot_api import get_account
|
||||
|
||||
class LoginCog(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
@@ -13,7 +11,7 @@ class LoginCog(commands.Cog):
|
||||
|
||||
async def _handle_login(self, interaction: discord.Interaction, summoner: str):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
|
||||
|
||||
if "#" not in summoner:
|
||||
await interaction.followup.send("❌ Use the format `Name#TAG`", ephemeral=True)
|
||||
return
|
||||
@@ -26,41 +24,40 @@ class LoginCog(commands.Cog):
|
||||
|
||||
discord_id = str(interaction.user.id)
|
||||
|
||||
url = (
|
||||
f"https://americas.api.riotgames.com/riot/account/v1/accounts"
|
||||
f"/by-riot-id/{game_name}/{tag_line}"
|
||||
)
|
||||
headers = {"X-Riot-Token": RIOT_API_KEY}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
if resp.status == 404:
|
||||
await interaction.followup.send("❌ Summoner not found. Check your Riot ID.", ephemeral=True)
|
||||
return
|
||||
if resp.status != 200:
|
||||
await interaction.followup.send(f"❌ Riot API error ({resp.status}). Try again later.", ephemeral=True)
|
||||
return
|
||||
# Use the service instead of direct API call
|
||||
data = await get_account(game_name, tag_line)
|
||||
|
||||
data = await resp.json()
|
||||
puuid = data["puuid"]
|
||||
if data is None:
|
||||
await interaction.followup.send("❌ Summoner not found. Check your Riot ID.", ephemeral=True)
|
||||
return
|
||||
|
||||
if isinstance(data, dict) and "error" in data:
|
||||
if data["error"] == 401:
|
||||
await interaction.followup.send(
|
||||
"❌ Riot API error (401): Unauthorized. "
|
||||
"This usually means the bot's API key has expired. "
|
||||
"Please notify the bot owner to refresh it at developer.riotgames.com.",
|
||||
ephemeral=True
|
||||
)
|
||||
else:
|
||||
await interaction.followup.send(
|
||||
f"❌ Riot API error ({data['error']}). Try again later.",
|
||||
ephemeral=True
|
||||
)
|
||||
return
|
||||
|
||||
puuid = data["puuid"]
|
||||
save_user(discord_id, puuid, game_name, tag_line)
|
||||
|
||||
await interaction.followup.send(
|
||||
f"✅ Linked **{game_name}#{tag_line}** to your Discord account!",
|
||||
ephemeral=True
|
||||
)
|
||||
|
||||
@app_commands.command(name="login", description="Link your Riot account")
|
||||
@app_commands.describe(summoner="Your Riot ID (e.g. Name#TAG)")
|
||||
async def login(self, interaction: discord.Interaction, summoner: str):
|
||||
await self._handle_login(interaction, summoner)
|
||||
|
||||
@app_commands.command(name="signin", description="Link your Riot account")
|
||||
@app_commands.describe(summoner="Your Riot ID (e.g. Name#TAG)")
|
||||
async def signin(self, interaction: discord.Interaction, summoner: str):
|
||||
await self._handle_login(interaction, summoner)
|
||||
|
||||
|
||||
async def setup(bot):
|
||||
await bot.add_cog(LoginCog(bot))
|
||||
|
||||
+32
-32
@@ -1,13 +1,10 @@
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
import aiohttp
|
||||
import os
|
||||
|
||||
from database.db import get_user
|
||||
|
||||
RIOT_API_KEY = os.getenv("LEAGUEAPI")
|
||||
REGION = "na1"
|
||||
from services.riot_api import get_summoner, get_rank
|
||||
|
||||
class ProfileCog(commands.Cog):
|
||||
def __init__(self, bot):
|
||||
@@ -29,28 +26,38 @@ class ProfileCog(commands.Cog):
|
||||
return
|
||||
|
||||
_, puuid, game_name, tag_line = user
|
||||
headers = {"X-Riot-Token": RIOT_API_KEY}
|
||||
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# 1. Get summoner data (level) via PUUID
|
||||
summoner = await fetch(
|
||||
session,
|
||||
f"https://{REGION}.api.riotgames.com/lol/summoner/v4/summoners/by-puuid/{puuid}",
|
||||
headers
|
||||
)
|
||||
if not summoner:
|
||||
await interaction.followup.send("❌ Could not fetch summoner data.")
|
||||
return
|
||||
# 1. Get summoner data (level) via PUUID
|
||||
summoner = await get_summoner(puuid)
|
||||
|
||||
if not summoner:
|
||||
await interaction.followup.send("❌ Could not fetch summoner data (Summoner not found).")
|
||||
return
|
||||
|
||||
if isinstance(summoner, dict) and "error" in summoner:
|
||||
if summoner["error"] == 401:
|
||||
await interaction.followup.send("❌ Riot API error (401): Unauthorized. API Key might be expired.")
|
||||
else:
|
||||
await interaction.followup.send(f"❌ Riot API error ({summoner['error']}).")
|
||||
return
|
||||
|
||||
summoner_id = summoner["id"]
|
||||
level = summoner["summonerLevel"]
|
||||
# Ensure 'id' exists before accessing it
|
||||
if "id" not in summoner:
|
||||
await interaction.followup.send("❌ Unexpected data format from Riot API.")
|
||||
return
|
||||
|
||||
summoner_id = summoner["id"]
|
||||
level = summoner.get("summonerLevel", "N/A")
|
||||
|
||||
# 2. Get rank & LP (League-v4)
|
||||
leagues = await get_rank(summoner_id)
|
||||
|
||||
if leagues is None:
|
||||
leagues = []
|
||||
elif isinstance(leagues, dict) and "error" in leagues:
|
||||
await interaction.followup.send(f"❌ Riot API error ({leagues['error']}).")
|
||||
return
|
||||
|
||||
# 2. Get rank & LP (League-v4)
|
||||
leagues = await fetch(
|
||||
session,
|
||||
f"https://{REGION}.api.riotgames.com/lol/league/v4/entries/by-summoner/{summoner_id}",
|
||||
headers
|
||||
)
|
||||
# Parse ranked solo queue data
|
||||
rank_info = get_solo_rank(leagues)
|
||||
|
||||
@@ -81,16 +88,9 @@ class ProfileCog(commands.Cog):
|
||||
|
||||
await interaction.followup.send(embed=embed)
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
#try to get the information
|
||||
async def fetch(session:aiohttp.ClientSession, url: str, headers: dict):
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
if resp.status != 200:
|
||||
return None
|
||||
return await resp.json()
|
||||
|
||||
def get_solo_rank(leagues: list) -> dict:
|
||||
def get_solo_rank(leagues) -> dict:
|
||||
"""Extract solo queue entry from league data."""
|
||||
if not leagues:
|
||||
if not isinstance(leagues, list) or not leagues:
|
||||
return {}
|
||||
for entry in leagues:
|
||||
if entry.get("queueType") == "RANKED_SOLO_5x5":
|
||||
|
||||
+27
-46
@@ -1,27 +1,25 @@
|
||||
import discord
|
||||
from discord import app_commands
|
||||
from discord.ext import commands
|
||||
import aiohttp
|
||||
import os
|
||||
import asyncio
|
||||
from database.db import get_user
|
||||
from services.riot_api import get_match_ids, get_match, get_latest_patch
|
||||
|
||||
RIOT_API_KEY = os.getenv("LEAGUEAPI")
|
||||
REGION = "na1"
|
||||
CLUSTER = "americas"
|
||||
|
||||
CLUSTER_MAP = {
|
||||
"na1": "americas", "br1": "americas", "la1": "americas", "la2": "americas",
|
||||
"euw1": "europe", "eun1": "europe", "tr1": "europe", "ru": "europe",
|
||||
"kr": "asia", "jp1": "asia",
|
||||
}
|
||||
class RecentCog(commands.Cog):
|
||||
def __init__(self, bot) -> None:
|
||||
self.bot = bot
|
||||
self.patch = "14.8.1"
|
||||
|
||||
async def _update_patch(self):
|
||||
new_patch = await get_latest_patch()
|
||||
if new_patch:
|
||||
self.patch = new_patch
|
||||
|
||||
@app_commands.command(name = "recent", description="Show your last N matches")
|
||||
@app_commands.describe(count="Number of matches to show (1–10, default 5)")
|
||||
async def recent(self , interaction: discord.Interaction, count: int = 5):
|
||||
await interaction.response.defer(ephemeral=False)
|
||||
await self._update_patch()
|
||||
|
||||
count = max(1, min(count, 10)) # clamp between 1 and 10
|
||||
discord_id = str(interaction.user.id)
|
||||
@@ -36,32 +34,28 @@ class RecentCog(commands.Cog):
|
||||
|
||||
#get user
|
||||
_, puuid, game_name, tag_line = user
|
||||
cluster = CLUSTER_MAP.get(REGION, "americas")
|
||||
headers = {"X-Riot-Token": RIOT_API_KEY}
|
||||
|
||||
#get user data
|
||||
async with aiohttp.ClientSession() as session:
|
||||
# 1. Fetch match ID list
|
||||
match_ids = await fetch(
|
||||
session,
|
||||
f"https://{cluster}.api.riotgames.com/lol/match/v5/matches/by-puuid/{puuid}/ids?count={count}",
|
||||
headers
|
||||
)
|
||||
if not match_ids:
|
||||
await interaction.followup.send("❌ Could not fetch match history.")
|
||||
return
|
||||
# 1. Fetch match ID list
|
||||
match_ids = await get_match_ids(puuid, count=count)
|
||||
|
||||
if match_ids is None:
|
||||
await interaction.followup.send("❌ Could not fetch match history.")
|
||||
return
|
||||
|
||||
# 2. Fetch each match in parallel
|
||||
match_data = await fetch_all(session, [
|
||||
f"https://{cluster}.api.riotgames.com/lol/match/v5/matches/{mid}"
|
||||
for mid in match_ids
|
||||
], headers)
|
||||
if isinstance(match_ids, dict) and "error" in match_ids:
|
||||
await interaction.followup.send(f"❌ Riot API error ({match_ids['error']}).")
|
||||
return
|
||||
|
||||
# 2. Fetch each match in parallel (get_match handles caching internally)
|
||||
match_data = await asyncio.gather(*[get_match(mid) for mid in match_ids])
|
||||
|
||||
embeds = []
|
||||
for match in match_data:
|
||||
if match:
|
||||
embed = build_match_embed(match , puuid, game_name,tag_line)
|
||||
if match and isinstance(match, dict) and "error" not in match:
|
||||
embed = build_match_embed(match , puuid, game_name, tag_line, self.patch)
|
||||
if embed:
|
||||
embeds.append(embed)
|
||||
|
||||
if not embeds:
|
||||
await interaction.followup.send("❌ No recent matches found.")
|
||||
return
|
||||
@@ -78,19 +72,6 @@ class RecentCog(commands.Cog):
|
||||
|
||||
# ── Helpers ────────────────────────────────────────────────────────────────────
|
||||
|
||||
async def fetch(session: aiohttp.ClientSession, url: str, headers: dict):
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
if resp.status != 200:
|
||||
return None
|
||||
return await resp.json()
|
||||
|
||||
|
||||
async def fetch_all(session: aiohttp.ClientSession, urls: list, headers: dict):
|
||||
"""Fetch multiple URLs concurrently."""
|
||||
import asyncio
|
||||
return await asyncio.gather(*[fetch(session, url, headers) for url in urls])
|
||||
|
||||
|
||||
def get_player(match: dict, puuid: str) -> dict:
|
||||
"""Find this player's participant data within the match."""
|
||||
participants = match["info"]["participants"]
|
||||
@@ -118,7 +99,7 @@ def queue_name(queue_id: int) -> str:
|
||||
return queues.get(queue_id, "Other")
|
||||
|
||||
|
||||
def build_match_embed(match: dict, puuid: str, game_name: str, tag_line: str):
|
||||
def build_match_embed(match: dict, puuid: str, game_name: str, tag_line: str, patch: str):
|
||||
player = get_player(match, puuid)
|
||||
if not player:
|
||||
return None
|
||||
@@ -145,7 +126,7 @@ def build_match_embed(match: dict, puuid: str, game_name: str, tag_line: str):
|
||||
embed.add_field(name="🌾 CS", value=f"{cs} ({cs_per_min}/min)", inline=True)
|
||||
embed.add_field(name="👤 Player", value=f"{game_name}#{tag_line}", inline=True)
|
||||
embed.set_thumbnail(
|
||||
url=f"https://ddragon.leagueoflegends.com/cdn/14.8.1/img/champion/{champion}.png"
|
||||
url=f"https://ddragon.leagueoflegends.com/cdn/{patch}/img/champion/{champion}.png"
|
||||
)
|
||||
|
||||
return embed
|
||||
|
||||
Binary file not shown.
@@ -11,6 +11,14 @@ cursor.execute("""
|
||||
tag_line TEXT
|
||||
)
|
||||
""")
|
||||
|
||||
cursor.execute("""
|
||||
CREATE TABLE IF NOT EXISTS matches(
|
||||
match_id TEXT PRIMARY KEY,
|
||||
data TEXT NOT NULL,
|
||||
timestamp DATETIME DEFAULT CURRENT_TIMESTAMP
|
||||
)
|
||||
""")
|
||||
conn.commit()
|
||||
|
||||
|
||||
@@ -32,3 +40,17 @@ def save_user(discord_id: str, puuid: str, game_name: str, tag_line: str):
|
||||
def get_user(discord_id: str):
|
||||
cursor.execute("SELECT * FROM users WHERE discord_id = ?", (discord_id,))
|
||||
return cursor.fetchone()
|
||||
|
||||
|
||||
def save_match(match_id: str, data: str):
|
||||
cursor.execute(
|
||||
"INSERT OR REPLACE INTO matches(match_id, data) VALUES (?, ?)",
|
||||
(match_id, data),
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
|
||||
def get_match(match_id: str):
|
||||
cursor.execute("SELECT data FROM matches WHERE match_id = ?", (match_id,))
|
||||
row = cursor.fetchone()
|
||||
return row[0] if row else None
|
||||
|
||||
Binary file not shown.
+15
-5
@@ -3,7 +3,9 @@ import asyncio
|
||||
import os
|
||||
import json
|
||||
from dotenv import load_dotenv
|
||||
from db import save_match, get_match as get_cached_match
|
||||
from database.db import save_match, get_match as get_cached_match
|
||||
|
||||
load_dotenv()
|
||||
|
||||
RIOT_API_KEY = os.getenv("LEAGUEAPI")
|
||||
REGION = os.getenv("REGION", "na1")
|
||||
@@ -24,21 +26,29 @@ CLUSTER = CLUSTER_MAP.get(REGION, "americas")
|
||||
|
||||
|
||||
async def riot_get(url: str, retries: int = 3) -> dict | list | None:
|
||||
if not RIOT_API_KEY:
|
||||
print("❌ RIOT_API_KEY not found in environment")
|
||||
return {"error": 401, "message": "API Key missing"}
|
||||
|
||||
headers = {"X-Riot-Token": RIOT_API_KEY}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
for attempt in range(retries):
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
if resp.status == 200:
|
||||
return await resp.json()
|
||||
elif resp.status == 492:
|
||||
elif resp.status == 429:
|
||||
wait = int(resp.headers.get("Retry-After", 5))
|
||||
print(f"⚠️ Rate limited. Retrying in {wait}s...")
|
||||
await asyncio.sleep(wait)
|
||||
elif resp.status == 401:
|
||||
print(f"❌ 401 Unauthorized: RIOT_API_KEY is invalid or expired.")
|
||||
return {"error": 401, "message": "Unauthorized (Key expired/invalid)"}
|
||||
elif resp.status == 404:
|
||||
return None
|
||||
else:
|
||||
print(f"❌ Error {resp.status} (attempt {attempt + 1}): {url}")
|
||||
await asyncio.sleep(1)
|
||||
if attempt < retries - 1:
|
||||
await asyncio.sleep(1)
|
||||
|
||||
return None
|
||||
|
||||
@@ -80,9 +90,9 @@ async def get_match(match_id: str) -> dict | None:
|
||||
if cached:
|
||||
return json.loads(cached)
|
||||
data = await riot_get(
|
||||
f"https://{CLUSTER}.api.riotgames.com" f"/lol/match/v5/matches/{match_id}"
|
||||
f"https://{CLUSTER}.api.riotgames.com/lol/match/v5/matches/{match_id}"
|
||||
)
|
||||
if data:
|
||||
if data and isinstance(data, dict) and "error" not in data:
|
||||
save_match(match_id, json.dumps(data))
|
||||
return data
|
||||
|
||||
|
||||
Reference in New Issue
Block a user