Skip to content

Instantly share code, notes, and snippets.

@fastfingertips
Created February 21, 2025 18:08
Show Gist options
  • Save fastfingertips/ac4e7cc68331e87f7b61bfb4046f27ac to your computer and use it in GitHub Desktop.
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)
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