import struct import socket import base64 import json import sys import logging.config logger = logging.getLogger(__name__) class Server: def __init__(self, data): self.description = data.get('description') # print(self.description) if isinstance(self.description, dict): # cat server if "translate" in self.description: self.description = self.description['translate'] # waterfall / bungee elif 'extra' in self.description: lines = [] description = self.description if 'extra' in description.keys(): for e in description['extra']: if "text" in e.keys(): lines.append(e['text']) total_text = " ".join(lines) self.description = total_text # normal MC else: self.description = self.description['text'] self.icon = base64.b64decode(data.get('favicon', '')[22:]) self.players = Players(data['players']).report() self.version = data['version']['name'] self.protocol = data['version']['protocol'] class Players(list): def __init__(self, data): super().__init__(Player(x) for x in data.get('sample', [])) self.max = data['max'] self.online = data['online'] def report(self): players = [] for x in self: players.append(str(x)) r_data = { 'online': self.online, 'max': self.max, 'players': players } return json.dumps(r_data) class Player: def __init__(self, data): self.id = data['id'] self.name = data['name'] def __str__(self): return self.name # For the rest of requests see wiki.vg/Protocol def ping(ip, port=25565): def read_var_int(): i = 0 j = 0 while True: k = sock.recv(1) if not k: return 0 k = k[0] i |= (k & 0x7f) << (j * 7) j += 1 if j > 5: raise ValueError('var_int too big') if not (k & 0x80): return i sock = socket.socket() try: sock.connect((ip, port)) except: pass return False try: host = ip.encode('utf-8') data = b'' # wiki.vg/Server_List_Ping data += b'\x00' # packet ID data += b'\x04' # protocol variant data += struct.pack('>b', len(host)) + host data += struct.pack('>H', port) data += b'\x01' # next state data = struct.pack('>b', len(data)) + data sock.sendall(data + b'\x01\x00') # handshake + status ping length = read_var_int() # full packet length if length < 10: if length < 0: return False else: return False sock.recv(1) # packet type, 0 for pings length = read_var_int() # string length data = b'' while len(data) != length: chunk = sock.recv(length - len(data)) if not chunk: return False data += chunk logger.debug("Server reports this data on ping: {}".format(data)) return Server(json.loads(data)) finally: sock.close()