A Python library & CLI for downloading, inspecting, and patching Riot Games files using RMAN manifests.
Getting Started · Python API · CLI · Examples
| Game | Keys |
|---|---|
| League of Legends | lol league |
| Teamfight Tactics | tft |
| VALORANT | val valorant |
| Legends of Runeterra | lor runeterra bacon |
| 2XKO | 2xko ko2 |
| Wild Rift | wildrift wr |
| Riot Client | rc riotclient |
- Manifest decoding — parse Riot's binary RMAN format via a pure-Python FlatBuffer reader, no external schema needed
- Multi-threaded downloads — parallel HTTP Range requests + zstd decompression, writing chunks directly to pre-allocated files
- Smart diffing — compare old vs. new manifests and download only what changed
- On-disk resume — verify existing files and skip chunks already fully written
- Version history — browse every past patch via the Morilli/riot-manifests community archive
- Glob extraction — pull specific files with pattern filters like
ShooterGame/Content/** - Language-aware — bitmask-based locale filtering; download just the voice packs you need
- Rich CLI — beautiful terminal output with live progress bars, tables, and panels
git clone https://github.com/Jo0x01/PyRiotDL.git
cd PyRiotDL
pip install .Requires Python 3.10+
Dependencies: requests · zstandard · xxhash · typer · rich · certifi
from pyriotdl import PyRiotDL
dl = PyRiotDL("lol", region="NA1")
dl = PyRiotDL("val", region="eu")
dl = PyRiotDL("tft", region="EUW1")
# Using a GameConfig directly
dl = PyRiotDL(PyRiotDL.VALORANT.copy_with(region="na"))Enable logging:
import logging
PyRiotDL.setup_logging(level=logging.INFO) # or logging.DEBUGDownload a full game from scratch.
progress = dl.install(
output_dir = "./LeagueOfLegends",
languages = ["en_US"], # see Language Filtering below
workers = 16, # parallel threads
retries = 3,
save_manifest = "./lol.manifest", # save for future updates
)Only downloads chunks that changed since the installed version.
progress = dl.update(
current = "./lol.manifest", # path or CDN URL
output_dir = "./LeagueOfLegends",
languages = ["en_US"],
save_manifest_path = "./lol.manifest", # overwrite with new version
)Checks what's on disk and re-downloads anything missing or incomplete.
progress = dl.repair(
output_dir = "./LeagueOfLegends",
manifest_src = "./lol.manifest", # omit to use latest from API
languages = ["en_US"],
workers = 8,
)result = dl.diff(old="v1.manifest", new="v2.manifest")
print(f"Added {len(result.added):>5} files")
print(f"Removed {len(result.removed):>5} files")
print(f"Modified {len(result.modified):>5} files")
print(f"Same {len(result.unchanged):>5} files")
# Inspect individual changes
for f in result.modified:
print(f" ~ {f.path} ({f.size_delta:+} bytes)")Pull only the files you care about using glob patterns.
# Single pattern
progress = dl.extract(
output_dir = "./Assets",
pattern_filter = "ShooterGame/Content/Characters/**",
languages = ["en_US"],
)
# Multiple patterns
progress = dl.extract(
output_dir = "./Assets",
pattern_filter = ["**/*.pak", "**/*.uasset"],
)Browse past releases from the community archive.
versions = dl.history(
limit = 20,
include_hotfixes = False,
patch_filter = "15.04", # restrict to one patch cycle
)
for v in versions:
print(f"[{v.kind}] {v.version:<28} {v.manifest_id} {v.url}")Each ManifestVersion has:
| Property | Type | Description |
|---|---|---|
manifest_id |
str |
16-char hex ID |
version |
str |
Full version string e.g. 15.04.01.2352000 |
url |
str |
CDN manifest URL |
is_hotfix |
bool |
True if hotfix segment > 0 |
patch_number |
str |
Short label e.g. "15.04" |
kind |
str |
"patch" or "hotfix" |
status = dl.check_for_update(current="./lol.manifest")
if status.has_update:
print(f"Update available: {status.current_id} → {status.latest_id}")
else:
print("Already up to date.")Get size info before committing to a download.
info = dl.calculate_download_size(
languages = ["en_US"],
game_dir = "./LeagueOfLegends",
old_manifest = "./lol.manifest",
)
print(f"Files: {info.total_files:,}")
print(f"To download: {info.compressed_to_dl / 1e9:.2f} GB")
print(f"Skipped: {info.chunks_unchanged:,} chunks (unchanged)")
print(f"On disk: {info.chunks_on_disk:,} chunks (already present)")for lang in dl.language_sizes():
print(f"{lang.name:<14} {lang.file_count:>5} files {lang.total_bytes / 1e9:.2f} GB")Inspect a manifest without downloading anything.
plan = dl.dump(
manifest = "./lol.manifest", # omit to fetch latest
languages = ["en_US"],
json_path = "plan.json",
txt_path = "summary.txt",
urls_path = "bundle_urls.txt",
)
print(f"{len(plan)} files in plan")| Value | What gets downloaded |
|---|---|
[] (default) |
Language-neutral base files only — no voice packs |
None |
Everything — all locales, largest possible download |
["en_US"] |
Base files + English voice/text |
["en_US", "ar_AE"] |
Base files + English + Arabic |
pyriotdl <command> [options]
| Command | Description |
|---|---|
games |
List every supported game and its key aliases |
regions <game> |
Show valid region codes for a game |
latest <game> |
Print the latest live manifest CDN URL |
history <game> |
Browse version history from the community archive |
check-update <game> <manifest> |
Check if an update is available |
info <manifest> |
Show metadata from a local or remote manifest |
lang-sizes <game> |
Per-language download size breakdown |
build <manifest> |
Parse a manifest and export JSON / TXT / URLs |
diff <old> <new> |
Compare two manifests |
download <game> |
Fresh install |
update <game> |
Incremental patch |
# List all supported games
pyriotdl games
# Valid regions for LoL
pyriotdl regions lol
# Latest VALORANT manifest URL
pyriotdl latest val --region eu
# Last 10 LoL patches, no hotfixes
pyriotdl history lol --region EUW1 --limit 10 --no-hotfixes
# Check if an update is available
pyriotdl check-update lol ./lol.manifest --region NA1
# Decode manifest metadata
pyriotdl info ./lol.manifest
# Language pack sizes
pyriotdl lang-sizes val --region eu
# Export file plan without downloading
pyriotdl build ./lol.manifest --game lol --lang en_US --json plan.json --urls urls.txt
# Compare two patch versions
pyriotdl diff v1.manifest v2.manifest --game lol --detail
# Download LoL (English, 16 threads)
pyriotdl download lol --output ./LoL --region EUW1 --lang en_US --workers 16
# Patch an existing install
pyriotdl update lol --current ./lol.manifest --output ./LoL --region EUW1Every command supports
--verbose/-vfor debug output and--helpfor full options.
Download VALORANT (English only)
from pyriotdl import PyRiotDL
dl = PyRiotDL("val", region="eu")
dl.install(output_dir="./VALORANT", languages=["en_US"], workers=16)Get a specific historical patch
from pyriotdl import PyRiotDL
from pyriotdl.builder import ManifestBuilder
dl = PyRiotDL("lol", region="EUW1")
versions = dl.history(patch_filter="15.04", include_hotfixes=False)
target = versions[0]
print(f"Patch {target}")Check download size before committing
from pyriotdl import PyRiotDL
dl = PyRiotDL("lol", region="EUW1")
info = dl.calculate_download_size(languages=["en_US"])
print(f"Install size: {info.total_size / 1e9:.1f} GB")
print(f"To download: {info.compressed_to_dl / 1e9:.1f} GB compressed")Extract only VALORANT character assets
from pyriotdl import PyRiotDL
dl = PyRiotDL("val", region="eu")
dl.extract(
output_dir = "./Characters",
pattern_filter = "ShooterGame/Content/Characters/**",
languages = ["en_US"],
workers = 8,
)Export full file list for datamining
from pyriotdl import PyRiotDL
dl = PyRiotDL("lol")
dl.dump(
languages = None, # all locales
json_path = "lol_all.json",
urls_path = "bundles.txt",
)- Morilli/ManifestDownloader — original C CLI tool
- moonshadow565/rman — C++ toolkit
- ev3nvy/rman-rs — Rust implementation
- Morilli/riot-manifests — community manifest archive (used by this project)