mirror of
https://github.com/Murasame-Dev/McStatus-Img.git
synced 2025-12-14 12:17:59 +00:00
Upgrade
This commit is contained in:
parent
5c576c811f
commit
57a741ca17
9 changed files with 199 additions and 18 deletions
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
__pycache__/
|
||||
|
||||
*.png
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal 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
BIN
MiSans-Bold.ttf
Normal file
Binary file not shown.
76
create_image.py
Normal file
76
create_image.py
Normal 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
|
||||
|
|
@ -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
44
main.py
Normal 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
1
mc_status_api
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 7346b1f7729c7d0884f5ba705420f8a6aeb643b8
|
||||
69
motd_formatter.py
Normal file
69
motd_formatter.py
Normal 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
2
requirements.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
pillow
|
||||
mcstatus >= 12.0.5
|
||||
Loading…
Add table
Add a link
Reference in a new issue