From f0011b145c075050b3ab5076ac6cc3bf761cc02d Mon Sep 17 00:00:00 2001 From: quqiOnfree Date: Tue, 2 Sep 2025 12:34:07 +0800 Subject: [PATCH 1/6] Delete mc_status_api --- .gitmodules | 3 -- main.py | 113 -------------------------------------------------- mc_status_api | 1 - 3 files changed, 117 deletions(-) delete mode 100644 main.py delete mode 160000 mc_status_api diff --git a/.gitmodules b/.gitmodules index 7ff0725..e69de29 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "api"] - path = mc_status_api - url = https://github.com/Murasame-Dev/McStatus-API.git diff --git a/main.py b/main.py deleted file mode 100644 index f3cc3eb..0000000 --- a/main.py +++ /dev/null @@ -1,113 +0,0 @@ -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 - -import base64 -import asyncio - -BACKGROUND_URL = "https://www.loliapi.com/acg/" -DEFAULT_ICON = "./minecraft-creeper-face.png" - -async def get_icon_image(url: str): - if url.startswith("http"): - icon_data = await download_image_with_httpx_auto_redirect(url) - if icon_data: - return icon_data - else: - return None - else: - def read_file(path): - with open(path, "rb") as f: - return f.read() - loop = asyncio.get_event_loop() - return await loop.run_in_executor(None, read_file, url) - -async def generate_java_status_image(addr: str): - loop = asyncio.get_event_loop() - try: - ip, type = await loop.run_in_executor(None, dns_lookup, addr) - status = await loop.run_in_executor(None, java_status, ip) - data = format_java_data(ip, type, status) - except Exception as e: - print(f"查询服务器时出错: {e}") - return - - background_data = await download_image_with_httpx_auto_redirect(BACKGROUND_URL) - if not background_data: - background_data = None - - icon_data = await get_icon_image(DEFAULT_ICON) - - motd_list = data['motd'].split("\n") - text_list = [ - f"ip: {data['ip']}", - f"type: {data['type']}", - f"version: {data['version']}", - f"latency: {round(data['latency'], 2)} ms", - f"players: {data['players']['online']}/{data['players']['max']}", - ] - - if status.icon: - image = await loop.run_in_executor(None, - create_image, - background_data, - base64.b64decode(status.icon.split(",")[1]), - text_list, - motd_list) - else: - image = await loop.run_in_executor(None, - create_image, - background_data, - icon_data, - text_list, - motd_list) - return image - -async def generate_bedrock_status_image(addr: str): - loop = asyncio.get_event_loop() - try: - ip, type = await loop.run_in_executor(None, dns_lookup, addr) - status = await loop.run_in_executor(None, bedrock_status, ip) - data = format_bedrock_data(ip, status) - except Exception as e: - print(f"查询服务器时出错: {e}") - return - - background_data = await download_image_with_httpx_auto_redirect(BACKGROUND_URL) - if not background_data: - background_data = None - - icon_data = await get_icon_image(DEFAULT_ICON) - - motd_list = data['motd'].split("\n") - text_list = [ - f"ip: {data['ip']}", - f"version: {data['version']}", - f"latency: {round(data['latency'], 2)} ms", - f"players: {data['players']['online']}/{data['players']['max']}", - ] - - image = await loop.run_in_executor(None, - create_image, - background_data, - icon_data, - text_list, - motd_list) - return image - -if __name__ == "__main__": - image = asyncio.run(generate_java_status_image("mc.hypixel.net")) - if image: - image.save("output_image.png") - - image = asyncio.run(generate_bedrock_status_image("play.cubecraft.net")) - if image: - image.save("output_image-be.png") \ No newline at end of file diff --git a/mc_status_api b/mc_status_api deleted file mode 160000 index 7346b1f..0000000 --- a/mc_status_api +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 7346b1f7729c7d0884f5ba705420f8a6aeb643b8 From 4485213713c5a78f407e719e605f018c281c9851 Mon Sep 17 00:00:00 2001 From: quqiOnfree Date: Tue, 2 Sep 2025 13:09:40 +0800 Subject: [PATCH 2/6] trim --- create_image.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/create_image.py b/create_image.py index a1602a1..4b31fa5 100644 --- a/create_image.py +++ b/create_image.py @@ -1,7 +1,13 @@ from PIL import Image, ImageDraw, ImageFont, ImageFilter from io import BytesIO -from motd_formatter import foramt_motd from PIL.ImageColor import getrgb +import asyncio + +from .motd_formatter import foramt_motd +from .get_background import download_image_with_httpx_auto_redirect + +BACKGROUND_URL = "https://www.loliapi.com/acg/" +DEFAULT_ICON = "./minecraft-creeper-face.png" def create_background(input: bytes, width: int, height: int): background = Image.open(BytesIO(input)) @@ -103,3 +109,17 @@ def create_image(background: bytes, font_size) return image + +async def get_icon_image(url: str): + if url.startswith("http"): + icon_data = await download_image_with_httpx_auto_redirect(url) + if icon_data: + return icon_data + else: + return None + else: + def read_file(path): + with open(path, "rb") as f: + return f.read() + loop = asyncio.get_event_loop() + return await loop.run_in_executor(None, read_file, url) From fd8031587686aea25dba8b86f49e423ba73308c8 Mon Sep 17 00:00:00 2001 From: quqiOnfree Date: Tue, 2 Sep 2025 13:12:10 +0800 Subject: [PATCH 3/6] trim --- create_image.py | 19 ------------------- get_icon.py | 19 +++++++++++++++++++ 2 files changed, 19 insertions(+), 19 deletions(-) create mode 100644 get_icon.py diff --git a/create_image.py b/create_image.py index 4b31fa5..145b2eb 100644 --- a/create_image.py +++ b/create_image.py @@ -1,13 +1,8 @@ from PIL import Image, ImageDraw, ImageFont, ImageFilter from io import BytesIO from PIL.ImageColor import getrgb -import asyncio from .motd_formatter import foramt_motd -from .get_background import download_image_with_httpx_auto_redirect - -BACKGROUND_URL = "https://www.loliapi.com/acg/" -DEFAULT_ICON = "./minecraft-creeper-face.png" def create_background(input: bytes, width: int, height: int): background = Image.open(BytesIO(input)) @@ -109,17 +104,3 @@ def create_image(background: bytes, font_size) return image - -async def get_icon_image(url: str): - if url.startswith("http"): - icon_data = await download_image_with_httpx_auto_redirect(url) - if icon_data: - return icon_data - else: - return None - else: - def read_file(path): - with open(path, "rb") as f: - return f.read() - loop = asyncio.get_event_loop() - return await loop.run_in_executor(None, read_file, url) diff --git a/get_icon.py b/get_icon.py new file mode 100644 index 0000000..008f1da --- /dev/null +++ b/get_icon.py @@ -0,0 +1,19 @@ +from .get_background import download_image_with_httpx_auto_redirect +import asyncio + +# BACKGROUND_URL = "https://www.loliapi.com/acg/" +# DEFAULT_ICON = "./minecraft-creeper-face.png" + +async def get_icon_image(url: str): + if url.startswith("http"): + icon_data = await download_image_with_httpx_auto_redirect(url) + if icon_data: + return icon_data + else: + return None + else: + def read_file(path): + with open(path, "rb") as f: + return f.read() + loop = asyncio.get_event_loop() + return await loop.run_in_executor(None, read_file, url) From 928e333e6b6e74ec8920aacae0677503d402209e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=AE=E3=83=AA=E7=8C=AB?= Date: Tue, 2 Sep 2025 17:15:41 +0800 Subject: [PATCH 4/6] add some custom settings. --- create_image.py | 34 +++++++++++++++++++++++++--------- get_icon.py | 3 --- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/create_image.py b/create_image.py index 145b2eb..93347a5 100644 --- a/create_image.py +++ b/create_image.py @@ -31,9 +31,9 @@ def draw_text_with_shadow(image: Image.Image, text: str, posx: int, posy: int, - font_size: int): + font_size: int, + font): 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') @@ -41,9 +41,9 @@ def draw_motd_text_with_shadow(image: Image.Image, text: str, posx: int, posy: int, - font_size: int): + font_size: int, + font): draw = ImageDraw.Draw(image) - font = ImageFont.truetype("./MiSans-Bold.ttf", font_size) w1, _, w2, _ = draw.textbbox((0, 0), text.strip(), font=font) weight = w2 - w1 motd_list = foramt_motd(text.strip(), weight) @@ -56,9 +56,17 @@ def draw_motd_text_with_shadow(image: Image.Image, def create_image(background: bytes, icon: str | None, text_list: list[str], - motd_list: list[str]): + motd_list: list[str], + font_url: str | None, + image_size: list[int]): # 图片尺寸 - width, height = 1200, 400 + if image_size == [0, 0] or image_size == []: + width = 1200 + height = 400 + else: + width = image_size[0] + height = image_size[1] + if (len(text_list) + len(motd_list)) * 20 + 20 > height: height = (len(text_list) + len(motd_list)) * 20 + 20 else: @@ -74,7 +82,7 @@ def create_image(background: bytes, # 添加半透明蒙版层以增强文字可读性 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: @@ -87,6 +95,12 @@ def create_image(background: bytes, image.paste(small_image, (30, height // 2 - small_size // 2)) + # 设置字体 + if font_url == None: + font = ImageFont.load_default(font_size) + else: + font = ImageFont.truetype(font_url, font_size) + text_list_size = len(text_list) motd_list_size = len(motd_list) start_posy = height / 2 - (text_list_size + motd_list_size) / 2 * font_size * 1.2 @@ -95,12 +109,14 @@ def create_image(background: bytes, motd_list[i], width // 2.5, start_posy + font_size * 1.2 * i, - int(font_size * 0.8)) + int(font_size * 0.8), + font) for i in range(text_list_size): draw_text_with_shadow(image, text_list[i], width // 2.5, start_posy + font_size * 1.2 * (i + motd_list_size), - font_size) + font_size, + font) return image diff --git a/get_icon.py b/get_icon.py index 008f1da..9da0a44 100644 --- a/get_icon.py +++ b/get_icon.py @@ -1,9 +1,6 @@ from .get_background import download_image_with_httpx_auto_redirect import asyncio -# BACKGROUND_URL = "https://www.loliapi.com/acg/" -# DEFAULT_ICON = "./minecraft-creeper-face.png" - async def get_icon_image(url: str): if url.startswith("http"): icon_data = await download_image_with_httpx_auto_redirect(url) From a37b9d14f260064a8eecc7526b323c4e6ada6a45 Mon Sep 17 00:00:00 2001 From: quqiOnfree Date: Tue, 2 Sep 2025 17:34:56 +0800 Subject: [PATCH 5/6] Trim some code --- create_image.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/create_image.py b/create_image.py index 93347a5..7a1c15c 100644 --- a/create_image.py +++ b/create_image.py @@ -31,7 +31,6 @@ def draw_text_with_shadow(image: Image.Image, text: str, posx: int, posy: int, - font_size: int, font): draw = ImageDraw.Draw(image) draw.text((posx + 2, posy + 2), text, font=font, fill='black') @@ -41,7 +40,6 @@ def draw_motd_text_with_shadow(image: Image.Image, text: str, posx: int, posy: int, - font_size: int, font): draw = ImageDraw.Draw(image) w1, _, w2, _ = draw.textbbox((0, 0), text.strip(), font=font) @@ -58,14 +56,16 @@ def create_image(background: bytes, text_list: list[str], motd_list: list[str], font_url: str | None, - image_size: list[int]): + image_size: list[int] = [0, 0]): # 图片尺寸 if image_size == [0, 0] or image_size == []: width = 1200 height = 400 - else: + elif len(image_size) == 2: width = image_size[0] height = image_size[1] + else: + assert ValueError("image_size is invalid") if (len(text_list) + len(motd_list)) * 20 + 20 > height: height = (len(text_list) + len(motd_list)) * 20 + 20 @@ -109,14 +109,12 @@ def create_image(background: bytes, motd_list[i], width // 2.5, start_posy + font_size * 1.2 * i, - int(font_size * 0.8), font) for i in range(text_list_size): draw_text_with_shadow(image, text_list[i], width // 2.5, start_posy + font_size * 1.2 * (i + motd_list_size), - font_size, font) return image From b191e02d89098044246072793edcb45bed0308ff Mon Sep 17 00:00:00 2001 From: quqiOnfree Date: Tue, 2 Sep 2025 17:44:52 +0800 Subject: [PATCH 6/6] Apply suggestions from code review --- create_image.py | 1 - 1 file changed, 1 deletion(-) diff --git a/create_image.py b/create_image.py index 7a1c15c..f58b152 100644 --- a/create_image.py +++ b/create_image.py @@ -82,7 +82,6 @@ def create_image(background: bytes, # 添加半透明蒙版层以增强文字可读性 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: