Created
February 21, 2025 18:08
-
-
Save fastfingertips/ac4e7cc68331e87f7b61bfb4046f27ac to your computer and use it in GitHub Desktop.
Must be run in the same directory as nping. (github.com/hanshuaikang/Nping)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import tkinter as tk | |
from tkinter import ttk, messagebox | |
import subprocess | |
import os | |
import sys | |
import re | |
class DarkTheme: | |
BG_COLOR = "#1e1e1e" | |
FG_COLOR = "#ffffff" | |
ENTRY_BG = "#2d2d2d" | |
BUTTON_BG = "#0078d4" | |
BUTTON_FG = "#ffffff" | |
HOVER_BG = "#106ebe" | |
@classmethod | |
def apply(cls, root): | |
style = ttk.Style() | |
style.theme_use('clam') | |
# Configure main styles | |
style.configure('.', | |
background=cls.BG_COLOR, | |
foreground=cls.FG_COLOR, | |
fieldbackground=cls.ENTRY_BG) | |
# Configure specific elements | |
style.configure('TLabel', | |
background=cls.BG_COLOR, | |
foreground=cls.FG_COLOR) | |
style.configure('TButton', | |
background=cls.BUTTON_BG, | |
foreground=cls.BUTTON_FG, | |
padding=10) | |
style.map('TButton', | |
background=[('active', cls.HOVER_BG)]) | |
style.configure('TEntry', | |
fieldbackground=cls.ENTRY_BG, | |
foreground=cls.FG_COLOR, | |
insertcolor=cls.FG_COLOR) | |
style.configure('TFrame', | |
background=cls.BG_COLOR) | |
style.configure('TCheckbutton', | |
background=cls.BG_COLOR, | |
foreground=cls.FG_COLOR) | |
style.configure('TCombobox', | |
fieldbackground=cls.ENTRY_BG, | |
background=cls.BUTTON_BG, | |
foreground=cls.FG_COLOR, | |
selectbackground=cls.BUTTON_BG, | |
selectforeground=cls.FG_COLOR) | |
class NPingGUI: | |
def __init__(self, root): | |
self.root = root | |
self.root.title("NPing GUI") | |
self.root.geometry("700x600") | |
# Apply dark theme | |
DarkTheme.apply(root) | |
self.root.configure(bg=DarkTheme.BG_COLOR) | |
# Get the directory of the script | |
if getattr(sys, 'frozen', False): | |
self.script_dir = os.path.dirname(sys.executable) | |
else: | |
self.script_dir = os.path.dirname(os.path.abspath(__file__)) | |
# Create main frame | |
main_frame = ttk.Frame(root, padding="20") | |
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) | |
# Configure grid weights | |
root.grid_rowconfigure(0, weight=1) | |
root.grid_columnconfigure(0, weight=1) | |
main_frame.grid_columnconfigure(1, weight=1) | |
# Targets | |
ttk.Label(main_frame, text="Targets (one per line):").grid(row=0, column=0, columnspan=2, sticky=tk.W, pady=(0,5)) | |
self.targets_text = tk.Text(main_frame, height=5, width=60) | |
self.targets_text.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0,15)) | |
self.targets_text.configure(bg=DarkTheme.ENTRY_BG, fg=DarkTheme.FG_COLOR, insertbackground=DarkTheme.FG_COLOR) | |
# Count | |
ttk.Label(main_frame, text="Count:").grid(row=2, column=0, sticky=tk.W, pady=5) | |
self.count_var = tk.StringVar(value="65535") | |
self.count_entry = ttk.Entry(main_frame, textvariable=self.count_var) | |
self.count_entry.grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5) | |
# Interval | |
ttk.Label(main_frame, text="Interval (seconds):").grid(row=3, column=0, sticky=tk.W, pady=5) | |
self.interval_var = tk.StringVar(value="0") | |
self.interval_entry = ttk.Entry(main_frame, textvariable=self.interval_var) | |
self.interval_entry.grid(row=3, column=1, sticky=(tk.W, tk.E), pady=5) | |
# Force IPv6 | |
self.force_ipv6_var = tk.BooleanVar() | |
self.force_ipv6_check = ttk.Checkbutton(main_frame, text="Force IPv6", variable=self.force_ipv6_var) | |
self.force_ipv6_check.grid(row=4, column=0, columnspan=2, sticky=tk.W, pady=5) | |
# Multiple | |
ttk.Label(main_frame, text="Multiple:").grid(row=5, column=0, sticky=tk.W, pady=5) | |
self.multiple_var = tk.StringVar(value="0") | |
self.multiple_entry = ttk.Entry(main_frame, textvariable=self.multiple_var) | |
self.multiple_entry.grid(row=5, column=1, sticky=(tk.W, tk.E), pady=5) | |
# View Type | |
ttk.Label(main_frame, text="View Type:").grid(row=6, column=0, sticky=tk.W, pady=5) | |
self.view_type_var = tk.StringVar(value="graph") | |
view_type_combo = ttk.Combobox(main_frame, textvariable=self.view_type_var, state='readonly') | |
view_type_combo['values'] = ('graph', 'table') | |
view_type_combo.grid(row=6, column=1, sticky=(tk.W, tk.E), pady=5) | |
# Run Button | |
self.run_button = ttk.Button(main_frame, text="Run NPing", command=self.run_nping) | |
self.run_button.grid(row=7, column=0, columnspan=2, pady=20) | |
# Command Preview | |
ttk.Label(main_frame, text="Command Preview:").grid(row=8, column=0, columnspan=2, sticky=tk.W, pady=(10,5)) | |
self.preview_text = tk.Text(main_frame, height=3, width=60) | |
self.preview_text.grid(row=9, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=(0,10)) | |
self.preview_text.configure(bg=DarkTheme.ENTRY_BG, fg=DarkTheme.FG_COLOR, insertbackground=DarkTheme.FG_COLOR) | |
# Status Label | |
self.status_label = ttk.Label(main_frame, text="") | |
self.status_label.grid(row=10, column=0, columnspan=2, pady=5) | |
# Bind events for live command preview | |
self.bind_update_events() | |
# Check if nping.exe exists | |
self.check_nping_executable() | |
def clean_url(self, url): | |
"""Remove http://, https://, paths, and query parameters from URL""" | |
# Remove protocol (http:// or https://) | |
url = re.sub(r'^https?://', '', url) | |
# Remove path, query parameters, and fragments | |
url = url.split('/')[0] # Remove everything after first / | |
url = url.split('?')[0] # Remove query parameters | |
url = url.split('#')[0] # Remove fragments | |
return url.strip() | |
def check_nping_executable(self): | |
nping_path = os.path.join(self.script_dir, "nping.exe") | |
if not os.path.exists(nping_path): | |
self.status_label.config(text=f"Warning: nping.exe not found in {self.script_dir}") | |
self.run_button.config(state="disabled") | |
else: | |
self.status_label.config(text=f"nping.exe found in {self.script_dir}") | |
def bind_update_events(self): | |
self.targets_text.bind('<KeyRelease>', self.update_command_preview) | |
self.count_entry.bind('<KeyRelease>', self.update_command_preview) | |
self.interval_entry.bind('<KeyRelease>', self.update_command_preview) | |
self.multiple_entry.bind('<KeyRelease>', self.update_command_preview) | |
self.force_ipv6_var.trace('w', lambda *args: self.update_command_preview(None)) | |
self.view_type_var.trace('w', lambda *args: self.update_command_preview(None)) | |
def build_command(self): | |
# Get targets and clean URLs | |
targets = self.targets_text.get("1.0", tk.END).strip() | |
targets = [self.clean_url(url) for url in targets.split('\n') if url.strip()] | |
targets = ' '.join(targets) | |
if not targets: | |
return "" | |
# Change directory command | |
cd_cmd = f'cd /d "{self.script_dir}" && ' | |
# Build command for nping.exe | |
cmd = f'nping.exe {targets}' | |
# Add options | |
count = self.count_var.get().strip() | |
if count and count != "65535": | |
cmd += f" -c {count}" | |
interval = self.interval_var.get().strip() | |
if interval and interval != "0": | |
cmd += f" -i {interval}" | |
if self.force_ipv6_var.get(): | |
cmd += " -6" | |
multiple = self.multiple_var.get().strip() | |
if multiple and multiple != "0": | |
cmd += f" -m {multiple}" | |
view_type = self.view_type_var.get() | |
if view_type and view_type != "graph": | |
cmd += f" -v {view_type}" | |
return cd_cmd + cmd | |
def update_command_preview(self, event): | |
cmd = self.build_command() | |
self.preview_text.delete("1.0", tk.END) | |
self.preview_text.insert("1.0", cmd) | |
def run_nping(self): | |
cmd = self.build_command() | |
if not cmd: | |
messagebox.showerror("Error", "Please enter at least one target") | |
return | |
try: | |
# Create cmd.exe command | |
full_cmd = f'cmd.exe /k "{cmd}"' | |
# Run the command in a new window | |
process = subprocess.Popen(full_cmd, creationflags=subprocess.CREATE_NEW_CONSOLE) | |
self.root.withdraw() # Hide the GUI window | |
process.wait() # Wait for the command to complete | |
self.root.deiconify() # Show the GUI window again | |
except Exception as e: | |
messagebox.showerror("Error", f"Failed to run command: {str(e)}") | |
if __name__ == "__main__": | |
root = tk.Tk() | |
app = NPingGUI(root) | |
root.mainloop() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment