Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Streamlit secrets
.streamlit/secrets.toml

# Python
__pycache__/
*.py[cod]
*$py.class
*.so
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg

# Virtual environments
venv/
ENV/
env/

# IDEs
.vscode/
.idea/
*.swp
*.swo
*~

# OS
.DS_Store
Thumbs.db
73 changes: 69 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,71 @@
# Welcome to Streamlit!
# League of Legends Data Viewer

Edit `/streamlit_app.py` to customize this app to your heart's desire. :heart:
A Streamlit application for viewing League of Legends match history and champion mastery data using the Riot Games API.

If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
forums](https://discuss.streamlit.io).
## Features

- **Match History**: View the last 10 matches with detailed statistics
- Champion played
- KDA (Kills/Deaths/Assists)
- CS (Creep Score)
- Damage dealt to champions
- Game mode and duration
- Win/Loss indicator

- **Champion Mastery**: Display top 10 champions by mastery
- Champion level
- Mastery points

- **Multi-Region Support**: Supports all major LoL regions
- Japan (jp1)
- Korea (kr)
- North America (na1)
- Europe West (euw1)
- Europe Nordic & East (eun1)
- And more...

## Setup

### 1. Install Dependencies

```bash
pip install -r requirements.txt
```

### 2. Get Riot API Key

1. Visit [Riot Developer Portal](https://developer.riotgames.com/)
2. Sign in with your Riot account
3. Generate a Development API Key

### 3. Run the Application

```bash
streamlit run streamlit_app.py
```

## Usage

1. Open the application in your browser
2. Select your region from the sidebar
3. Enter your Riot API Key in the sidebar
4. Enter a summoner name
5. Click "Fetch Data"

## API Rate Limits

Development API keys have rate limits:
- 20 requests every 1 second
- 100 requests every 2 minutes

The app includes a small delay between requests to help avoid rate limiting.

## Note

- Make sure to select the correct region for the summoner you're searching
- API keys expire after 24 hours and need to be regenerated
- For production use, apply for a production API key from Riot

## License

This project is for educational purposes. League of Legends and Riot Games are trademarks or registered trademarks of Riot Games, Inc.
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
altair
pandas
streamlit
requests
274 changes: 236 additions & 38 deletions streamlit_app.py
Original file line number Diff line number Diff line change
@@ -1,40 +1,238 @@
import altair as alt
import numpy as np
import pandas as pd
import streamlit as st
import requests
import time
from typing import Optional, List, Dict

"""
# Welcome to Streamlit!

Edit `/streamlit_app.py` to customize this app to your heart's desire :heart:.
If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
forums](https://discuss.streamlit.io).

In the meantime, below is an example of what you can do with just a few lines of code:
"""

num_points = st.slider("Number of points in spiral", 1, 10000, 1100)
num_turns = st.slider("Number of turns in spiral", 1, 300, 31)

indices = np.linspace(0, 1, num_points)
theta = 2 * np.pi * num_turns * indices
radius = indices

x = radius * np.cos(theta)
y = radius * np.sin(theta)

df = pd.DataFrame({
"x": x,
"y": y,
"idx": indices,
"rand": np.random.randn(num_points),
})

st.altair_chart(alt.Chart(df, height=700, width=700)
.mark_point(filled=True)
.encode(
x=alt.X("x", axis=None),
y=alt.Y("y", axis=None),
color=alt.Color("idx", legend=None, scale=alt.Scale()),
size=alt.Size("rand", legend=None, scale=alt.Scale(range=[1, 150])),
))

class RiotAPI:
"""Riot Games API Client"""

def __init__(self, api_key: str, region: str = "jp1", routing: str = "asia"):
self.api_key = api_key
self.region = region # Platform routing (jp1, kr, na1, etc.)
self.routing = routing # Regional routing (asia, americas, europe, sea)
self.headers = {"X-Riot-Token": api_key}

def get_summoner_by_name(self, summoner_name: str) -> Optional[Dict]:
"""Get summoner information by summoner name"""
url = f"https://{self.region}.api.riotgames.com/lol/summoner/v4/summoners/by-name/{summoner_name}"
try:
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
return response.json()
else:
st.error(f"Error fetching summoner: {response.status_code} - {response.text}")
return None
except Exception as e:
st.error(f"Exception: {str(e)}")
return None

def get_champion_mastery(self, puuid: str, count: int = 10) -> Optional[List[Dict]]:
"""Get champion mastery for a summoner"""
url = f"https://{self.region}.api.riotgames.com/lol/champion-mastery/v4/champion-masteries/by-puuid/{puuid}/top"
try:
response = requests.get(url, headers=self.headers, params={"count": count})
if response.status_code == 200:
return response.json()
else:
st.error(f"Error fetching champion mastery: {response.status_code}")
return None
except Exception as e:
st.error(f"Exception: {str(e)}")
return None

def get_match_ids(self, puuid: str, count: int = 10) -> Optional[List[str]]:
"""Get match IDs for a summoner"""
url = f"https://{self.routing}.api.riotgames.com/lol/match/v5/matches/by-puuid/{puuid}/ids"
try:
response = requests.get(url, headers=self.headers, params={"count": count})
if response.status_code == 200:
return response.json()
else:
st.error(f"Error fetching match IDs: {response.status_code}")
return None
except Exception as e:
st.error(f"Exception: {str(e)}")
return None

def get_match_details(self, match_id: str) -> Optional[Dict]:
"""Get match details by match ID"""
url = f"https://{self.routing}.api.riotgames.com/lol/match/v5/matches/{match_id}"
try:
response = requests.get(url, headers=self.headers)
if response.status_code == 200:
return response.json()
else:
st.error(f"Error fetching match details: {response.status_code}")
return None
except Exception as e:
st.error(f"Exception: {str(e)}")
return None


def display_champion_mastery(mastery_data: List[Dict]):
"""Display champion mastery information"""
st.subheader("🏆 Champion Mastery Top 10")

if not mastery_data:
st.warning("No champion mastery data available")
return

for idx, champ in enumerate(mastery_data, 1):
col1, col2, col3, col4 = st.columns([1, 3, 2, 2])
with col1:
st.write(f"**#{idx}**")
with col2:
st.write(f"Champion ID: {champ['championId']}")
with col3:
st.write(f"Level: {champ['championLevel']}")
with col4:
st.write(f"Points: {champ['championPoints']:,}")


def display_match_history(match_data: List[Dict], summoner_puuid: str):
"""Display match history"""
st.subheader("📊 Recent Match History")

if not match_data:
st.warning("No match history available")
return

for match in match_data:
info = match.get('info', {})
participants = info.get('participants', [])

# Find the player's data in participants
player_data = None
for participant in participants:
if participant.get('puuid') == summoner_puuid:
player_data = participant
break

if not player_data:
continue

# Display match info
game_mode = info.get('gameMode', 'Unknown')
game_duration = info.get('gameDuration', 0) // 60 # Convert to minutes
win = player_data.get('win', False)

# Create expandable section for each match
with st.expander(f"{'✅ Victory' if win else '❌ Defeat'} - {game_mode} ({game_duration} min)"):
col1, col2, col3, col4 = st.columns(4)

with col1:
st.metric("Champion", player_data.get('championName', 'Unknown'))
with col2:
kills = player_data.get('kills', 0)
deaths = player_data.get('deaths', 0)
assists = player_data.get('assists', 0)
st.metric("KDA", f"{kills}/{deaths}/{assists}")
with col3:
cs = player_data.get('totalMinionsKilled', 0) + player_data.get('neutralMinionsKilled', 0)
st.metric("CS", cs)
with col4:
damage = player_data.get('totalDamageDealtToChampions', 0)
st.metric("Damage", f"{damage:,}")


# Main App
st.title("⚔️ League of Legends Data Viewer")
st.write("View match history and champion mastery for any summoner")

# Sidebar for configuration
with st.sidebar:
st.header("Settings")

# Region selection
region = st.selectbox(
"Region",
["jp1", "kr", "na1", "euw1", "eun1", "br1", "la1", "la2", "oc1", "ru", "tr1"],
index=0
)

# Routing mapping
routing_map = {
"jp1": "asia", "kr": "asia",
"na1": "americas", "br1": "americas", "la1": "americas", "la2": "americas",
"euw1": "europe", "eun1": "europe", "ru": "europe", "tr1": "europe",
"oc1": "sea"
}
routing = routing_map.get(region, "asia")

# API Key input
api_key_input = st.text_input("Riot API Key", type="password", placeholder="RGAPI-...")

st.info("Get your API key from [Riot Developer Portal](https://developer.riotgames.com/)")

# Main content
summoner_name = st.text_input("Enter Summoner Name", placeholder="Hide on bush")

if st.button("Fetch Data") and summoner_name and api_key_input:
api = RiotAPI(api_key_input, region=region, routing=routing)

with st.spinner("Fetching summoner data..."):
summoner = api.get_summoner_by_name(summoner_name)

if summoner:
st.success(f"Found summoner: {summoner['name']}")

# Display basic info
col1, col2, col3 = st.columns(3)
with col1:
st.metric("Summoner Level", summoner['summonerLevel'])
with col2:
st.metric("Profile Icon", summoner['profileIconId'])
with col3:
st.write(f"**PUUID:** {summoner['puuid'][:8]}...")

st.divider()

# Fetch and display champion mastery
with st.spinner("Fetching champion mastery..."):
mastery_data = api.get_champion_mastery(summoner['puuid'], count=10)

if mastery_data:
display_champion_mastery(mastery_data)

st.divider()

# Fetch and display match history
with st.spinner("Fetching match history..."):
match_ids = api.get_match_ids(summoner['puuid'], count=10)

if match_ids:
matches = []
progress_bar = st.progress(0)
for idx, match_id in enumerate(match_ids):
match_details = api.get_match_details(match_id)
if match_details:
matches.append(match_details)
progress_bar.progress((idx + 1) / len(match_ids))
time.sleep(0.1) # Rate limiting

progress_bar.empty()
display_match_history(matches, summoner['puuid'])

elif summoner_name and not api_key_input:
st.warning("⚠️ Please enter your Riot API Key in the sidebar")

# Instructions
with st.expander("ℹ️ How to use"):
st.markdown("""
### Steps:
1. Get your Riot API Key from [Riot Developer Portal](https://developer.riotgames.com/)
2. Enter your API key in the sidebar
3. Select your region
4. Enter a summoner name
5. Click "Fetch Data"

### Features:
- 📊 View recent match history (last 10 games)
- 🏆 View top 10 champion masteries
- 📈 Detailed match statistics (KDA, CS, damage, etc.)

### Note:
- Development API keys are rate-limited
- Make sure to select the correct region for the summoner
""")