MiLoader open source

MiLoader open source

GioWolf

from mcstatus.server import JavaServer

import tkinter as tk

from tkinter import filedialog, messagebox

import re

import base64

from io import BytesIO

from PIL import Image



def parse_motd(motd_data):

    """

    Converts MOTD to a string, including color codes and gradients.

    """

    if isinstance(motd_data, str):

        return motd_data  # If it's a string, return it as is.

    elif isinstance(motd_data, dict):

        # If it's a dictionary, process 'text' and 'extra'.

        text = motd_data.get("text", "")

        extra = motd_data.get("extra", [])

        for part in extra:

            text += part.get("text", "")

        return text

    return ""



def get_motd_with_colors(motd_raw):

    """

    Converts color codes to & symbols or retains HEX codes.

    """

    # Replacement of standard color codes

    color_codes = {

        "§0": "&0", "§1": "&1", "§2": "&2", "§3": "&3",

        "§4": "&4", "§5": "&5", "§6": "&6", "§7": "&7",

        "§8": "&8", "§9": "&9", "§a": "&a", "§b": "&b",

        "§c": "&c", "§d": "&d", "§e": "&e", "§f": "&f",

        "§k": "&k", "§l": "&l", "§m": "&m", "§n": "&n", "§o": "&o", "§r": "&r"

    }

    hex_pattern = r"§#[a-fA-F0-9]{6}"  # HEX color codes


    def replace_color(match):

        code = match.group(0)

        if code in color_codes:

            return color_codes[code]

        elif re.match(hex_pattern, code):

            return code.replace("§", "&")  # Replace HEX with the format &#rrggbb

        return code


    return re.sub(f"({'|'.join(color_codes.keys())}|{hex_pattern})", replace_color, motd_raw)



def fetch_motds(ip):

    """

    Fetches MOTD from the server.

    """

    try:

        server = JavaServer.lookup(ip)

        status = server.status()

        motd_data = status.description  # Fetch MOTD as data

        motd_raw = parse_motd(motd_data)  # Convert to string

        motd_with_colors = get_motd_with_colors(motd_raw)

        return [motd_with_colors]

    except Exception as e:

        return [f"Error: {e}"]



def save_motd_file(ip):

    """

    Fetches MOTD and saves it to a text file.

    """

    motds = fetch_motds(ip)

    if not motds or "Error" in motds[0]:

        messagebox.showerror("Error", motds[0] if motds else "Failed to fetch MOTD.")

        return

    file_path = filedialog.asksaveasfilename(

        title="Save MOTD as",

        defaultextension=".txt",

        filetypes=[("Text Files", "*.txt")]

    )

    if file_path:

        with open(file_path, "w", encoding="utf-8") as file:

            for idx, motd in enumerate(motds, start=1):

                file.write(f"MOTD {idx}:\n{motd}\n\n")

        messagebox.showinfo("Done", "MOTD saved successfully!")



def save_server_icon(ip):

    """

    Fetches the server icon and saves it as a PNG file.

    """

    try:

        server = JavaServer.lookup(ip)

        status = server.status()

        if status.icon:  # Use the icon attribute instead of favicon

            # Decode the base64 icon string

            icon_data = status.icon.split(",")[1]

            icon_bytes = base64.b64decode(icon_data)

            icon = Image.open(BytesIO(icon_bytes))


            # Ask the user where to save the icon

            file_path = filedialog.asksaveasfilename(

                title="Save Server Icon",

                defaultextension=".png",

                filetypes=[("PNG Image", "*.png")]

            )

            if file_path:

                icon.save(file_path, "PNG")

                messagebox.showinfo("Done", "Server icon saved successfully!")

        else:

            messagebox.showerror("Error", "No server icon found.")

    except Exception as e:

        messagebox.showerror("Error", f"Failed to fetch server icon: {e}")



# GUI creation

def main():

    root = tk.Tk()

    root.title("MiLoader by GioWolf")

    root.geometry("400x250")

    root.configure(bg="#2b2b2b")

    root.resizable(False, False)  # Make the window fixed size


    # Get the screen width and height

    screen_width = root.winfo_screenwidth()

    screen_height = root.winfo_screenheight()


    # Calculate the position to center the window

    window_width = 400

    window_height = 250

    position_top = int((screen_height - window_height) / 2)

    position_left = int((screen_width - window_width) / 2)


    # Set the window's position

    root.geometry(f'{window_width}x{window_height}+{position_left}+{position_top}')

   

    # Input field for IP

    tk.Label(root, text="Minecraft Server IP:", fg="white", bg="#2b2b2b", font=("Arial", 12)).pack(pady=10)

    ip_entry = tk.Entry(root, width=30, font=("Arial", 14))

    ip_entry.pack(pady=5)

   

    # Button to fetch MOTD

    def on_fetch_motd():

        ip = ip_entry.get().strip()

        if not ip:

            messagebox.showerror("Error", "Please enter the server IP.")

            return

        save_motd_file(ip)


    # Button to fetch the server icon

    def on_fetch_icon():

        ip = ip_entry.get().strip()

        if not ip:

            messagebox.showerror("Error", "Please enter the server IP.")

            return

        save_server_icon(ip)

   

    # Wider buttons with fixed width

    tk.Button(

        root,

        text="Download MOTD",

        command=on_fetch_motd,

        bg="#4CAF50",

        fg="white",

        font=("Arial", 12),

        activebackground="#45a049",

        width=20

    ).pack(pady=10)


    tk.Button(

        root,

        text="Download ICON",

        command=on_fetch_icon,

        bg="#2196F3",

        fg="white",

        font=("Arial", 12),

        activebackground="#1E88E5",

        width=20

    ).pack(pady=10)

   

    root.mainloop()



if __name__ == "__main__":

    main()


Report Page