Intial Init

This commit is contained in:
Murasame 2025-08-16 04:50:02 +08:00
parent c197ac5d5d
commit 3dbd5e8a8e
7 changed files with 294 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
.pdm-python
/__pycache__
uv.lock
.python-version

47
BedrockServerStatus.py Normal file
View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# 此模块用于查询基岩版版服务器状态,并将其数据赋值给类以供灵活调用单个值
from mcstatus import BedrockServer
class BedrockStatus:
def __init__(self, gamemode, map_name, latency, motd, version, players, online_player, max_players):
self.gamemode = gamemode
self.map_name = map_name
self.latency = latency
self.motd = motd
self.version = version
self.players = players
self.online_player = online_player
self.max_players = max_players
def bedrock_status(ip):
try:
server = BedrockServer.lookup(ip)
print(f'正在解析: {ip}')
status = server.status()
# 将 status 属性拆分成多个变量
gamemode = status.gamemode # 游戏模式
map_name = status.map_name # 地图名
latency = status.latency # 延迟
motd = status.description # 标题
version = status.version.name # 版本
# 关于玩家信息的获取
players = status.players # 玩家总类
online_player = players.online # 在线玩家数
max_players = players.max # 最大玩家数
return BedrockStatus(
gamemode,
map_name,
latency,
motd,
version,
players,
online_player,
max_players
)
except Exception as e:
return print(f"获取服务器状态时出错: {e}")

66
FormatData.py Normal file
View file

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# 此模块用于格式化此项目的所有文本输出数据,包括那些鸡毛蒜皮的空值提示
# 格式化 Java 服务器状态的数据
def format_java_data(ip, type, status):
data = {
'ip': ip,
'type': type,
'latency': status.latency,
'motd': status.motd,
'version': status.version,
'enforces_secure_chat': status.enforces_secure_chat,
'forge_data': status.forge_data,
'players': {
'online': status.online_player,
'max': status.max_players,
'sample': status.sample_players
},
'icon': status.icon
}
return data
# 格式化基岩版服务器状态的数据
def format_bedrock_data(ip, status):
data = {
'ip': ip,
'gamemode': status.gamemode,
'map_name': status.map_name,
'latency': status.latency,
'motd': status.motd,
'version': status.version,
'players': {
'online': status.online_player,
'max': status.max_players
}
}
return data
def format_index():
message = {
"message": "欢迎使用 Minecraft 服务器状态查询 API",
"usage": {
"JavaStatus": "/java?ip=<IP> - (Required)",
"BedrockStatus": "/bedrock?ip=<IP> - (Required)"
}
}
return message
def format_java_index():
message = {
"message": "缺少 IP 参数",
"usage": "/java?ip=<IP> - (Required)"
}
return message
def format_bedrock_index():
message = {
"message": "缺少 IP 参数",
"usage": "/bedrock?ip=<IP> - (Required)"
}
return message

52
JavaServerStatus.py Normal file
View file

@ -0,0 +1,52 @@
# -*- coding: utf-8 -*-
# 此模块用于查询 Java 版服务器状态,并将其数据赋值给类以供灵活调用单个值
from mcstatus import JavaServer
class JavaStatus:
def __init__(self, enforces_secure_chat, forge_data, icon, latency, motd, version, players, online_player, max_players, sample_players):
self.enforces_secure_chat = enforces_secure_chat
self.forge_data = forge_data
self.icon = icon
self.latency = latency
self.motd = motd
self.version = version
self.players = players
self.online_player = online_player
self.max_players = max_players
self.sample_players = sample_players
def java_status(ip):
try:
print(f'正在解析: {ip}')
server = JavaServer.lookup(ip)
status = server.status()
# 将 status 属性拆分成多个变量
enforces_secure_chat = status.enforces_secure_chat # 是否开启聊天签名
forge_data = status.forge_data # FML版本
icon = status.icon # 图标,输出为 base64
latency = status.latency # 延迟
motd = status.description # 标题
version = status.version.name # 版本
# 关于玩家信息的获取
players = status.players # 玩家总类
online_player = players.online # 在线玩家数
max_players = players.max # 最大玩家数
sample_players = players.sample # 在线玩家的 ID,UUID
return JavaStatus(
enforces_secure_chat,
forge_data,
icon,
latency,
motd,
version,
players,
online_player,
max_players,
sample_players,
)
except Exception as e:
return print(f"获取服务器状态时出错: {e}")

73
app.py Normal file
View file

@ -0,0 +1,73 @@
# -*- coding: utf-8 -*-
# 重写 Flask-MCMOTD,早期版本用的是面向过程的方式进行写的一个文件写了400多行真是要爆了T.T
# API
from flask import Flask, request, jsonify
from flask_cors import CORS
# Java版查询模块
from JavaServerStatus import java_status
# 基岩版查询模块
from BedrockServerStatus import bedrock_status
# 此API优先解析 srv 记录
from dnslookup import dns_lookup
# 格式化文本
from FormatData import format_java_data, format_bedrock_data, format_index, format_java_index, format_bedrock_index
app = Flask(__name__)
app.json.sort_keys = False
app.json.ensure_ascii = False
app.json.mimetype = 'application/json;charset=UTF-8'
app.json.compact = False
CORS(app)
@app.route('/')
def index():
message = format_index()
return jsonify(message), 200
# Java 服务器状态查询
@app.route('/java')
def get_java_status():
ip = request.args.get('ip')
# 空值输出 API 用法
if not ip:
message = format_java_index()
return jsonify(message), 400
try:
ip, type = dns_lookup(ip)
print(f"解析Java版IP: {ip}, 是否为 SRV: {type}")
status = java_status(ip)
data = format_java_data(ip, type, status)
return jsonify(data), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
# 基岩版服务器状态查询
@app.route('/bedrock')
def get_bedrock_status():
ip = request.args.get('ip')
# 空值输出 API 用法
if not ip:
message = format_bedrock_index()
return jsonify(message), 400
try:
print(f"解析基岩版IP: {ip}")
status = bedrock_status(ip)
data = format_bedrock_data(ip, status)
return jsonify(data), 200
except Exception as e:
return jsonify({"error": str(e)}), 500
if __name__ == '__main__':
app.run(debug=True, port=5000)

41
dnslookup.py Normal file
View file

@ -0,0 +1,41 @@
# -*- coding: utf-8 -*-
# 此模块用于解析 SRV 记录,返回值为 IP 和 解析类型(srv 或者 normal)
import dns.resolver
def dns_lookup(ip):
# 因为第一次解析是面向于 SRV 的,所以需要做是否带端口号的判断
if ':' in ip:
type = f'normal'
return ip, type
# 自定义 DNS 解析器
resolver = dns.resolver.Resolver()
resolver.nameservers = ['223.5.5.5', '223.6.6.6'] # 添加备用DNS
resolver.timeout = 5 # 单次查询超时时间
resolver.lifetime = 10 # 总解析时间限制
try:
print(f'正在解析 SRV 记录: _minecraft._tcp.{ip}')
answers = resolver.resolve(f'_minecraft._tcp.{ip}', 'SRV')
# address 的源输出末端有沟槽的 ".",去掉它
address = str(answers[0].target).rstrip('.')
port = answers[0].port
# 拼接端口号,赋值 SRV
ip = f'{address}:{port}'
print(f'解析出 SRV 地址: {ip}')
type = f'srv'
return ip, type
except dns.resolver.NoAnswer:
print(f'无法解析SRV记录: _minecraft._tcp.{ip} (DNS服务器无答应)')
except dns.resolver.NXDOMAIN:
print(f'域名不存在SRV记录: _minecraft._tcp.{ip}')
except (dns.resolver.Timeout, dns.resolver.LifetimeTimeout):
print(f'DNS解析超时: {ip}')
except Exception as e:
print(f'DNS解析出现未知错误: {e}')
type = f'normal'
return ip, type

11
pyproject.toml Normal file
View file

@ -0,0 +1,11 @@
[project]
name = "mcstatus-api"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.13"
dependencies = [
"flask>=3.1.1",
"flask-cors>=6.0.1",
"mcstatus>=12.0.5",
]