This commit is contained in:
quqiOnfree 2025-08-26 03:15:56 +08:00
parent 5c576c811f
commit 57a741ca17
9 changed files with 199 additions and 18 deletions

3
.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
__pycache__/
*.png

3
.gitmodules vendored Normal file
View file

@ -0,0 +1,3 @@
[submodule "api"]
path = mc_status_api
url = https://github.com/Murasame-Dev/McStatus-API.git

BIN
MiSans-Bold.ttf Normal file

Binary file not shown.

76
create_image.py Normal file
View file

@ -0,0 +1,76 @@
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from io import BytesIO
from motd_formatter import foramt_motd
from PIL.ImageColor import getrgb
def create_background(input: bytes, width: int, height: int):
background = Image.open(BytesIO(input))
w1, h1, w2, h2 = background.getbbox()
midw = (w1 + w2) // 2
midh = (h1 + h2) // 2
rheight = int(height / width * w2)
rwidth = w2
if rheight > h2:
rwidth = int(width / height * h2)
rheight = h2
background = background.crop((midw - int(rwidth / 2), midh - int(rheight / 2), midw + int(rwidth / 2), midh + int(rheight / 2)))
background = background.resize((width, height), Image.Resampling.LANCZOS)
blurred_background = background.filter(ImageFilter.GaussianBlur(radius=5))
image = blurred_background
return image
def draw_text_with_shadow(image: Image.Image, text: str, posx: int, posy: int):
font_size = 14
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("./MiSans-Bold.ttf", font_size)
draw.text((posx + 2, posy + 2), text, font=font, fill='black')
draw.text((posx, posy), text, font=font, fill='white')
def draw_motd_text_with_shadow(image: Image.Image, text: str, posx: int, posy: int):
font_size = 10
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("./MiSans-Bold.ttf", font_size)
w1, _, w2, _ = draw.textbbox((0, 0), text, font=font)
weight = w2 - w1
motd_list = foramt_motd(text, weight)
for pos, color, text in motd_list:
draw.text((posx + pos + 1, posy + 1), text, font=font, fill='black')
draw.text((posx + pos, posy), text, font=font, fill=getrgb(color))
def create_image(background: bytes, icon: str | None, text_list: list[str], motd_list: list[str]):
# 图片尺寸
width, height = 600, 200
if (len(text_list) + len(motd_list)) * 20 + 20 > height:
height = len(text_list) * 20 + 20
try:
image = create_background(background, width, height)
except FileNotFoundError:
image = Image.new('RGB', (width, height), color='orange')
# 添加半透明蒙版层以增强文字可读性
overlay = Image.new('RGBA', (width, height), (0, 0, 0, 80)) # 半透明黑色蒙版
image.paste(overlay, (0, 0), overlay)
if width // 2 > height:
small_size = int(height * 0.8)
else:
small_size = width // 3
if icon == None:
small_image = Image.new('RGBA', (small_size, small_size), color='gray')
else:
small_image = Image.open(BytesIO(icon)).resize((small_size, small_size), Image.Resampling.LANCZOS)
image.paste(small_image, (30, height // 2 - small_size // 2))
text_list_size = len(text_list)
motd_list_size = len(motd_list)
for i in range(text_list_size):
draw_text_with_shadow(image, text_list[i], width // 2.5, 10 + 20 * i)
for i in range(motd_list_size):
draw_motd_text_with_shadow(image, motd_list[i], width // 2.5, 10 + 20 * (i + text_list_size))
return image

View file

@ -1,7 +1,6 @@
import httpx
import os
def download_image_with_httpx_auto_redirect(url, save_path):
def download_image_with_httpx_auto_redirect(url:str):
"""
使用httpx库自动处理重定向下载图片
@ -16,17 +15,7 @@ def download_image_with_httpx_auto_redirect(url, save_path):
# 检查状态码
if response.status_code == 200:
# 确保保存目录存在
os.makedirs(os.path.dirname(save_path), exist_ok=True)
# 写入文件
with open(save_path, 'wb') as f:
f.write(response.content)
Background = response.content
print(f"图片已成功保存到: {save_path}")
print(f"最终URL: {response.url}") # 显示最终重定向后的URL
return Background
else:
print(f"请求失败,状态码: {response.status_code}")
@ -35,9 +24,3 @@ def download_image_with_httpx_auto_redirect(url, save_path):
except Exception as e:
print(f"下载失败: {e}")
return False
# 使用示例
if __name__ == "__main__":
image_url = "https://www.loliapi.com/acg/"
save_path = "images/downloaded_image.jpg"
download_image_with_httpx_auto_redirect(image_url, save_path)

44
main.py Normal file
View file

@ -0,0 +1,44 @@
from get_background import download_image_with_httpx_auto_redirect
from create_image import create_image
# Java版查询模块
from mc_status_api.JavaServerStatus import java_status
# 基岩版查询模块
from mc_status_api.BedrockServerStatus import bedrock_status
# 此API优先解析 srv 记录
from mc_status_api.dnslookup import dns_lookup
# 格式化文本
from mc_status_api.FormatData import format_java_data, format_bedrock_data, format_index, format_java_index, format_bedrock_index
import base64
BACKGROUND_URL = "https://www.loliapi.com/acg/"
def generate_java_status_image(addr: str, output_image_path: str):
try:
ip, type = dns_lookup(addr)
status = java_status(ip)
data = format_java_data(ip, type, status)
except Exception as e:
print(f"查询服务器时出错: {e}")
return
background_data = download_image_with_httpx_auto_redirect(BACKGROUND_URL)
if not background_data:
background_data = None
motd_list = data['motd'].split("\n")
text_list = [
f"ip: {data["ip"]}",
f"type: {data['type']}",
f"version: {data['version']}",
f"latency: {data['latency']} ms",
f"players: {data['players']['online']}/{data['players']['max']}",
]
image = create_image(background_data, base64.b64decode(status.icon.split(",")[1]), text_list, motd_list)
image.save(output_image_path)
if __name__ == "__main__":
generate_java_status_image("mc.hypixel.net", "output_image.png")

1
mc_status_api Submodule

@ -0,0 +1 @@
Subproject commit 7346b1f7729c7d0884f5ba705420f8a6aeb643b8

69
motd_formatter.py Normal file
View file

@ -0,0 +1,69 @@
def format_color(color_code: str) -> str:
"""
将Minecraft颜色代码转换为对应的颜色名称
Args:
color_code (str): Minecraft颜色代码单个字符
Returns:
str: 对应的颜色名称
"""
color_map = {
'0': '#000000',
'1': '#0000AA',
'2': '#00AA00',
'3': '#00AAAA',
'4': '#AA0000',
'5': '#AA00AA',
'6': '#FFAA00',
'7': '#AAAAAA',
'8': '#555555',
'9': '#5555FF',
'a': '#55FF55',
'b': '#55FFFF',
'c': '#FF5555',
'd': '#FF55FF',
'e': '#FFFF55',
'f': '#FFFFFF',
'g': '#DDD605',
'r': '#FFFFFF'
}
return color_map.get(color_code.lower(), 'white')
def foramt_motd(data: str, weight: int) -> list[tuple[int, str, str]]:
"""
格式化 MOTD 文本去除多余的空格和换行符
Args:
data (str): 原始 MOTD 文本
Returns:
list: 格式化后的 MOTD 文本
"""
iter = 0
character_count = 0
motd_list = []
color_state = "#FFFFFF"
data_size = len(data)
while iter < data_size:
if data[iter] == "§":
if iter + 1 < data_size:
color = data[iter + 1]
text = ""
iter += 2
character_count += 1
while iter < data_size and data[iter] != "§" and data[iter] != "\n":
text += data[iter]
iter += 1
if color != "l":
color_state = format_color(color)
motd_list.append(((iter - character_count * 2) / data_size * weight, color_state, text))
else:
iter += 1
else:
text = ""
while iter < data_size and data[iter] != "§" and data[iter] != "\n":
text += data[iter]
iter += 1
motd_list.append((len(text), "white", text))
return motd_list

2
requirements.txt Normal file
View file

@ -0,0 +1,2 @@
pillow
mcstatus >= 12.0.5