emote-api / api.py
MatrixCoder0101
Test
8e8ce9f
Raw History Blame Contribute Delete
12.5 kB
# ============================================
# PRODUCTION API WITH WEBSOCKET - api.py
# Real-time team updates, no JSON storage
# ============================================
from flask import Flask, request, jsonify
from flask_cors import CORS
from flask_sock import Sock
import queue
import json
import time
app = Flask(__name__)
CORS(app)
sock = Sock(app)
command_queue = queue.Queue()
# WebSocket clients list
websocket_clients = []
# ============================================
# WEBSOCKET - Real-time Team Updates
# ============================================
@sock.route('/ws')
def websocket(ws):
"""WebSocket connection for real-time updates"""
print(f"[WS] Client connected")
websocket_clients.append(ws)
try:
# Send initial team status
team_status = get_live_team_status()
ws.send(json.dumps({
'type': 'initial',
'data': team_status
}))
# Keep connection alive
while True:
# Receive messages from client (optional)
message = ws.receive(timeout=30)
if message:
data = json.loads(message)
# Handle client requests
if data.get('type') == 'get_team':
team_status = get_live_team_status()
ws.send(json.dumps({
'type': 'team_update',
'data': team_status
}))
except Exception as e:
print(f"[WS] Client disconnected: {e}")
finally:
if ws in websocket_clients:
websocket_clients.remove(ws)
print(f"[WS] Client removed")
def broadcast_team_update(event_type, data):
"""Broadcast team updates to all connected WebSocket clients"""
# DEBUG: Log what we're sending
if event_type in ['member_joined', 'member_left']:
player = data.get('player', {})
print(f"[WS→] {event_type}: {player.get('name')} (UID: {player.get('uid')})")
message = json.dumps({
'type': event_type,
'data': data,
'timestamp': time.time()
}, ensure_ascii=False) # Important for Unicode characters
disconnected = []
sent_count = 0
for client in websocket_clients:
try:
client.send(message)
sent_count += 1
except Exception as e:
print(f"[WS→] Failed to send to client: {e}")
disconnected.append(client)
if sent_count > 0:
print(f"[WS→] Sent to {sent_count} client(s)")
# Remove disconnected clients
for client in disconnected:
if client in websocket_clients:
websocket_clients.remove(client)
# ============================================
# JOIN TEAM API
# ============================================
@app.route('/join', methods=['GET', 'POST'])
def join_team():
"""Join a team using teamcode"""
try:
if request.method == 'GET':
teamcode = request.args.get('teamcode')
else:
data = request.get_json(silent=True)
teamcode = data.get('teamcode') if data else None
if not teamcode:
return jsonify({
'success': False,
'message': 'teamcode is required'
}), 400
command_queue.put({
'type': 'join',
'teamcode': teamcode
})
return jsonify({
'success': True,
'message': 'Join command queued',
'teamcode': teamcode
})
except Exception as e:
return jsonify({
'success': False,
'message': str(e)
}), 500
# ============================================
# EMOTE API
# ============================================
@app.route('/emote', methods=['POST'])
def send_emote():
"""Send emote to players (bot must be in team)"""
try:
data = request.get_json(silent=True)
if not data:
return jsonify({
'success': False,
'message': 'JSON body required'
}), 400
uids = data.get('uids')
emote_code = data.get('emote_code')
if not emote_code:
return jsonify({
'success': False,
'message': 'emote_code is required'
}), 400
if not isinstance(uids, list) or len(uids) == 0:
return jsonify({
'success': False,
'message': 'uids must be a non-empty array'
}), 400
if len(uids) > 5:
return jsonify({
'success': False,
'message': 'Maximum 5 UIDs allowed per request'
}), 400
# Check if bot is in team (LIVE CHECK)
team_status = get_live_team_status()
if not team_status['in_team']:
return jsonify({
'success': False,
'message': 'Bot is not in any team. Join a team first.',
'in_team': False
}), 400
# Queue emote command
command_queue.put({
'type': 'emote',
'uids': uids,
'emote_code': emote_code
})
return jsonify({
'success': True,
'message': f'Emote queued for {len(uids)} player(s)',
'uids': uids,
'emote_code': emote_code,
'in_team': True
})
except Exception as e:
return jsonify({
'success': False,
'message': str(e)
}), 500
# ============================================
# EMOTE ALL TEAM MEMBERS
# ============================================
@app.route('/emote/team', methods=['POST'])
def emote_team():
"""Send emote to all team members"""
try:
data = request.get_json(silent=True)
if not data:
return jsonify({
'success': False,
'message': 'JSON body required'
}), 400
emote_code = data.get('emote_code')
if not emote_code:
return jsonify({
'success': False,
'message': 'emote_code is required'
}), 400
# Get LIVE team status
team_status = get_live_team_status()
if not team_status['in_team']:
return jsonify({
'success': False,
'message': 'Bot is not in any team',
'in_team': False
}), 400
if not team_status.get('members'):
return jsonify({
'success': False,
'message': 'No team members found',
'in_team': True
}), 400
uids = [m['uid'] for m in team_status['members']]
# Queue emote for all members
command_queue.put({
'type': 'emote',
'uids': uids,
'emote_code': emote_code
})
return jsonify({
'success': True,
'message': f'Emote queued for all {len(uids)} team members',
'uids': uids,
'emote_code': emote_code,
'team_size': len(uids)
})
except Exception as e:
return jsonify({
'success': False,
'message': str(e)
}), 500
# ============================================
# GET TEAM MEMBERS - LIVE DATA
# ============================================
@app.route('/team/members', methods=['GET'])
def get_team_members():
"""Get current team members - LIVE from memory, not JSON"""
try:
team_status = get_live_team_status()
# Bot is NOT in team
if not team_status['in_team']:
return jsonify({
'success': False,
'message': 'Bot is not in any team',
'in_team': False,
'members': [],
'total_members': 0
})
# Bot IS in team - return LIVE data
return jsonify({
'success': True,
'message': 'Team members retrieved',
'in_team': True,
'total_members': team_status['total_members'],
'leader_uid': team_status['leader_uid'],
'members': team_status['members']
})
except Exception as e:
return jsonify({
'success': False,
'message': str(e)
}), 500
# ============================================
# BOT STATUS
# ============================================
@app.route('/status', methods=['GET'])
def bot_status():
"""Get bot connection status"""
try:
from main import online_writer, whisper_writer, key, iv, region
connections = {
'online': online_writer is not None,
'chat': whisper_writer is not None,
'authenticated': key is not None and iv is not None,
'region': region
}
team_status = get_live_team_status()
return jsonify({
'success': True,
'bot_online': connections['online'] and connections['chat'],
'connections': connections,
'team': team_status,
'queue_size': command_queue.qsize(),
'ws_clients': len(websocket_clients)
})
except ImportError:
return jsonify({
'success': False,
'message': 'Bot not running',
'bot_online': False
}), 503
# ============================================
# HOME / API INFO
# ============================================
@app.route('/', methods=['GET'])
def home():
"""API documentation"""
return jsonify({
'name': 'FF Emote Bot API',
'version': '2.0',
'status': 'online',
'websocket': 'ws://host:5000/ws',
'endpoints': {
'POST /join': 'Join team - Body: {"teamcode": "ABC123"}',
'POST /emote': 'Send emote - Body: {"uids": ["123"], "emote_code": "909000001"}',
'POST /emote/team': 'Emote all team - Body: {"emote_code": "909000001"}',
'GET /team/members': 'Get team members (LIVE)',
'GET /status': 'Bot status',
'WS /ws': 'WebSocket for real-time updates'
}
})
# ============================================
# HELPER FUNCTIONS - LIVE DATA FROM MEMORY
# ============================================
def get_live_team_status():
"""Get LIVE team status from bot memory (not JSON file)"""
try:
from main import team_collection_active, team_members_data, current_team_leader
# Check if bot is actually in a team RIGHT NOW
in_team = team_collection_active and len(team_members_data) > 0
if not in_team:
return {
'in_team': False,
'total_members': 0,
'leader_uid': None,
'members': []
}
return {
'in_team': True,
'total_members': len(team_members_data),
'leader_uid': str(current_team_leader) if current_team_leader else None,
'members': team_members_data
}
except:
return {
'in_team': False,
'total_members': 0,
'leader_uid': None,
'members': []
}
# ============================================
# RUN SERVER
# ============================================
if __name__ == '__main__':
print("""
╔══════════════════════════════════════════════╗
β•‘ FF Emote Bot API - Production v2.0 β•‘
β•‘ with WebSocket Support β•‘
β•šβ•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•β•
πŸ“‘ HTTP API: http://0.0.0.0:5000
πŸ”Œ WebSocket: ws://0.0.0.0:5000/ws
Endpoints:
β€’ POST /join - Join team
β€’ POST /emote - Send emote (requires team)
β€’ POST /emote/team - Emote all team members
β€’ GET /team/members - Get team info (LIVE)
β€’ GET /status - Bot status
β€’ WS /ws - Real-time updates
""")
app.run(host='0.0.0.0', port=7860, debug=False)