first commit
No files matched your search
@@ -0,0 +1,60 @@
|
|||||||
|
# Node
|
||||||
|
node_modules/
|
||||||
|
npm-debug.log*
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
.pnp/
|
||||||
|
.pnp.js
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
out/
|
||||||
|
coverage/
|
||||||
|
|
||||||
|
# pnpm (keep pnpm-lock.yaml)
|
||||||
|
pnpm-debug.log*
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
logs/
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Environment
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
.vscode/
|
||||||
|
.idea/
|
||||||
|
*.suo
|
||||||
|
*.ntvs*
|
||||||
|
*.njsproj
|
||||||
|
*.sln
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*$py.class
|
||||||
|
venv/
|
||||||
|
.venv/
|
||||||
|
env/
|
||||||
|
pip-wheel-metadata/
|
||||||
|
*.egg-info/
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.coverage
|
||||||
|
htmlcov/
|
||||||
|
|
||||||
|
# Secrets and keys
|
||||||
|
*.pem
|
||||||
|
*.key
|
||||||
|
*.crt
|
||||||
|
secrets.*
|
||||||
|
|
||||||
|
# OS files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
|
ehthumbs.db
|
||||||
|
|
||||||
|
# Misc caches
|
||||||
|
.cache/
|
||||||
|
.parcel-cache/
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
ALL EXCLUSIVE AND OG ITEMS THAT ARE SUPPOSED TO BE LABELED MYTHIC IN THE SKIN CHECK!
|
||||||
|
Season 1 exclusives
|
||||||
|
Season 2 Battle Pass exclusives
|
||||||
|
Promotional exclusives (Samsung, Nintendo, PlayStation, Xbox, Twitch Prime, Intel, NVIDIA, etc.)
|
||||||
|
Founder exclusives
|
||||||
|
Tournament exclusives
|
||||||
|
Creator/Search for Survivors exclusives
|
||||||
|
Limited-time challenge exclusives
|
||||||
|
|
||||||
|
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
|
||||||
|
|
||||||
|
OG Skins
|
||||||
|
Renegade Raider
|
||||||
|
Aerial Assault Trooper
|
||||||
|
Black Knight
|
||||||
|
Blue Squire
|
||||||
|
Royale Knight
|
||||||
|
Sparkle Specialist
|
||||||
|
The Reaper
|
||||||
|
Elite Agent
|
||||||
|
Omega (fully upgraded)
|
||||||
|
Purple Skull Trooper
|
||||||
|
Pink Ghoul Trooper
|
||||||
|
Exclusive Skins
|
||||||
|
Galaxy
|
||||||
|
IKONIK
|
||||||
|
Glow
|
||||||
|
Wonder
|
||||||
|
Honor Guard
|
||||||
|
Eon
|
||||||
|
Dark Vertex
|
||||||
|
Double Helix
|
||||||
|
Neo Versa
|
||||||
|
Royale Bomber
|
||||||
|
Wildcat
|
||||||
|
Stealth Reflex
|
||||||
|
Reflex (original)
|
||||||
|
Rogue Spider Knight
|
||||||
|
Huntmaster Saber
|
||||||
|
Surf Strider
|
||||||
|
Blue Team Leader
|
||||||
|
Blue Striker
|
||||||
|
Carbon Commando
|
||||||
|
Prodigy
|
||||||
|
Cloud Striker
|
||||||
|
Fixer
|
||||||
|
Point Patroller
|
||||||
|
Trailblazer
|
||||||
|
OG Pickaxes
|
||||||
|
Raider's Revenge
|
||||||
|
Aerial Assault One
|
||||||
|
AC/DC
|
||||||
|
Trusty No. 2
|
||||||
|
Party Animal
|
||||||
|
OG / Exclusive Emotes
|
||||||
|
Fresh
|
||||||
|
Rambunctious
|
||||||
|
Tidy
|
||||||
|
Floss
|
||||||
|
Take the L
|
||||||
|
Orange Justice
|
||||||
|
Ride the Pony
|
||||||
|
Pony Up
|
||||||
|
Scenario
|
||||||
|
Evasive Maneuvers
|
||||||
|
Widow's Pirouette
|
||||||
|
Hot Marat
|
||||||
|
Kiss the Cup
|
||||||
|
Rare Banners
|
||||||
|
Battle Bus Banner
|
||||||
|
Alpha Tester Banner
|
||||||
|
Founder's Banners
|
||||||
|
Frostnite 128 Banner
|
||||||
|
FNCS Champion Banners
|
||||||
|
World Cup Finalist Banners
|
||||||
|
Fall Skirmish Banner
|
||||||
|
Summer Skirmish Banner
|
||||||
|
Galaxy Banner
|
||||||
|
IKONIK Banner
|
||||||
|
Glow Banner
|
||||||
|
Wonder Banner
|
||||||
|
Honor Guard Banner
|
||||||
|
EON Banner
|
||||||
|
Dark Vertex Banner
|
||||||
|
Double Helix Banner
|
||||||
|
Neo Versa Banner
|
||||||
|
Wildcat Banner
|
||||||
|
Search for Survivors Creator Banners
|
||||||
|
PewDiePie Banner
|
||||||
|
VanossGaming Banner
|
||||||
|
Muselk Banner
|
||||||
|
Jesse Cox Banner
|
||||||
|
Dhalucard Banner
|
||||||
|
Folagor03 Banner
|
||||||
|
Ionix_TV Banner
|
||||||
|
JesusAVGN Banner
|
||||||
|
OrkPod Banner
|
||||||
|
Rare Emoticons
|
||||||
|
Founder Emoticons
|
||||||
|
Galaxy Emoticon
|
||||||
|
IKONIK Emoticon
|
||||||
|
Glow Emoticon
|
||||||
|
Wonder Emoticon
|
||||||
|
Honor Guard Emoticon
|
||||||
|
Twitch Prime Emoticons
|
||||||
|
Early Battle Pass Emoticons
|
||||||
@@ -0,0 +1,178 @@
|
|||||||
|
FORTNITE OG / EXCLUSIVE / PROMOTIONAL / STW / CREATOR BANNER MASTER LIST
|
||||||
|
|
||||||
|
======================== YOUTUBER / CREATOR BANNERS
|
||||||
|
======================== - PewDiePie Banner - VanossGaming Banner -
|
||||||
|
Muselk Banner - Jesse Cox Banner - Dhalucard Banner - Folagor03 Banner -
|
||||||
|
Ionix_TV Banner - JesusAVGN Banner - OrkPod Banner
|
||||||
|
|
||||||
|
======================== SAVE THE WORLD EXCLUSIVE BANNERS
|
||||||
|
======================== - Founder’s Banner - Ultimate Founder’s
|
||||||
|
Banner - Challenge the Horde Banner - Horde Bash Banner - Frostnite
|
||||||
|
Banner - Frostnite 128 Banner - Hit the Road Banner - Endurance Banner -
|
||||||
|
Mythic Storm King Banner - Survive the Storm Banner - Canny Valley
|
||||||
|
Endurance Banner - Plankerton Endurance Banner - Stonewood Endurance
|
||||||
|
Banner - Twine Peaks Endurance Banner
|
||||||
|
|
||||||
|
======================== OG SKINS ======================== - Renegade
|
||||||
|
Raider - Aerial Assault Trooper - Black Knight - Blue Squire - Royale
|
||||||
|
Knight - Sparkle Specialist - The Reaper - Elite Agent - Omega (Max
|
||||||
|
Lights) - Carbide (Max Lights) - Purple Skull Trooper - Pink Ghoul
|
||||||
|
Trooper
|
||||||
|
|
||||||
|
======================== EXCLUSIVE SKINS ======================== -
|
||||||
|
Galaxy - IKONIK - Glow - Honor Guard - Wonder - EON - Dark Vertex -
|
||||||
|
Double Helix - Neo Versa - Royale Bomber - Wildcat - Reflex - Stealth
|
||||||
|
Reflex - Rogue Spider Knight - Huntmaster Saber - Blue Team Leader -
|
||||||
|
Blue Striker - Carbon Commando - Prodigy - Cloud Striker - Fixer - Point
|
||||||
|
Patroller - Trailblazer - Havoc - Rose Team Leader - Warpaint
|
||||||
|
|
||||||
|
======================== EXCLUSIVE PICKAXES ======================== -
|
||||||
|
Raider’s Revenge - Aerial Assault One - Merry Mint Axe - Stellar Axe -
|
||||||
|
Resonator - Razor Edge - Pinpoint - Angular Axe - Tenderizer - AC/DC -
|
||||||
|
Trusty No. 2 - Party Animal
|
||||||
|
|
||||||
|
======================== EXCLUSIVE EMOTES ======================== -
|
||||||
|
Scenario - Levitate - Pony Up - Ride The Pony - Fresh - Rambunctious -
|
||||||
|
Tidy - Floss - Take The L - Orange Justice - Evasive Maneuvers - Widow’s
|
||||||
|
Pirouette - Hot Marat - Kiss The Cup
|
||||||
|
|
||||||
|
======================== SAMSUNG GALAXY BUNDLE
|
||||||
|
======================== - Galaxy - Galactic Disc - Stellar Axe -
|
||||||
|
Discovery
|
||||||
|
|
||||||
|
======================== IKONIK BUNDLE ======================== -
|
||||||
|
IKONIK - Scenario
|
||||||
|
|
||||||
|
======================== GLOW BUNDLE ======================== - Glow -
|
||||||
|
Levitate
|
||||||
|
|
||||||
|
======================== EON BUNDLE ======================== - EON -
|
||||||
|
Resonator - Aurora
|
||||||
|
|
||||||
|
======================== DARK VERTEX BUNDLE ======================== -
|
||||||
|
Dark Vertex - Dark Deflector - Razor Edge - Dark Forerunner
|
||||||
|
|
||||||
|
======================== DOUBLE HELIX BUNDLE ======================== -
|
||||||
|
Double Helix - Telemetry - Pinpoint - Rotor
|
||||||
|
|
||||||
|
======================== NEO VERSA BUNDLE ======================== - Neo
|
||||||
|
Versa - Neo Phrenzy
|
||||||
|
|
||||||
|
======================== ROYALE BOMBER BUNDLE ======================== -
|
||||||
|
Royale Bomber - Royale Air
|
||||||
|
|
||||||
|
======================== REFLEX BUNDLE ======================== -
|
||||||
|
Reflex - Response Unit - Angular Axe - Pivot
|
||||||
|
|
||||||
|
======================== STEALTH REFLEX BUNDLE
|
||||||
|
======================== - Stealth Reflex - Stealth Response Unit
|
||||||
|
|
||||||
|
======================== WILDCAT BUNDLE ======================== -
|
||||||
|
Wildcat - Sleek Strike
|
||||||
|
|
||||||
|
======================== ROGUE SPIDER KNIGHT BUNDLE
|
||||||
|
======================== - Rogue Spider Knight - Time Keeper
|
||||||
|
|
||||||
|
======================== FOUNDER EXCLUSIVES ======================== -
|
||||||
|
Rose Team Leader - Warpaint - Pony Up - Founder’s Umbrella - Founder’s
|
||||||
|
Gliders - Founder’s Pickaxes - Founder’s Banners
|
||||||
|
|
||||||
|
======================== RARE BANNERS ======================== - Alpha
|
||||||
|
Tester Banner - Battle Bus Banner - Founder’s Banner - FNCS Champion
|
||||||
|
Banner - World Cup Banner - Fall Skirmish Banner - Summer Skirmish
|
||||||
|
Banner - Galaxy Banner - IKONIK Banner - Glow Banner - Wonder Banner -
|
||||||
|
Honor Guard Banner - EON Banner - Dark Vertex Banner - Double Helix
|
||||||
|
Banner - Neo Versa Banner - Wildcat Banner
|
||||||
|
|
||||||
|
|
||||||
|
extra stuff IGNORE THAT IT SAYS MISSING JUST ADD THEM TO EITHER OG OR EXCLUSIVE LIST
|
||||||
|
|
||||||
|
|
||||||
|
Missing Exclusive Skins
|
||||||
|
Honor Guard
|
||||||
|
Wonder
|
||||||
|
Surf Strider
|
||||||
|
Gildedguy
|
||||||
|
Tart Tycoon
|
||||||
|
Various FNCS reward skins/styles
|
||||||
|
Platform-exclusive reskins
|
||||||
|
Crew Pack exclusive legacy styles
|
||||||
|
Missing Pickaxes
|
||||||
|
Crowbar (High Stakes)
|
||||||
|
Instigator
|
||||||
|
Founder-exclusive pickaxes
|
||||||
|
STW event pickaxes
|
||||||
|
Galaxy Cup pickaxes
|
||||||
|
Tournament reward pickaxes
|
||||||
|
Missing Gliders
|
||||||
|
Snowflake Umbrella
|
||||||
|
Mako
|
||||||
|
Founder's Gliders
|
||||||
|
Exclusive bundle gliders
|
||||||
|
Tournament gliders
|
||||||
|
Missing Banners
|
||||||
|
Many Search for Survivors creator banners
|
||||||
|
Alpha Tester variants
|
||||||
|
Early STW event banners
|
||||||
|
Dungeon banners
|
||||||
|
Ventures banners
|
||||||
|
Holiday event banners
|
||||||
|
Tournament placement banners
|
||||||
|
Missing Emoticons
|
||||||
|
Founder emoticons
|
||||||
|
Samsung emoticons
|
||||||
|
Wonder emoticons
|
||||||
|
Honor Guard emoticons
|
||||||
|
Twitch Prime emoticons
|
||||||
|
Early Battle Pass emoticons
|
||||||
|
Missing Wraps
|
||||||
|
Stealth Black
|
||||||
|
Magma
|
||||||
|
Star Scout
|
||||||
|
Competitive reward wraps
|
||||||
|
Platform-exclusive wraps
|
||||||
|
Missing Sprays
|
||||||
|
Tournament sprays
|
||||||
|
World Cup sprays
|
||||||
|
FNCS sprays
|
||||||
|
STW sprays
|
||||||
|
Missing Loading Screens
|
||||||
|
Galaxy loading screens
|
||||||
|
Wildcat loading screens
|
||||||
|
Tournament loading screens
|
||||||
|
STW exclusive loading screens
|
||||||
|
Missing Back Blings
|
||||||
|
|
||||||
|
There are dozens of exclusive back blings tied to:
|
||||||
|
|
||||||
|
Samsung bundles
|
||||||
|
Xbox bundles
|
||||||
|
Nintendo bundles
|
||||||
|
PlayStation bundles
|
||||||
|
Founder packs
|
||||||
|
Twitch Prime packs
|
||||||
|
Intel/NVIDIA promotions
|
||||||
|
Missing OG Progression Items
|
||||||
|
Max Omega Lights
|
||||||
|
Max Carbide Lights
|
||||||
|
Corrupted Scratch levels
|
||||||
|
Golden Peely
|
||||||
|
Fully Enlightened Chapter 2 skins
|
||||||
|
Holo Foil Marvel skins
|
||||||
|
Rainbow Foil Marvel skins
|
||||||
|
Gold Agent styles
|
||||||
|
Missing STW Exclusives
|
||||||
|
|
||||||
|
This is a huge category:
|
||||||
|
|
||||||
|
Founder heroes
|
||||||
|
Founder schematics
|
||||||
|
Founder banners
|
||||||
|
Event banners
|
||||||
|
Challenge the Horde rewards
|
||||||
|
Survive the Storm rewards
|
||||||
|
Frostnite rewards
|
||||||
|
Endurance rewards
|
||||||
|
Mythic Storm King rewards
|
||||||
|
|
||||||
|
If your goal is a checker that's com
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
@@ -0,0 +1 @@
|
|||||||
|
.env
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|

|
||||||
|
|
||||||
|
Provably-Safe Telegram Fortnite Skin Checker Bot
|
||||||
|
- single handedly developed by @xhexago on telegram and discord
|
||||||
|
|
||||||
|
Setup Guide(Windows):
|
||||||
|
- install Python 3.11.4 from https://www.python.org/ftp/python/3.11.4/python-3.11.4-amd64.exe
|
||||||
|
- make sure python is installed with the option "Add to "PATh";
|
||||||
|
- python -m pip install --upgrade pip
|
||||||
|
|
||||||
|
- pip install Pillow==11.0.0
|
||||||
|
- pip install telebot
|
||||||
|
- pip install asyncio
|
||||||
|
- pip install aiohttp
|
||||||
|
|
||||||
|
Setup Guide(Linux):
|
||||||
|
- sudo apt update
|
||||||
|
- sudo apt upgrade
|
||||||
|
- sudo apt install -y python3
|
||||||
|
- sudo apt install -y python3-pip
|
||||||
|
- pip install Pillow==11.0.0
|
||||||
|
- pip install telebot
|
||||||
|
- pip install asyncio
|
||||||
|
- pip install aiohttp
|
||||||
|
|
||||||
|
- Make .env file with variables for:
|
||||||
|
- TELEGRAM_API_TOKEN
|
||||||
|
After Width: | Height: | Size: 3.6 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 9.9 KiB |
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 9.8 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 8.9 KiB |
@@ -0,0 +1,24 @@
|
|||||||
|
class FortniteCosmetic:
|
||||||
|
def __init__(self):
|
||||||
|
self.cosmetic_id = ""
|
||||||
|
self.name = ""
|
||||||
|
self.backend_value = "AthenaCharacter"
|
||||||
|
self.rarity_value = "common"
|
||||||
|
self.small_icon = ""
|
||||||
|
self.is_banner = False
|
||||||
|
self.unlocked_styles = {}
|
||||||
|
self.is_exclusive = False
|
||||||
|
self.is_popular = False
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
"cosmetic_id": self.cosmetic_id,
|
||||||
|
"name": self.name,
|
||||||
|
"backend_value": self.backend_value,
|
||||||
|
"rarity_value": self.rarity_value,
|
||||||
|
"small_icon": self.small_icon,
|
||||||
|
"is_banner": self.is_banner,
|
||||||
|
"unlocked_styles": self.unlocked_styles,
|
||||||
|
"is_exclusive": self.is_exclusive,
|
||||||
|
"is_popular": self.is_popular,
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 4.0 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 4.4 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 10 KiB |
|
After Width: | Height: | Size: 14 KiB |
@@ -0,0 +1,690 @@
|
|||||||
|
import aiohttp
|
||||||
|
import requests
|
||||||
|
import asyncio
|
||||||
|
import os
|
||||||
|
import platform
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
from typing import Optional
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from cosmetic import FortniteCosmetic
|
||||||
|
from utils import bool_to_emoji
|
||||||
|
|
||||||
|
# these tokens are used to authorize in epic games's API and let us do the skincheck without getting errors
|
||||||
|
EPIC_API_SWITCH_TOKEN = "OThmN2U0MmMyZTNhNGY4NmE3NGViNDNmYmI0MWVkMzk6MGEyNDQ5YTItMDAxYS00NTFlLWFmZWMtM2U4MTI5MDFjNGQ3"
|
||||||
|
# keep in mind, sometimes epic games block the client ids, so then you have to generate new ios token for it to start working again
|
||||||
|
EPIC_API_IOS_CLIENT_TOKEN = "M2Y2OWU1NmM3NjQ5NDkyYzhjYzI5ZjFhZjA4YThhMTI6YjUxZWU5Y2IxMjIzNGY1MGE2OWVmYTY3ZWY1MzgxMmU="
|
||||||
|
|
||||||
|
class EpicEndpoints:
|
||||||
|
endpoint_oauth_token = "https://account-public-service-prod.ol.epicgames.com/account/api/oauth/token"
|
||||||
|
endpoint_prod03_oauth_token = "https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/token"
|
||||||
|
endpoint_redirect_url = "https://www.epicgames.com/id/login?redirectUrl=https%3A//www.epicgames.com/id/login%3FredirectUrl%3Dhttps%253A%252F%252Fwww.epicgames.com%252Fid%252Fapi%252Fredirect%253FclientId%253Dec684b8c687f479fadea3cb2ad83f5c6%2526responseType%253Dcode"
|
||||||
|
endpoint_oauth_exchange = "https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/exchange"
|
||||||
|
endpoint_device_auth = "https://account-public-service-prod03.ol.epicgames.com/account/api/oauth/deviceAuthorization"
|
||||||
|
|
||||||
|
# locker categories we render
|
||||||
|
locker_categories = ['AthenaCharacter', 'AthenaBackpack', 'AthenaPickaxe', 'AthenaDance', 'AthenaGlider', 'AthenaPopular', 'AthenaExclusive']
|
||||||
|
|
||||||
|
class EpicUser:
|
||||||
|
def __init__(self, data: dict = {}):
|
||||||
|
self.raw = data
|
||||||
|
|
||||||
|
# api response for login link generation
|
||||||
|
self.access_token = data.get("access_token", "")
|
||||||
|
self.expires_in = data.get("expires_in", 0)
|
||||||
|
self.expires_at = data.get("expires_at", "")
|
||||||
|
self.token_type = data.get("token_type", "")
|
||||||
|
self.client_id = data.get("client_id", "")
|
||||||
|
self.internal_client = data.get("internal_client", False)
|
||||||
|
self.client_service = data.get("client_service", "")
|
||||||
|
self.product_id = data.get("product_id", "")
|
||||||
|
self.application_id = data.get("application_id", "")
|
||||||
|
|
||||||
|
# api response for account metadata
|
||||||
|
self.refresh_token = data.get("refresh_token", "")
|
||||||
|
self.refresh_expires = data.get("refresh_expires", "")
|
||||||
|
self.refresh_expires_at = data.get("refresh_expires_at", "")
|
||||||
|
self.account_id = data.get("account_id", "")
|
||||||
|
self.display_name = data.get("displayName", "")
|
||||||
|
self.app = data.get("app", "")
|
||||||
|
self.in_app_id = data.get("in_app_id", "")
|
||||||
|
self.acr = data.get("acr", "")
|
||||||
|
self.auth_time = data.get("auth_time", "")
|
||||||
|
|
||||||
|
class LockerData:
|
||||||
|
def __init__(self):
|
||||||
|
self.cosmetic_categories = {}
|
||||||
|
self.cosmetic_array = {}
|
||||||
|
self.unlocked_styles = {}
|
||||||
|
self.homebase_banners = {}
|
||||||
|
self.last_match = ''
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
"cosmetic_categories": self.cosmetic_categories,
|
||||||
|
"cosmetic_array": self.cosmetic_array,
|
||||||
|
"unlocked_styles": self.unlocked_styles,
|
||||||
|
"homebase_banners": self.homebase_banners,
|
||||||
|
}
|
||||||
|
|
||||||
|
def add_missing_array2(arr, arr2, category, idclean):
|
||||||
|
# i hate hardcoding stuff, so ill make helper funcs instead
|
||||||
|
if category not in arr:
|
||||||
|
arr[category] = []
|
||||||
|
arr2[category] = []
|
||||||
|
|
||||||
|
arr[category].append(idclean)
|
||||||
|
|
||||||
|
def add_missing_array(arr, arr2, category):
|
||||||
|
# i hate hardcoding stuff, so ill make helper funcs instead
|
||||||
|
if category not in arr:
|
||||||
|
arr[category] = []
|
||||||
|
arr2[category] = []
|
||||||
|
|
||||||
|
async def get_cosmetic_data(cosmetic_lowercase_id):
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
f'https://fortnite-api.com/v2/cosmetics/br/search/ids?language=en{cosmetic_lowercase_id}'
|
||||||
|
)
|
||||||
|
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json().get('data', [])
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error getting cosmetic info for cosmetic with ID: {cosmetic_lowercase_id}\n> Exception: {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
class EpicGenerator:
|
||||||
|
def __init__(self) -> None:
|
||||||
|
# init the generator
|
||||||
|
self.http: aiohttp.ClientSession
|
||||||
|
self.user_agent = f"DeviceAuthGenerator/{platform.system()}/{platform.version()}"
|
||||||
|
self.access_token = ""
|
||||||
|
|
||||||
|
async def start(self) -> None:
|
||||||
|
self.http = aiohttp.ClientSession(headers={"User-Agent": self.user_agent})
|
||||||
|
self.access_token = await self.get_access_token()
|
||||||
|
|
||||||
|
async def kill(self) -> None:
|
||||||
|
await self.http.close()
|
||||||
|
|
||||||
|
async def get_access_token(self) -> str:
|
||||||
|
# getting the access token from epic's api(REQUIRES usage of EPIC_API_SWITCH_TOKEN as Authorization in headers for it to work)
|
||||||
|
# if it's not getting any data, it means the EPIC_API_SWITCH_TOKEN is expired, you must find new one :D
|
||||||
|
async with self.http.request(
|
||||||
|
method="POST",
|
||||||
|
url=EpicEndpoints.endpoint_oauth_token,
|
||||||
|
headers={
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
"Authorization": f"basic {EPIC_API_SWITCH_TOKEN}"
|
||||||
|
},
|
||||||
|
data={ "grant_type": "client_credentials" },
|
||||||
|
) as response:
|
||||||
|
data = await response.json()
|
||||||
|
return data["access_token"]
|
||||||
|
|
||||||
|
async def create_device_code(self) -> tuple:
|
||||||
|
# devide code is used on the link the checker bot sends u "active?userCode=SOMETHING" something like this
|
||||||
|
# REQUIRES usage of self.access_token, which we got from get_access_token function, as Authorization in headers
|
||||||
|
# returns the device code, used in the link we generate for the user to login
|
||||||
|
async with self.http.request(
|
||||||
|
method="POST",
|
||||||
|
url=EpicEndpoints.endpoint_device_auth,
|
||||||
|
headers={
|
||||||
|
"Authorization": f"bearer {self.access_token}",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
}
|
||||||
|
) as response:
|
||||||
|
data = await response.json()
|
||||||
|
return data
|
||||||
|
|
||||||
|
async def create_exchange_code(self, user: EpicUser) -> str:
|
||||||
|
# creates exchange code for the api requests & returns it
|
||||||
|
# REQUIRES usage of user.access_token, which we got from get_access_token function, as Authorization in headers
|
||||||
|
async with self.http.request(
|
||||||
|
method="GET",
|
||||||
|
url=EpicEndpoints.endpoint_oauth_exchange,
|
||||||
|
headers={"Authorization": f"bearer {user.access_token}"},
|
||||||
|
) as response:
|
||||||
|
data = await response.json()
|
||||||
|
return data["code"]
|
||||||
|
|
||||||
|
async def wait_for_device_code_completion(self, bot, message, code: str) -> Optional[EpicUser]:
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
async with self.http.request(
|
||||||
|
method="POST",
|
||||||
|
url=EpicEndpoints.endpoint_prod03_oauth_token,
|
||||||
|
headers={
|
||||||
|
"Authorization": f"basic {EPIC_API_SWITCH_TOKEN}",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded",
|
||||||
|
},
|
||||||
|
data={"grant_type": "device_code", "device_code": code},
|
||||||
|
timeout=10
|
||||||
|
) as request:
|
||||||
|
token_data = await request.json()
|
||||||
|
|
||||||
|
if request.status == 200 and "access_token" in token_data:
|
||||||
|
break
|
||||||
|
|
||||||
|
# Handle specific API errors
|
||||||
|
error_code = token_data.get("errorCode")
|
||||||
|
if error_code == "errors.com.epicgames.account.oauth.authorization_pending":
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif error_code == "g":
|
||||||
|
pass
|
||||||
|
|
||||||
|
elif error_code == "errors.com.epicgames.not_found":
|
||||||
|
bot.send_message(message.chat.id, f'❌ Login link expired, please use /login again.')
|
||||||
|
return None
|
||||||
|
else:
|
||||||
|
bot.send_message(message.chat.id, f'❌ Error occurred: {token_data.get("errorMessage", "Unknown error")}')
|
||||||
|
return None
|
||||||
|
|
||||||
|
await asyncio.sleep(10)
|
||||||
|
except ValueError as ve:
|
||||||
|
print(f"Error with waiting for device code: {ve}")
|
||||||
|
bot.send_message(message.chat.id, f'❌ An unexpected error occurred, please try again later.')
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unhandled exception: {e}")
|
||||||
|
bot.send_message(message.chat.id, f'❌ An error occurred, please contact support.')
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
async with self.http.request(
|
||||||
|
method="GET",
|
||||||
|
url=EpicEndpoints.endpoint_oauth_exchange,
|
||||||
|
headers={"Authorization": f"bearer {token_data['access_token']}"},
|
||||||
|
) as request:
|
||||||
|
if request.status != 200:
|
||||||
|
bot.send_message(message.chat.id, f'❌ Failed to retrieve exchange code. Please try again.')
|
||||||
|
return None
|
||||||
|
|
||||||
|
exchange_data = await request.json()
|
||||||
|
|
||||||
|
async with self.http.request(
|
||||||
|
method="POST",
|
||||||
|
url=EpicEndpoints.endpoint_prod03_oauth_token,
|
||||||
|
headers={
|
||||||
|
"Authorization": f"basic {EPIC_API_IOS_CLIENT_TOKEN}",
|
||||||
|
"Content-Type": "application/x-www-form-urlencoded"
|
||||||
|
},
|
||||||
|
data={
|
||||||
|
"grant_type": "exchange_code",
|
||||||
|
"exchange_code": exchange_data["code"]
|
||||||
|
},
|
||||||
|
) as request:
|
||||||
|
if request.status != 200:
|
||||||
|
bot.send_message(message.chat.id, f'❌ Failed to authenticate using exchange code. Please try again.')
|
||||||
|
return None
|
||||||
|
|
||||||
|
auth_data = await request.json()
|
||||||
|
|
||||||
|
return EpicUser(data=auth_data)
|
||||||
|
|
||||||
|
except KeyError as ke:
|
||||||
|
bot.send_message(message.chat.id, f'❌ Unexpected response format from server.')
|
||||||
|
return None
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Unhandled exception during token exchange: {e}")
|
||||||
|
bot.send_message(message.chat.id, f'❌ An error occurred while completing authentication.')
|
||||||
|
return None
|
||||||
|
|
||||||
|
async def create_device_auths(self, user: EpicUser) -> dict:
|
||||||
|
# creates device auth
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
async with self.http.request(
|
||||||
|
method="POST",
|
||||||
|
url=f"https://account-public-service-prod.ol.epicgames.com/account/api/public/account/{user.account_id}/deviceAuth",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"bearer {user.access_token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
) as request:
|
||||||
|
data = await request.json()
|
||||||
|
|
||||||
|
return {
|
||||||
|
"device_id": data["deviceId"],
|
||||||
|
"account_id": data["accountId"],
|
||||||
|
"secret": data["secret"],
|
||||||
|
"user_agent": data["userAgent"],
|
||||||
|
"created": {
|
||||||
|
"location": data["created"]["location"],
|
||||||
|
"ip_address": data["created"]["ipAddress"],
|
||||||
|
"datetime": data["created"]["dateTime"],
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
async def get_account_metadata(self, user: EpicUser) -> json:
|
||||||
|
# grabs account's metadata(basic information) from the api
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
|
||||||
|
url = f'https://account-public-service-prod03.ol.epicgames.com/account/api/public/account/displayName/{user.display_name}'
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"bearer {user.access_token}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
}
|
||||||
|
|
||||||
|
async with self.http.get(url, headers=headers) as response:
|
||||||
|
metadata = await response.json()
|
||||||
|
|
||||||
|
return metadata
|
||||||
|
|
||||||
|
async def get_external_connections(self, user: EpicUser) -> dict:
|
||||||
|
# returns external connected accounts info
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
async with self.http.request(
|
||||||
|
method="GET",
|
||||||
|
url=f"https://account-public-service-prod03.ol.epicgames.com/account/api/public/account/{user.account_id}/externalAuths",
|
||||||
|
headers={"Authorization": f"bearer {user.access_token}"}
|
||||||
|
) as resp:
|
||||||
|
if resp.status != 200:
|
||||||
|
return []
|
||||||
|
|
||||||
|
external_auths = await resp.json()
|
||||||
|
|
||||||
|
return external_auths
|
||||||
|
|
||||||
|
async def get_public_account_info(self, user: EpicUser) -> dict:
|
||||||
|
# returns basic public info about the account
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
url = f'https://account-public-service-prod03.ol.epicgames.com/account/api/public/account/{user.account_id}'
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"bearer {user.access_token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
async with self.http.get(url, headers=headers) as response:
|
||||||
|
account_data = await response.json()
|
||||||
|
|
||||||
|
account_info = {} # creating json for only stuff we are interested into
|
||||||
|
creation_date = account_data.get("created", "?")
|
||||||
|
if creation_date != "?":
|
||||||
|
creation_date = datetime.strptime(creation_date, "%Y-%m-%dT%H:%M:%S.%fZ").strftime("%d/%m/%Y")
|
||||||
|
|
||||||
|
account_info['creation_date'] = creation_date
|
||||||
|
account_info['externalAuths'] = await self.get_external_connections(user)
|
||||||
|
return account_info
|
||||||
|
|
||||||
|
async def get_common_profile(self, user: EpicUser) -> json:
|
||||||
|
# gets the common profile, containing vbucks, receipts amount, vbucks purchases history, banners list
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
|
||||||
|
url = f'https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/api/game/v2/profile/{user.account_id}/client/QueryProfile?profileId=common_core&rvn=-1'
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"bearer {user.access_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_data = requests.post(url, headers=headers, json={}).json()
|
||||||
|
return profile_data
|
||||||
|
|
||||||
|
async def get_friend_codes(self, user: EpicUser, platform: str) -> json:
|
||||||
|
# https://fngw-mcp-gc-livefn.ol.epicgames.com/fortnite/api/v2/game/friendcodes/<accountID>/<platform>
|
||||||
|
# gets the save the world redeem codes based on the platform you've entered
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
# this always returns an error saying page isn't found, im not sure why.
|
||||||
|
url = f'https://fngw-mcp-gc-livefn.ol.epicgames.com/fortnite/api/v2/game/friendcodes/{user.account_id}/{platform}'
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"bearer {user.access_token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
async with self.http.get(url, headers=headers) as response:
|
||||||
|
codes_data = await response.json()
|
||||||
|
|
||||||
|
return codes_data
|
||||||
|
|
||||||
|
async def get_homebase_profile(self, user: EpicUser) -> json:
|
||||||
|
# gets the save the world profile data
|
||||||
|
# REQUIRES usage of user.access_token as Authorization in headers
|
||||||
|
|
||||||
|
url = f'https://fngw-mcp-gc-livefn.ol.epicgames.com/fortnite/api/game/v2/profile/{user.account_id}/client/QueryPublicProfile'
|
||||||
|
querystring = { "profileId":"campaign", "rvn":"-1" }
|
||||||
|
payload = {}
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"bearer {user.access_token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
profile_data = requests.request("POST", url, json=payload, headers=headers, params=querystring).json()
|
||||||
|
|
||||||
|
return profile_data
|
||||||
|
|
||||||
|
async def set_affiliate(self, user: EpicUser, affiliate_name: str):
|
||||||
|
url = f'https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/api/game/v2/profile/{user.account_id}/client/SetAffiliateName?profileId=common_core'
|
||||||
|
payload = { "affiliateName": affiliate_name }
|
||||||
|
headers = {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
"Authorization": f"bearer {user.access_token}"
|
||||||
|
}
|
||||||
|
|
||||||
|
affiliate_response = requests.request("POST", url, json=payload, headers=headers)
|
||||||
|
|
||||||
|
if affiliate_response.status != 200:
|
||||||
|
print(f"Error setting affiliate name ({affiliate_response.status})")
|
||||||
|
|
||||||
|
async def get_locker_data(self, user: EpicUser) -> LockerData:
|
||||||
|
# gets locker arrays
|
||||||
|
# locker_categories - the locker categories we render
|
||||||
|
url = f'https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/api/game/v2/profile/{user.account_id}/client/QueryProfile?profileId=athena'
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"bearer {user.access_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
athena_data = requests.post(url, headers=headers, json={}).json()
|
||||||
|
|
||||||
|
locker_data = LockerData()
|
||||||
|
exclusive_cosmetics = []
|
||||||
|
popular_cosmetics = []
|
||||||
|
if "profileChanges" not in athena_data:
|
||||||
|
return LockerData()
|
||||||
|
|
||||||
|
# activity
|
||||||
|
account_level = athena_data.get("profileChanges", [{}])[0].get("profile", {}).get("stats", {}).get("attributes", {}).get("accountLevel", 1)
|
||||||
|
last_match_end = athena_data.get("profileChanges", [{}])[0].get("profile", {}).get("stats", {}).get("attributes", {}).get("last_match_end_datetime", "")
|
||||||
|
if last_match_end:
|
||||||
|
last_match_end_date = datetime.fromisoformat(last_match_end.replace("Z", "+00:00"))
|
||||||
|
days_since_last_match = (datetime.now(timezone.utc) - last_match_end_date).days
|
||||||
|
last_match_date_str = last_match_end_date.strftime("%d.%m.%y")
|
||||||
|
locker_data.last_match = f"{last_match_date_str} ({days_since_last_match} days ago)"
|
||||||
|
else:
|
||||||
|
locker_data.last_match = "800+ days ago"
|
||||||
|
|
||||||
|
# getting extra cosmetics
|
||||||
|
try:
|
||||||
|
with open('exclusive.txt', 'r', encoding='utf-8') as f:
|
||||||
|
exclusive_cosmetics = [i.strip() for i in f.readlines()]
|
||||||
|
|
||||||
|
with open('most_wanted.txt', 'r', encoding='utf-8') as f:
|
||||||
|
popular_cosmetics = [i.strip() for i in f.readlines()]
|
||||||
|
except FileNotFoundError:
|
||||||
|
print("Warning: exclusive.txt or most_wanted.txt not found.")
|
||||||
|
|
||||||
|
# getting owned items list
|
||||||
|
for i in athena_data['profileChanges'][0]['profile']['items']:
|
||||||
|
template_id = athena_data['profileChanges'][0]['profile']['items'][i]['templateId']
|
||||||
|
if template_id.startswith('Athena'):
|
||||||
|
cosmetic_category = template_id.split(':')[0]
|
||||||
|
cosmetic_id = template_id.split(':')[1]
|
||||||
|
locker_data.unlocked_styles[cosmetic_id] = []
|
||||||
|
|
||||||
|
# adding missing categories to the arrays
|
||||||
|
if 'AthenaExclusive' not in locker_data.cosmetic_categories:
|
||||||
|
locker_data.cosmetic_categories['AthenaExclusive'] = []
|
||||||
|
locker_data.cosmetic_array['AthenaExclusive'] = []
|
||||||
|
locker_data.cosmetic_categories['AthenaExclusive'].append(cosmetic_id)
|
||||||
|
|
||||||
|
if 'AthenaPopular' not in locker_data.cosmetic_categories:
|
||||||
|
locker_data.cosmetic_categories['AthenaPopular'] = []
|
||||||
|
locker_data.cosmetic_array['AthenaPopular'] = []
|
||||||
|
locker_data.cosmetic_categories['AthenaPopular'].append(cosmetic_id)
|
||||||
|
|
||||||
|
if 'HomebaseBannerIcons' not in locker_data.cosmetic_categories:
|
||||||
|
locker_data.cosmetic_categories['HomebaseBannerIcons'] = []
|
||||||
|
locker_data.cosmetic_array['HomebaseBannerIcons'] = []
|
||||||
|
locker_data.cosmetic_categories['HomebaseBannerIcons'].append(cosmetic_id)
|
||||||
|
|
||||||
|
if cosmetic_category not in locker_data.cosmetic_categories:
|
||||||
|
locker_data.cosmetic_categories[cosmetic_category] = []
|
||||||
|
locker_data.cosmetic_array[cosmetic_category] = []
|
||||||
|
locker_data.cosmetic_categories[cosmetic_category].append(cosmetic_id)
|
||||||
|
|
||||||
|
# listing the owned unlocked styles for each cosmetic
|
||||||
|
for item_id, item_data in athena_data['profileChanges'][0]['profile']['items'].items():
|
||||||
|
template_id = item_data.get('templateId', '')
|
||||||
|
|
||||||
|
if template_id.startswith('Athena'):
|
||||||
|
lowercase_cosmetic_id = template_id.split(':')[1]
|
||||||
|
|
||||||
|
# adding the cosmetic to the "unlocked styles"
|
||||||
|
if lowercase_cosmetic_id not in locker_data.unlocked_styles:
|
||||||
|
locker_data.unlocked_styles[lowercase_cosmetic_id] = []
|
||||||
|
|
||||||
|
attributes = item_data.get('attributes', {})
|
||||||
|
variants = attributes.get('variants', [])
|
||||||
|
|
||||||
|
for variant in variants:
|
||||||
|
# adding the cosmetic's owned styles
|
||||||
|
locker_data.unlocked_styles[lowercase_cosmetic_id].extend(variant.get('owned', []))
|
||||||
|
|
||||||
|
# getting banners
|
||||||
|
common_profile_data = await self.get_common_profile(user)
|
||||||
|
if common_profile_data:
|
||||||
|
# common profile found
|
||||||
|
for profileChange in common_profile_data["profileChanges"]:
|
||||||
|
profile_items = profileChange["profile"]["items"]
|
||||||
|
|
||||||
|
# checking every item
|
||||||
|
for item_key, item_value in profile_items.items():
|
||||||
|
cosmetic_template_id = item_value.get("templateId", "")
|
||||||
|
if cosmetic_template_id:
|
||||||
|
# the banner is found, so we adding it
|
||||||
|
lowercase_banner_id = cosmetic_template_id.split(':')[1]
|
||||||
|
if lowercase_banner_id not in locker_data.homebase_banners:
|
||||||
|
locker_data.homebase_banners[lowercase_banner_id] = []
|
||||||
|
|
||||||
|
|
||||||
|
for category in locker_categories:
|
||||||
|
if category == "AthenaPopular" or category == 'AthenaExclusive':
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
list_of_cosmetic_ids = []
|
||||||
|
# splitting the category's cosmetic ids to sublists
|
||||||
|
for i in range(0, len(locker_data.cosmetic_categories[category]), 50):
|
||||||
|
sublist = locker_data.cosmetic_categories[category][i:i+50]
|
||||||
|
list_of_cosmetic_ids.append(sublist)
|
||||||
|
|
||||||
|
for cosmetic_id in list_of_cosmetic_ids:
|
||||||
|
cosmetics_data = requests.get('https://fortnite-api.com/v2/cosmetics/br/search/ids?language=en&id={}'.format('&id='.join(cosmetic_id)))
|
||||||
|
c_data = cosmetics_data.json().get("data", [])
|
||||||
|
if not c_data:
|
||||||
|
# cosmetics data not found
|
||||||
|
continue
|
||||||
|
|
||||||
|
for cosmetic in c_data:
|
||||||
|
if cosmetic['id'] == "CID_DefaultOutfit":
|
||||||
|
# skipping default skin
|
||||||
|
continue
|
||||||
|
|
||||||
|
if category == 'AthenaDance' and cosmetic['type']['value'] != 'emote' and cosmetic['id'] not in exclusive_cosmetics:
|
||||||
|
# emote category, but isnt exclusive and isnt emote
|
||||||
|
continue
|
||||||
|
|
||||||
|
make_mythic = False
|
||||||
|
if cosmetic['id'] in exclusive_cosmetics:
|
||||||
|
make_mythic = True
|
||||||
|
# Pink Ghoul Trooper
|
||||||
|
if cosmetic['id'].lower() == 'cid_029_athena_commando_f_halloween':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Mat3' in locker_data.unlocked_styles.get('cid_029_athena_commando_f_halloween', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Purple Skull Trooper
|
||||||
|
if cosmetic['id'].lower() == 'cid_030_athena_commando_m_halloween':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Mat1' in locker_data.unlocked_styles.get('cid_030_athena_commando_m_halloween', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Aerial Assault Trooper
|
||||||
|
if cosmetic['id'].lower() == 'cid_017_athena_commando_m':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage2' in locker_data.unlocked_styles.get('cid_017_athena_commando_m', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Renegade Raider
|
||||||
|
if cosmetic['id'].lower() == 'cid_028_athena_commando_f':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Mat3' in locker_data.unlocked_styles.get('cid_028_athena_commando_f', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Raider's Revenge
|
||||||
|
if cosmetic['id'].lower() == 'pickaxe_lockjaw':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage2' in locker_data.unlocked_styles.get('pickaxe_lockjaw', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Aerial Assault One
|
||||||
|
if cosmetic['id'].lower() == 'glider_id_001':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage2' in locker_data.unlocked_styles.get('glider_id_001', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Stage 5 Omega Lights
|
||||||
|
if cosmetic['id'].lower() == 'cid_116_athena_commando_m_carbideblack':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage5' in locker_data.unlocked_styles.get('cid_116_athena_commando_m_carbideblack', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Gold Midas
|
||||||
|
if cosmetic['id'].lower() == 'cid_694_athena_commando_m_catburglar':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage4' in locker_data.unlocked_styles.get('cid_694_athena_commando_m_catburglar', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Gold Meowscles
|
||||||
|
if cosmetic['id'].lower() == 'cid_693_athena_commando_m_buffcat':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage4' in locker_data.unlocked_styles.get('cid_693_athena_commando_m_buffcat', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Gold TNtina
|
||||||
|
if cosmetic['id'].lower() == 'cid_691_athena_commando_f_tntina':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage7' in locker_data.unlocked_styles.get('cid_691_athena_commando_f_tntina', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Gold Skye
|
||||||
|
if cosmetic['id'].lower() == 'cid_690_athena_commando_f_photographer':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage4' in locker_data.unlocked_styles.get('cid_690_athena_commando_f_photographer', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Gold Agent Peely
|
||||||
|
if cosmetic['id'].lower() == 'cid_701_athena_commando_m_bananaagent':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage4' in locker_data.unlocked_styles.get('cid_701_athena_commando_m_bananaagent', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# World Cup Fishtick
|
||||||
|
if cosmetic['id'].lower() == 'cid_315_athena_commando_m_teriyakifish':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Stage3' in locker_data.unlocked_styles.get('cid_315_athena_commando_m_teriyakifish', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
# Mate Black Masterchief
|
||||||
|
if cosmetic['id'].lower() == 'cid_971_athena_commando_m_jupiter_s0z6m':
|
||||||
|
make_mythic = False
|
||||||
|
if 'Mat2' in locker_data.unlocked_styles.get('cid_971_athena_commando_m_jupiter_s0z6m', []):
|
||||||
|
make_mythic = True
|
||||||
|
|
||||||
|
if make_mythic == True:
|
||||||
|
cosmetic['rarity']['value'] = 'mythic'
|
||||||
|
|
||||||
|
cosmetic_info = FortniteCosmetic()
|
||||||
|
cosmetic_info.cosmetic_id = cosmetic['id']
|
||||||
|
cosmetic_info.name = cosmetic['name']
|
||||||
|
cosmetic_info.small_icon = cosmetic['images']['smallIcon']
|
||||||
|
cosmetic_info.backend_value = category
|
||||||
|
cosmetic_info.rarity_value = cosmetic['rarity']['value']
|
||||||
|
cosmetic_info.is_banner = False
|
||||||
|
cosmetic_info.is_exclusive = make_mythic
|
||||||
|
cosmetic_info.is_popular = cosmetic['id'] in popular_cosmetics
|
||||||
|
cosmetic_info.unlocked_styles = locker_data.unlocked_styles[cosmetic['id'].lower()]
|
||||||
|
|
||||||
|
locker_data.cosmetic_array[category].append(cosmetic_info)
|
||||||
|
|
||||||
|
# now special ones
|
||||||
|
if cosmetic_info.is_popular:
|
||||||
|
locker_data.cosmetic_array['AthenaPopular'].append(cosmetic_info)
|
||||||
|
|
||||||
|
if make_mythic:
|
||||||
|
locker_data.cosmetic_array['AthenaExclusive'].append(cosmetic_info)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f'exception: {e}')
|
||||||
|
continue
|
||||||
|
|
||||||
|
# handle banners
|
||||||
|
banners_data = requests.get('https://fortnite-api.com/v1/banners')
|
||||||
|
for fn_banner in banners_data.json()['data']:
|
||||||
|
banner_lower_id = fn_banner['id'].lower()
|
||||||
|
if banner_lower_id not in locker_data.homebase_banners:
|
||||||
|
# banner isn't owned
|
||||||
|
continue
|
||||||
|
|
||||||
|
make_mythic = False
|
||||||
|
icon = fn_banner['images']['icon']
|
||||||
|
rarity = 'uncommon'
|
||||||
|
if fn_banner['id'] in exclusive_cosmetics:
|
||||||
|
make_mythic = True
|
||||||
|
rarity = 'mythic'
|
||||||
|
|
||||||
|
# for future
|
||||||
|
cosmetic_info = FortniteCosmetic()
|
||||||
|
cosmetic_info.cosmetic_id = fn_banner['id']
|
||||||
|
cosmetic_info.name = fn_banner['devName']
|
||||||
|
cosmetic_info.small_icon = fn_banner['images']['smallIcon']
|
||||||
|
cosmetic_info.rarity_value = rarity
|
||||||
|
cosmetic_info.backend_value = 'HomebaseBannerIcons'
|
||||||
|
cosmetic_info.is_banner = True
|
||||||
|
cosmetic_info.is_exclusive = make_mythic
|
||||||
|
cosmetic_info.is_popular = fn_banner['id'] in popular_cosmetics
|
||||||
|
|
||||||
|
locker_data.cosmetic_array['HomebaseBannerIcons'].append(cosmetic_info)
|
||||||
|
# now exclusive ones
|
||||||
|
if make_mythic:
|
||||||
|
locker_data.cosmetic_array['AthenaExclusive'].append(cosmetic_info)
|
||||||
|
|
||||||
|
# sorting exclusives category
|
||||||
|
locker_data.cosmetic_array['AthenaExclusive'].sort(
|
||||||
|
key=lambda cosmetic: exclusive_cosmetics.index(cosmetic.cosmetic_id)
|
||||||
|
if cosmetic.cosmetic_id in exclusive_cosmetics
|
||||||
|
else float('inf')
|
||||||
|
)
|
||||||
|
|
||||||
|
# returning back the locker data
|
||||||
|
return locker_data
|
||||||
|
|
||||||
|
async def get_seasons_message(self, user: EpicUser) -> str:
|
||||||
|
url = f'https://fortnite-public-service-prod11.ol.epicgames.com/fortnite/api/game/v2/profile/{user.account_id}/client/QueryProfile?profileId=athena'
|
||||||
|
headers = {
|
||||||
|
"Authorization": f"bearer {user.access_token}",
|
||||||
|
"Content-Type": "application/json"
|
||||||
|
}
|
||||||
|
|
||||||
|
athena_data = requests.post(url, headers=headers, json={}).json()
|
||||||
|
|
||||||
|
past_seasons = {}
|
||||||
|
seasons_info = []
|
||||||
|
|
||||||
|
# seasons infos
|
||||||
|
past_seasons = athena_data.get("profileChanges", [{}])[0].get("profile", {}).get("stats", {}).get("attributes", {}).get("past_seasons", [])
|
||||||
|
total_wins = sum(season.get("numWins", 0) for season in past_seasons)
|
||||||
|
total_matches = sum(
|
||||||
|
season.get("numHighBracket", 0) + season.get("numLowBracket", 0) +
|
||||||
|
season.get("numHighBracket_LTM", 0) + season.get("numLowBracket_LTM", 0) +
|
||||||
|
season.get("numHighBracket_Ar", 0) + season.get("numLowBracket_Ar", 0)
|
||||||
|
for season in past_seasons
|
||||||
|
)
|
||||||
|
|
||||||
|
curses = athena_data.get("profileChanges", [{}])[0].get("profile", {}).get("stats", {}).get("attributes", {})
|
||||||
|
cursesinfo = {
|
||||||
|
'level': curses.get('level', 1),
|
||||||
|
'book_level': curses.get('book_level', 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for season in past_seasons:
|
||||||
|
seasons_info.append(f"""
|
||||||
|
#️⃣Season {season.get('seasonNumber', 1)}
|
||||||
|
› Level: {season.get('seasonLevel', '1')}
|
||||||
|
› Battle Pass: {bool_to_emoji(season.get('purchasedVIP', False))}
|
||||||
|
› Wins: {season.get('numWins', 0)}
|
||||||
|
""")
|
||||||
|
|
||||||
|
seasons_info_embeds = seasons_info
|
||||||
|
seasons_info_message = "Previous Seasons History:\n" + "\n".join(seasons_info_embeds)
|
||||||
|
seasons_info_message += f"\nCurrent Season:\n› Level: {cursesinfo['level']}\n› Battle Pass Level: {cursesinfo['book_level']}"
|
||||||
|
return seasons_info_message
|
||||||
@@ -0,0 +1,415 @@
|
|||||||
|
Pickaxe_Lockjaw
|
||||||
|
CID_028_Athena_Commando_F
|
||||||
|
CID_029_Athena_Commando_F_Halloween
|
||||||
|
CID_017_Athena_Commando_M
|
||||||
|
CID_030_Athena_Commando_M_Halloween
|
||||||
|
Glider_ID_001
|
||||||
|
Pickaxe_ID_376_FNCS
|
||||||
|
Pickaxe_FNCS_S32
|
||||||
|
CID_035_Athena_Commando_M_Medieval
|
||||||
|
CID_039_Athena_Commando_F_Disco
|
||||||
|
|
||||||
|
CID_660_Athena_Commando_F_BandageNinjaBlue
|
||||||
|
CID_619_Athena_Commando_F_TechLlama
|
||||||
|
CID_434_Athena_Commando_F_StealthHonor
|
||||||
|
CID_757_Athena_Commando_F_WildCat
|
||||||
|
CID_175_Athena_Commando_M_Celestial
|
||||||
|
CID_342_Athena_Commando_M_StreetRacerMetallic
|
||||||
|
CID_313_Athena_Commando_M_KpopFashion
|
||||||
|
CID_386_Athena_Commando_M_StreetOpsStealth
|
||||||
|
CID_259_Athena_Commando_M_StreetOps
|
||||||
|
CID_174_Athena_Commando_F_CarbideWhite
|
||||||
|
Character_MasterKeyOrder
|
||||||
|
CID_371_Athena_Commando_M_SpeedyMidnight
|
||||||
|
CID_753_Athena_Commando_F_Hostile
|
||||||
|
CID_183_Athena_Commando_M_ModernMilitaryRed
|
||||||
|
CID_479_Athena_Commando_F_Davinci
|
||||||
|
CID_516_Athena_Commando_M_BlackWidowRogue
|
||||||
|
CID_441_Athena_Commando_F_CyberScavengerBlue
|
||||||
|
CID_783_Athena_Commando_M_AquaJacket
|
||||||
|
CID_850_Athena_Commando_F_SkullBriteCube
|
||||||
|
CID_113_Athena_Commando_M_BlueAce
|
||||||
|
CID_515_Athena_Commando_M_BarbequeLarry
|
||||||
|
CID_971_Athena_Commando_M_Jupiter_S0Z6M
|
||||||
|
|
||||||
|
|
||||||
|
CID_033_Athena_Commando_F_Medieval
|
||||||
|
CID_032_Athena_Commando_M_Medieval
|
||||||
|
|
||||||
|
|
||||||
|
CID_084_Athena_Commando_M_Assassin
|
||||||
|
CID_083_Athena_Commando_F_Tactical
|
||||||
|
CID_090_Athena_Commando_M_Tactical
|
||||||
|
|
||||||
|
CID_116_Athena_Commando_M_CarbideBlack
|
||||||
|
|
||||||
|
|
||||||
|
CID_703_Athena_Commando_M_Cyclone
|
||||||
|
CID_761_Athena_Commando_M_CycloneSpace
|
||||||
|
CID_478_Athena_Commando_F_WorldCup
|
||||||
|
CID_964_Athena_Commando_M_Historian_869BC
|
||||||
|
CID_315_Athena_Commando_M_TeriyakiFish
|
||||||
|
|
||||||
|
CID_085_Athena_Commando_M_Twitch
|
||||||
|
CID_089_Athena_Commando_M_RetroGrey
|
||||||
|
CID_114_Athena_Commando_F_TacticalWoodland
|
||||||
|
|
||||||
|
|
||||||
|
CID_096_Athena_Commando_F_Founder
|
||||||
|
CID_095_Athena_Commando_M_Founder
|
||||||
|
|
||||||
|
|
||||||
|
Character_SnowNinjaDark
|
||||||
|
CID_052_Athena_Commando_F_PSBlue
|
||||||
|
CID_138_Athena_Commando_M_PSBurnout
|
||||||
|
CID_296_Athena_Commando_M_Math
|
||||||
|
CID_360_Athena_Commando_M_TechOpsBlue
|
||||||
|
CID_A_101_Athena_Commando_M_TacticalWoodlandBlue
|
||||||
|
CID_A_421_Athena_Commando_F_BlizzardBomber
|
||||||
|
CID_657_Athena_Commando_F_TechOpsBlue
|
||||||
|
CID_711_Athena_Commando_M_LongShorts
|
||||||
|
Character_BlueJet
|
||||||
|
CID_926_Athena_Commando_F_StreetFashionDiamond
|
||||||
|
Character_RetroWheels
|
||||||
|
|
||||||
|
|
||||||
|
CID_701_Athena_Commando_M_BananaAgent
|
||||||
|
CID_690_Athena_Commando_F_Photographer
|
||||||
|
CID_691_Athena_Commando_F_TNTina
|
||||||
|
CID_693_Athena_Commando_M_BuffCat
|
||||||
|
CID_694_Athena_Commando_M_CatBurglar
|
||||||
|
|
||||||
|
|
||||||
|
Character_TubaGummi
|
||||||
|
|
||||||
|
|
||||||
|
BID_004_BlackKnight
|
||||||
|
BID_415_TechLlama
|
||||||
|
BID_138_Celestial
|
||||||
|
BID_521_WildCat
|
||||||
|
BID_249_StreetOpsStealth
|
||||||
|
BID_234_SpeedyMidnight
|
||||||
|
BID_604_SkullBritecube
|
||||||
|
BID_114_ModernMilitaryRed
|
||||||
|
BID_346_BlackWidowRogue
|
||||||
|
PetCarrier_013_BbqLarry
|
||||||
|
|
||||||
|
BID_002_RoyaleKnight
|
||||||
|
BID_001_BlueSquire
|
||||||
|
|
||||||
|
|
||||||
|
Backpack_SnowNinjaDark
|
||||||
|
BID_A_019_BlizzardBomberFemale
|
||||||
|
BID_169_MathMale
|
||||||
|
BID_224_TechOpsBlue
|
||||||
|
Backpack_BlueJet
|
||||||
|
Backpack_SnowSoldierFashion
|
||||||
|
|
||||||
|
|
||||||
|
BID_027_Scavenger
|
||||||
|
BID_468_Cyclone
|
||||||
|
BID_520_CycloneUniverse
|
||||||
|
|
||||||
|
|
||||||
|
Backpack_FNCSShield_S32
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_116_Celestial
|
||||||
|
Pickaxe_ID_398_WildCatFemale
|
||||||
|
Pickaxe_ID_077_CarbideWhite
|
||||||
|
Pickaxe_ID_099_ModernMilitaryRed
|
||||||
|
Pickaxe_ID_461_SkullBriteCube
|
||||||
|
Pickaxe_ID_189_StreetOpsStealth
|
||||||
|
Pickaxe_ID_178_SpeedyMidnight
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_294_CandyCane
|
||||||
|
Pickaxe_ID_508_HistorianMale_6BQSW
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_013_Teslacoil
|
||||||
|
Pickaxe_ID_011_Medieval
|
||||||
|
Pickaxe_ID_028_Space
|
||||||
|
Pickaxe_ID_092_Bling
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_039_TacticalBlack
|
||||||
|
Pickaxe_ID_044_TacticalUrbanHammer
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_265_BarbequeLarry1H
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_STW006_Tier_7
|
||||||
|
Pickaxe_ID_153_RoseLeader
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_SnowNinjaDark
|
||||||
|
BID_055_PSBurnout
|
||||||
|
Pickaxe_ID_088_PSBurnout
|
||||||
|
Pickaxe_ID_256_TechOpsBlue
|
||||||
|
Pickaxe_ID_464_LongShortsMale
|
||||||
|
Pickaxe_ID_717_NetworkFemale
|
||||||
|
Pickaxe_SnowSoldierFashion
|
||||||
|
Pickaxe_RetroWheels
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_STW005_Tier_6
|
||||||
|
Pickaxe_ID_STW004_Tier_5
|
||||||
|
Pickaxe_ID_STW003_Tier_4
|
||||||
|
Pickaxe_ID_STW002_Tier_3
|
||||||
|
Pickaxe_ID_STW007_Basic
|
||||||
|
Pickaxe_ID_STW001_Tier_1
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_SpookyNeonRed
|
||||||
|
Pickaxe_SpookyNeonBlue
|
||||||
|
Pickaxe_ID_359_CycloneMale
|
||||||
|
|
||||||
|
|
||||||
|
EID_KPopDance03
|
||||||
|
EID_Davinci
|
||||||
|
|
||||||
|
|
||||||
|
EID_Fresh
|
||||||
|
EID_Floss
|
||||||
|
EID_Worm
|
||||||
|
EID_RideThePonyTwo
|
||||||
|
EID_TakeTheL
|
||||||
|
EID_HipHop01
|
||||||
|
EID_GoodVibes
|
||||||
|
EID_IceKing
|
||||||
|
EID_RichFam
|
||||||
|
EID_PlayerEleven
|
||||||
|
EID_RigorMortis
|
||||||
|
EID_Gleam
|
||||||
|
EID_Downward_8GZUA
|
||||||
|
EID_CycloneHeadBang
|
||||||
|
EID_SandwichBop
|
||||||
|
EID_JulyBooks
|
||||||
|
EID_Laugh
|
||||||
|
EID_Textile_3O8QG
|
||||||
|
EID_Uproar_496SC
|
||||||
|
EID_Tidy
|
||||||
|
EID_Zippy
|
||||||
|
|
||||||
|
|
||||||
|
EID_Avian
|
||||||
|
|
||||||
|
|
||||||
|
Emoji_S22_Showdown_Mae
|
||||||
|
Emoji_S22_Showdown_Zet
|
||||||
|
|
||||||
|
|
||||||
|
Spray_Showdown_Mae
|
||||||
|
Spray_Showdown_Zet
|
||||||
|
Spray_Showdown_Pi
|
||||||
|
SPID_066_Llamalaxy
|
||||||
|
SPID_065_DiscoBaller
|
||||||
|
SPID_043_Flairspray
|
||||||
|
SPID_274_Alt_3
|
||||||
|
SPID_022_SoloShowdown
|
||||||
|
|
||||||
|
|
||||||
|
Glider_Warthog
|
||||||
|
Glider_ID_003_District
|
||||||
|
|
||||||
|
Glider_ID_211_WildCatBlue
|
||||||
|
Glider_ID_090_Celestial
|
||||||
|
Glider_ID_056_CarbideWhite
|
||||||
|
Glider_ID_075_ModernMilitaryRed
|
||||||
|
Glider_ID_137_StreetOpsStealth
|
||||||
|
Glider_ID_131_SpeedyMidnight
|
||||||
|
|
||||||
|
|
||||||
|
Glider_ID_002_Medieval
|
||||||
|
Glider_ID_015_Brite
|
||||||
|
|
||||||
|
|
||||||
|
Glider_ID_161_RoseLeader
|
||||||
|
FounderGlider
|
||||||
|
Glider_Military
|
||||||
|
|
||||||
|
|
||||||
|
Glider_ID_013_PSBlue
|
||||||
|
Glider_ID_067_PSBurnout
|
||||||
|
Glider_ID_150_TechOpsBlue
|
||||||
|
Glider_ID_309_TacticalWoodlandBlue
|
||||||
|
Glider_ID_389_BlizzardBomberFemale
|
||||||
|
Glider_SnowSoldierFashion
|
||||||
|
|
||||||
|
Glider_ID_196_CycloneMale
|
||||||
|
Glider_ID_347_PeachMale
|
||||||
|
|
||||||
|
|
||||||
|
FounderUmbrella
|
||||||
|
Umbrella_Snowflake
|
||||||
|
Umbrella_PaperParasol
|
||||||
|
Umbrella_AssassinSuit
|
||||||
|
Umbrella_Lettuce
|
||||||
|
Umbrella_Vendetta
|
||||||
|
|
||||||
|
|
||||||
|
Wrap_SnowNinjaDark
|
||||||
|
Wrap_333_StealthWoodland
|
||||||
|
Wrap_UnknownNetwork
|
||||||
|
Wrap_DyedBurst
|
||||||
|
Wrap_210_Thermal
|
||||||
|
Wrap_303_GasCloud
|
||||||
|
|
||||||
|
|
||||||
|
Trails_ID_059_Sony2
|
||||||
|
Trails_ID_123_TacticalWoodlandBlue
|
||||||
|
Trails_ID_150_Avalanche
|
||||||
|
|
||||||
|
|
||||||
|
OT11Banner
|
||||||
|
OT10Banner
|
||||||
|
OT9Banner
|
||||||
|
OT8Banner
|
||||||
|
OT7Banner
|
||||||
|
OT6Banner
|
||||||
|
OT5Banner
|
||||||
|
OT4Banner
|
||||||
|
OT3Banner
|
||||||
|
OT2Banner
|
||||||
|
OT1Banner
|
||||||
|
OtherBanner51
|
||||||
|
BRSeason01
|
||||||
|
NewsletterBanner
|
||||||
|
Winter2018Krampus
|
||||||
|
Winter2018BearTrapFoot
|
||||||
|
Winter2018Cooker
|
||||||
|
Winter2018SnowmanBuried
|
||||||
|
Winter2018CrownFlame
|
||||||
|
Winter2018IcicleCluster
|
||||||
|
Winter2018Tower
|
||||||
|
Winter2018Wave30Complete
|
||||||
|
Winter2018GingerbreadMan
|
||||||
|
StarlightBanner6
|
||||||
|
StarlightBanner5
|
||||||
|
StarlightBanner4
|
||||||
|
StarlightBanner3
|
||||||
|
StarlightBanner2
|
||||||
|
StarlightBanner1
|
||||||
|
EnduranceWave30Theater04
|
||||||
|
EnduranceWave30Theater03
|
||||||
|
EnduranceWave30Theater02
|
||||||
|
EnduranceWave30Theater01
|
||||||
|
WargamesTprifts
|
||||||
|
WargamesTiki
|
||||||
|
WargamesPods
|
||||||
|
SurvivalBannerStorm2018Med
|
||||||
|
HordeBanner2018TwinePeaks
|
||||||
|
SurvivalBannerStorm2018Stonewood
|
||||||
|
WargamesAnomaly
|
||||||
|
WargamesMeteor
|
||||||
|
WargamesTornado
|
||||||
|
AchievementUnspeakableHorrors
|
||||||
|
AchievementWorldExplorer
|
||||||
|
AchievementGuardianAngel
|
||||||
|
AchievementPlaysWellWithOthers
|
||||||
|
AchievementTalentedBuilder
|
||||||
|
AchievementGoGnome
|
||||||
|
AchievementLootLegend
|
||||||
|
SurvivalBannerPlankertonComplete
|
||||||
|
SurvivalBannerCannyValleyComplete
|
||||||
|
SurvivalBannerStonewoodComplete
|
||||||
|
InfluencerBanner1
|
||||||
|
InfluencerBanner2
|
||||||
|
InfluencerBanner3
|
||||||
|
InfluencerBanner4
|
||||||
|
InfluencerBanner5
|
||||||
|
InfluencerBanner6
|
||||||
|
InfluencerBanner7
|
||||||
|
InfluencerBanner8
|
||||||
|
InfluencerBanner9
|
||||||
|
InfluencerBanner10
|
||||||
|
InfluencerBanner11
|
||||||
|
InfluencerBanner12
|
||||||
|
InfluencerBanner13
|
||||||
|
InfluencerBanner14
|
||||||
|
InfluencerBanner15
|
||||||
|
InfluencerBanner16
|
||||||
|
InfluencerBanner17
|
||||||
|
InfluencerBanner18
|
||||||
|
InfluencerBanner19
|
||||||
|
InfluencerBanner20
|
||||||
|
InfluencerBanner21
|
||||||
|
InfluencerBanner22
|
||||||
|
InfluencerBanner23
|
||||||
|
InfluencerBanner24
|
||||||
|
InfluencerBanner25
|
||||||
|
InfluencerBanner26
|
||||||
|
InfluencerBanner27
|
||||||
|
InfluencerBanner28
|
||||||
|
InfluencerBanner29
|
||||||
|
InfluencerBanner30
|
||||||
|
InfluencerBanner31
|
||||||
|
InfluencerBanner32
|
||||||
|
InfluencerBanner33
|
||||||
|
InfluencerBanner34
|
||||||
|
InfluencerBanner35
|
||||||
|
InfluencerBanner36
|
||||||
|
InfluencerBanner37
|
||||||
|
InfluencerBanner38
|
||||||
|
InfluencerBanner39
|
||||||
|
InfluencerBanner40
|
||||||
|
InfluencerBanner41
|
||||||
|
InfluencerBanner42
|
||||||
|
InfluencerBanner43
|
||||||
|
InfluencerBanner44
|
||||||
|
InfluencerBanner45
|
||||||
|
InfluencerBanner46
|
||||||
|
InfluencerBanner47
|
||||||
|
InfluencerBanner48
|
||||||
|
InfluencerBanner49
|
||||||
|
InfluencerBanner50
|
||||||
|
InfluencerBanner51
|
||||||
|
InfluencerBanner52
|
||||||
|
InfluencerBanner53
|
||||||
|
InfluencerBanner54
|
||||||
|
InfluencerBanner55
|
||||||
|
InfluencerBanner56
|
||||||
|
InfluencerBanner57
|
||||||
|
InfluencerBanner58
|
||||||
|
BRS22_Showdown_Mae
|
||||||
|
FounderTier5Banner1
|
||||||
|
FounderTier5Banner2
|
||||||
|
FounderTier5Banner3
|
||||||
|
FounderTier5Banner4
|
||||||
|
FounderTier5Banner5
|
||||||
|
FounderTier4Banner1
|
||||||
|
FounderTier4Banner2
|
||||||
|
FounderTier4Banner3
|
||||||
|
FounderTier4Banner4
|
||||||
|
FounderTier4Banner5
|
||||||
|
FounderTier3Banner1
|
||||||
|
FounderTier3Banner2
|
||||||
|
FounderTier3Banner3
|
||||||
|
FounderTier3Banner4
|
||||||
|
FounderTier3Banner5
|
||||||
|
FounderTier2Banner1
|
||||||
|
FounderTier2Banner2
|
||||||
|
FounderTier2Banner3
|
||||||
|
FounderTier2Banner4
|
||||||
|
FounderTier2Banner5
|
||||||
|
FounderTier1Banner1
|
||||||
|
FounderTier1Banner2
|
||||||
|
FounderTier1Banner3
|
||||||
|
FounderTier1Banner4
|
||||||
|
FounderTier1Banner5
|
||||||
|
SurvivalBannerHolidayHard
|
||||||
|
SurvivalBannerHolidayMed
|
||||||
|
SurvivalBannerHolidayEasy
|
||||||
|
SurvivalBannerStorm2018Hard
|
||||||
|
SurvivalBannerStorm2018Med
|
||||||
|
SurvivalBannerStorm2018Easy
|
||||||
|
BRS10Level100
|
||||||
|
BRS9Lvl100
|
||||||
|
BRS8Level100
|
||||||
|
NewsletterBanne
|
||||||
|
BRWorldCup2019
|
||||||
|
BRS23_FNCS_Drops
|
||||||
|
BRS9Doggus
|
||||||
|
BRS9Cattus
|
||||||
|
After Width: | Height: | Size: 7.1 KiB |
|
After Width: | Height: | Size: 3.0 MiB |
|
After Width: | Height: | Size: 2.9 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
|
After Width: | Height: | Size: 2.8 MiB |
|
After Width: | Height: | Size: 3.2 MiB |
@@ -0,0 +1,148 @@
|
|||||||
|
Pickaxe_ID_376_FNCS
|
||||||
|
Pickaxe_FNCS_S32
|
||||||
|
CID_017_Athena_Commando_M
|
||||||
|
CID_028_Athena_Commando_F
|
||||||
|
Pickaxe_Lockjaw
|
||||||
|
Glider_ID_001
|
||||||
|
|
||||||
|
|
||||||
|
CID_619_Athena_Commando_F_TechLlama
|
||||||
|
CID_035_Athena_Commando_M_Medieval
|
||||||
|
CID_039_Athena_Commando_F_Disco
|
||||||
|
CID_434_Athena_Commando_F_StealthHonor
|
||||||
|
CID_757_Athena_Commando_F_WildCat
|
||||||
|
CID_175_Athena_Commando_M_Celestial
|
||||||
|
CID_703_Athena_Commando_M_Cyclone
|
||||||
|
CID_761_Athena_Commando_M_CycloneSpace
|
||||||
|
CID_515_Athena_Commando_M_BarbequeLarry
|
||||||
|
CID_259_Athena_Commando_M_StreetOps
|
||||||
|
|
||||||
|
|
||||||
|
CID_A_215_Athena_Commando_F_SunriseCastle_48TIZ
|
||||||
|
CID_A_381_Athena_Commando_F_CactusRocker_3HTBV
|
||||||
|
Character_TigerRootFame
|
||||||
|
Character_Hitman_Dark
|
||||||
|
Character_VoltaicHuntress
|
||||||
|
Character_FallValleyBlink
|
||||||
|
Character_FallValleyCharge
|
||||||
|
Character_UpbeatIguana_D
|
||||||
|
Character_UpbeatIguana
|
||||||
|
CID_993_Athena_Commando_M_TyphoonRobot_2YRGV
|
||||||
|
Character_StallionAviator
|
||||||
|
CID_530_Athena_Commando_F_BlackMonday_1BV6J
|
||||||
|
CID_A_138_Athena_Commando_F_Foray_YQPB0
|
||||||
|
CID_A_205_Athena_Commando_F_TextileRam_GMRJ0
|
||||||
|
CID_A_206_Athena_Commando_F_TextileSparkle_V8YSA
|
||||||
|
CID_A_207_Athena_Commando_M_TextileKnight_9TE8L
|
||||||
|
CID_A_208_Athena_Commando_M_TextilePup_C85OD
|
||||||
|
CID_424_Athena_Commando_M_Vigilante
|
||||||
|
CID_423_Athena_Commando_F_Painter
|
||||||
|
CID_A_266_Athena_Commando_F_Grandeur_9CO1M
|
||||||
|
CID_A_265_Athena_Commando_M_Grandeur_TBC0O
|
||||||
|
Character_Hitman_Dark
|
||||||
|
Character_BlueMystery_Dark
|
||||||
|
Character_PinkTrooperDark
|
||||||
|
Character_DarkVogue
|
||||||
|
CID_A_256_Athena_Commando_F_UproarBraids_8IOZW
|
||||||
|
CID_A_329_Athena_Commando_F_Uproar_I5N5Z
|
||||||
|
CID_A_385_Athena_Commando_F_Rumble
|
||||||
|
CID_A_162_Athena_Commando_F_Quarrel_E5D63
|
||||||
|
CID_A_161_Athena_Commando_M_Quarrel_SLXQG
|
||||||
|
CID_A_384_Athena_Commando_M_Rumble
|
||||||
|
CID_A_024_Athena_Commando_F_Skirmish_QW2BQ
|
||||||
|
CID_A_023_Athena_Commando_M_Skirmish_W1N7H
|
||||||
|
CID_478_Athena_Commando_F_WorldCup
|
||||||
|
Character_SpeedDialBattle
|
||||||
|
CID_704_Athena_Commando_F_LollipopTrickster
|
||||||
|
CID_715_Athena_Commando_F_TwinDark
|
||||||
|
CID_A_047_Athena_Commando_F_Windwalker
|
||||||
|
CID_805_Athena_Commando_F_PunkDevilSummer
|
||||||
|
CID_801_Athena_Commando_F_GolfSummer
|
||||||
|
CID_650_Athena_Commando_F_HolidayPJ_B
|
||||||
|
Character_FauxVenom
|
||||||
|
CID_365_Athena_Commando_M_LuckyRider
|
||||||
|
CID_512_Athena_Commando_F_CubePaintRedKnight
|
||||||
|
CID_653_Athena_Commando_F_UglySweaterFrozen
|
||||||
|
Character_BrightIon
|
||||||
|
CID_216_Athena_Commando_F_Medic
|
||||||
|
CID_A_338_Athena_Commando_F_Galactic_HN9D
|
||||||
|
Character_RedOasisPomegranate
|
||||||
|
Character_RedOasisApricot
|
||||||
|
CID_819_Athena_Commando_F_NeonTightSuit_B
|
||||||
|
Character_SuperNovaTaro
|
||||||
|
CID_A_096_Athena_Commando_F_TaxiUpgradedMulticolor
|
||||||
|
CID_A_388_Athena_Commando_F_Lyrical
|
||||||
|
CID_A_387_Athena_Commando_M_Lyrical
|
||||||
|
CID_861_Athena_Commando_F_Elastic_B
|
||||||
|
CID_A_250_Athena_Commando_F_ZombieElastic_B
|
||||||
|
CID_A_443_Athena_Commando_F_PennantSeasOne_C
|
||||||
|
CID_A_444_Athena_Commando_F_PennantSeasOne_D
|
||||||
|
CID_A_441_Athena_Commando_F_PennantSeasOne
|
||||||
|
|
||||||
|
|
||||||
|
CID_065_Athena_Commando_F_SkiGirl_FRA
|
||||||
|
CID_062_Athena_Commando_F_SkiGirl_USA
|
||||||
|
CID_066_Athena_Commando_F_SkiGirl_GER
|
||||||
|
CID_064_Athena_Commando_F_SkiGirl_GBR
|
||||||
|
CID_063_Athena_Commando_F_SkiGirl_CAN
|
||||||
|
CID_068_Athena_Commando_F_SkiGirl_KOR
|
||||||
|
|
||||||
|
|
||||||
|
Character_ReconExpert_FNCS
|
||||||
|
Character_GarbageFNCS
|
||||||
|
Character_TreasureHunterFashionsFNCS
|
||||||
|
Character_LeatherKey
|
||||||
|
CID_888_Athena_Commando_F_ChOneBanshee
|
||||||
|
CID_889_Athena_Commando_F_ChOneWildcat
|
||||||
|
CID_884_Athena_Commando_F_ChOneRamirez
|
||||||
|
CID_885_Athena_Commando_M_ChOneHawk
|
||||||
|
|
||||||
|
|
||||||
|
BID_138_Celestial
|
||||||
|
BID_004_BlackKnight
|
||||||
|
BID_229_LuckyRiderMale
|
||||||
|
BID_468_Cyclone
|
||||||
|
BID_273_AssassinSuitCoin
|
||||||
|
|
||||||
|
|
||||||
|
Pickaxe_ID_294_CandyCane
|
||||||
|
Pickaxe_ID_508_HistorianMale_6BQSW
|
||||||
|
Pickaxe_ID_363_LollipopTricksterFemale
|
||||||
|
HalloweenScythe
|
||||||
|
Pickaxe_ID_015_HolidayCandyCane
|
||||||
|
Pickaxe_ID_599_CavernFemale
|
||||||
|
Pickaxe_ID_804_FNCSS20Male
|
||||||
|
Pickaxe_ID_138_Gnome
|
||||||
|
Pickaxe_SlowBurn
|
||||||
|
Pickaxe_IronBlaze
|
||||||
|
Pickaxe_ID_074_SharpDresser
|
||||||
|
Pickaxe_ID_014_WinterCamo
|
||||||
|
Pickaxe_ID_359_CycloneMale
|
||||||
|
Pickaxe_ID_475_ChOnePickaxe
|
||||||
|
|
||||||
|
|
||||||
|
EID_Fresh
|
||||||
|
EID_Floss
|
||||||
|
EID_TakeTheL
|
||||||
|
EID_CycloneHeadBang
|
||||||
|
EID_SpeedDial
|
||||||
|
EID_JanuaryBop
|
||||||
|
EID_Devotion
|
||||||
|
EID_Laugh
|
||||||
|
EID_Griddles
|
||||||
|
EID_Coping
|
||||||
|
EID_Cyclone
|
||||||
|
EID_JanuaryBop
|
||||||
|
EID_Punctual
|
||||||
|
EID_Breakdance2
|
||||||
|
EID_Jaywalking
|
||||||
|
EID_PlayerEleven
|
||||||
|
EID_HipHop01
|
||||||
|
EID_GoodVibes
|
||||||
|
EID_SandwichBop
|
||||||
|
EID_LetsPlay
|
||||||
|
|
||||||
|
|
||||||
|
Glider_ID_314_SpaceChimpMale
|
||||||
|
Glider_Warthog
|
||||||
|
Glider_ID_244_ChOneGlider
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
import os
|
||||||
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 14 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 8.0 KiB |
|
After Width: | Height: | Size: 13 KiB |
|
After Width: | Height: | Size: 18 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 21 KiB |
|
After Width: | Height: | Size: 8.6 KiB |
|
After Width: | Height: | Size: 8.5 KiB |
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 31 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 26 KiB |
|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.7 KiB |