|
|
""" |
|
|
API Configuration Loader |
|
|
Loads all API sources from all_apis_merged_2025.json |
|
|
""" |
|
|
import json |
|
|
import re |
|
|
from typing import Dict, List, Any |
|
|
|
|
|
class APILoader: |
|
|
def __init__(self, config_file='all_apis_merged_2025.json'): |
|
|
self.config_file = config_file |
|
|
self.apis = {} |
|
|
self.keys = {} |
|
|
self.cors_proxies = [] |
|
|
self.load_config() |
|
|
|
|
|
def load_config(self): |
|
|
"""Load and parse the comprehensive API configuration""" |
|
|
try: |
|
|
with open(self.config_file, 'r', encoding='utf-8') as f: |
|
|
data = json.load(f) |
|
|
|
|
|
|
|
|
self.extract_keys(data) |
|
|
|
|
|
|
|
|
self.extract_cors_proxies(data) |
|
|
|
|
|
|
|
|
self.build_api_registry(data) |
|
|
|
|
|
print(f"β Loaded {len(self.apis)} API sources") |
|
|
print(f"β Found {len(self.keys)} API keys") |
|
|
print(f"β Configured {len(self.cors_proxies)} CORS proxies") |
|
|
|
|
|
except Exception as e: |
|
|
print(f"β Error loading config: {e}") |
|
|
self.load_defaults() |
|
|
|
|
|
def extract_keys(self, data): |
|
|
"""Extract API keys from configuration""" |
|
|
content = str(data) |
|
|
|
|
|
|
|
|
key_patterns = { |
|
|
'TronScan': r'TronScan[:\s]+([a-f0-9-]{36})', |
|
|
'BscScan': r'BscScan[:\s]+([A-Z0-9]{34})', |
|
|
'Etherscan': r'Etherscan[:\s]+([A-Z0-9]{34})', |
|
|
'Etherscan_2': r'Etherscan_2[:\s]+([A-Z0-9]{34})', |
|
|
'CoinMarketCap': r'CoinMarketCap[:\s]+([a-f0-9-]{36})', |
|
|
'CoinMarketCap_2': r'CoinMarketCap_2[:\s]+([a-f0-9-]{36})', |
|
|
'CryptoCompare': r'CryptoCompare[:\s]+([a-f0-9]{40})', |
|
|
} |
|
|
|
|
|
for name, pattern in key_patterns.items(): |
|
|
match = re.search(pattern, content) |
|
|
if match: |
|
|
self.keys[name] = match.group(1) |
|
|
|
|
|
def extract_cors_proxies(self, data): |
|
|
"""Extract CORS proxy URLs""" |
|
|
self.cors_proxies = [ |
|
|
'https://api.allorigins.win/get?url=', |
|
|
'https://proxy.cors.sh/', |
|
|
'https://proxy.corsfix.com/?url=', |
|
|
'https://api.codetabs.com/v1/proxy?quest=', |
|
|
'https://thingproxy.freeboard.io/fetch/' |
|
|
] |
|
|
|
|
|
def build_api_registry(self, data): |
|
|
"""Build comprehensive API registry""" |
|
|
|
|
|
|
|
|
self.apis['CoinGecko'] = { |
|
|
'name': 'CoinGecko', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coingecko.com/api/v3/ping', |
|
|
'test_field': 'gecko_says', |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
self.apis['CoinGecko_Price'] = { |
|
|
'name': 'CoinGecko Price', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd', |
|
|
'test_field': 'bitcoin', |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
self.apis['Binance'] = { |
|
|
'name': 'Binance', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.binance.com/api/v3/ping', |
|
|
'test_field': None, |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
self.apis['Binance_Price'] = { |
|
|
'name': 'Binance BTCUSDT', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.binance.com/api/v3/ticker/24hr?symbol=BTCUSDT', |
|
|
'test_field': 'symbol', |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
self.apis['CoinCap'] = { |
|
|
'name': 'CoinCap', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coincap.io/v2/assets/bitcoin', |
|
|
'test_field': 'data', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
self.apis['Coinpaprika'] = { |
|
|
'name': 'Coinpaprika', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coinpaprika.com/v1/tickers/btc-bitcoin', |
|
|
'test_field': 'id', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
self.apis['CoinLore'] = { |
|
|
'name': 'CoinLore', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coinlore.net/api/ticker/?id=90', |
|
|
'test_field': None, |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
|
|
|
self.apis['Alternative.me'] = { |
|
|
'name': 'Alternative.me', |
|
|
'category': 'sentiment', |
|
|
'url': 'https://api.alternative.me/fng/', |
|
|
'test_field': 'data', |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
|
|
|
self.apis['CryptoPanic'] = { |
|
|
'name': 'CryptoPanic', |
|
|
'category': 'news', |
|
|
'url': 'https://cryptopanic.com/api/v1/posts/?public=true', |
|
|
'test_field': 'results', |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
self.apis['Reddit_Crypto'] = { |
|
|
'name': 'Reddit Crypto', |
|
|
'category': 'news', |
|
|
'url': 'https://www.reddit.com/r/CryptoCurrency/hot.json?limit=5', |
|
|
'test_field': 'data', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
|
|
|
if 'Etherscan' in self.keys: |
|
|
self.apis['Etherscan'] = { |
|
|
'name': 'Etherscan', |
|
|
'category': 'blockchain_explorers', |
|
|
'url': f'https://api.etherscan.io/api?module=stats&action=ethsupply&apikey={self.keys["Etherscan"]}', |
|
|
'test_field': 'result', |
|
|
'key': self.keys['Etherscan'], |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
if 'BscScan' in self.keys: |
|
|
self.apis['BscScan'] = { |
|
|
'name': 'BscScan', |
|
|
'category': 'blockchain_explorers', |
|
|
'url': f'https://api.bscscan.com/api?module=stats&action=bnbsupply&apikey={self.keys["BscScan"]}', |
|
|
'test_field': 'result', |
|
|
'key': self.keys['BscScan'], |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
if 'TronScan' in self.keys: |
|
|
self.apis['TronScan'] = { |
|
|
'name': 'TronScan', |
|
|
'category': 'blockchain_explorers', |
|
|
'url': 'https://apilist.tronscanapi.com/api/system/status', |
|
|
'test_field': None, |
|
|
'key': self.keys['TronScan'], |
|
|
'priority': 1 |
|
|
} |
|
|
|
|
|
|
|
|
self.apis['Blockchair_BTC'] = { |
|
|
'name': 'Blockchair Bitcoin', |
|
|
'category': 'blockchain_explorers', |
|
|
'url': 'https://api.blockchair.com/bitcoin/stats', |
|
|
'test_field': 'data', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
self.apis['Blockchain.info'] = { |
|
|
'name': 'Blockchain.info', |
|
|
'category': 'blockchain_explorers', |
|
|
'url': 'https://blockchain.info/latestblock', |
|
|
'test_field': 'height', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
|
|
|
self.apis['Ankr_ETH'] = { |
|
|
'name': 'Ankr Ethereum', |
|
|
'category': 'rpc_nodes', |
|
|
'url': 'https://rpc.ankr.com/eth', |
|
|
'test_field': None, |
|
|
'key': None, |
|
|
'priority': 2, |
|
|
'method': 'POST' |
|
|
} |
|
|
|
|
|
self.apis['Cloudflare_ETH'] = { |
|
|
'name': 'Cloudflare ETH', |
|
|
'category': 'rpc_nodes', |
|
|
'url': 'https://cloudflare-eth.com', |
|
|
'test_field': None, |
|
|
'key': None, |
|
|
'priority': 2, |
|
|
'method': 'POST' |
|
|
} |
|
|
|
|
|
|
|
|
self.apis['1inch'] = { |
|
|
'name': '1inch', |
|
|
'category': 'defi', |
|
|
'url': 'https://api.1inch.io/v5.0/1/healthcheck', |
|
|
'test_field': None, |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
|
|
|
self.apis['Messari'] = { |
|
|
'name': 'Messari', |
|
|
'category': 'market_data', |
|
|
'url': 'https://data.messari.io/api/v1/assets/bitcoin/metrics', |
|
|
'test_field': 'data', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
self.apis['CoinDesk'] = { |
|
|
'name': 'CoinDesk', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coindesk.com/v1/bpi/currentprice.json', |
|
|
'test_field': 'bpi', |
|
|
'key': None, |
|
|
'priority': 2 |
|
|
} |
|
|
|
|
|
def load_defaults(self): |
|
|
"""Load minimal default configuration if file loading fails""" |
|
|
self.apis = { |
|
|
'CoinGecko': { |
|
|
'name': 'CoinGecko', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.coingecko.com/api/v3/ping', |
|
|
'test_field': 'gecko_says', |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
}, |
|
|
'Binance': { |
|
|
'name': 'Binance', |
|
|
'category': 'market_data', |
|
|
'url': 'https://api.binance.com/api/v3/ping', |
|
|
'test_field': None, |
|
|
'key': None, |
|
|
'priority': 1 |
|
|
} |
|
|
} |
|
|
|
|
|
def get_all_apis(self) -> Dict[str, Dict[str, Any]]: |
|
|
"""Get all configured APIs""" |
|
|
return self.apis |
|
|
|
|
|
def get_apis_by_category(self, category: str) -> Dict[str, Dict[str, Any]]: |
|
|
"""Get APIs filtered by category""" |
|
|
return {k: v for k, v in self.apis.items() if v['category'] == category} |
|
|
|
|
|
def get_categories(self) -> List[str]: |
|
|
"""Get all unique categories""" |
|
|
return list(set(api['category'] for api in self.apis.values())) |
|
|
|
|
|
def add_custom_api(self, name: str, url: str, category: str, test_field: str = None): |
|
|
"""Add a custom API source""" |
|
|
self.apis[name] = { |
|
|
'name': name, |
|
|
'category': category, |
|
|
'url': url, |
|
|
'test_field': test_field, |
|
|
'key': None, |
|
|
'priority': 3 |
|
|
} |
|
|
return True |
|
|
|
|
|
def remove_api(self, name: str): |
|
|
"""Remove an API source""" |
|
|
if name in self.apis: |
|
|
del self.apis[name] |
|
|
return True |
|
|
return False |
|
|
|
|
|
|
|
|
api_loader = APILoader() |
|
|
|