Files
gaming-image-files/usr/local/bin/ip_info.py

185 lines
5.5 KiB
Python
Executable File

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# IP Address Information Tool for Stormux
# Provides local and remote IP addresses with speech-friendly formatting
import sys
import subprocess
import re
import socket
import urllib.request
import urllib.error
import speechd
def init_speech():
"""Initialize speech client"""
try:
client = speechd.SSIPClient('ip_info')
client.set_priority(speechd.Priority.IMPORTANT)
client.set_punctuation(speechd.PunctuationMode.SOME)
return client
except Exception as e:
print(f"Could not initialize speech: {e}")
return None
def speak(client, text):
"""Speak text using speech client"""
if client:
try:
client.speak(text)
except Exception:
print(text)
else:
print(text)
def format_ip_for_speech(ip_address):
"""Format IP address for clear speech synthesis"""
if not ip_address:
return "No IP address found"
# Split IP into parts and replace dots with "dot"
parts = ip_address.split('.')
if len(parts) != 4:
return ip_address # Return as-is if not a standard IPv4
# Join with " dot " and add spaces between digits for clarity
formatted_parts = []
for part in parts:
# Add spaces between digits for better speech clarity
spaced_digits = ' '.join(part)
formatted_parts.append(spaced_digits)
return ' dot '.join(formatted_parts)
def get_local_ip():
"""Get the local IP address using multiple methods"""
# Method 1: Try to connect to a remote host to determine local IP
try:
# Create a socket and connect to a remote address
# This doesn't actually send data, just determines routing
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.connect(("8.8.8.8", 80))
local_ip = sock.getsockname()[0]
sock.close()
# Validate it's not a loopback address
if not local_ip.startswith('127.'):
return local_ip
except Exception:
pass
# Method 2: Parse ip route command output
try:
result = subprocess.run(['ip', 'route', 'get', '8.8.8.8'],
capture_output=True, text=True, check=True)
# Look for "src" in the output
match = re.search(r'src\s+(\d+\.\d+\.\d+\.\d+)', result.stdout)
if match:
return match.group(1)
except Exception:
pass
# Method 3: Parse ip addr show output for common network interfaces
try:
result = subprocess.run(['ip', 'addr', 'show'],
capture_output=True, text=True, check=True)
# Look for inet addresses that are not loopback
# Common patterns: 192.168.x.x, 10.x.x.x, 172.16-31.x.x
pattern = r'inet\s+(\d+\.\d+\.\d+\.\d+)/\d+'
matches = re.findall(pattern, result.stdout)
for ip in matches:
# Skip loopback
if ip.startswith('127.'):
continue
# Prefer common private network ranges
if (ip.startswith('192.168.') or
ip.startswith('10.') or
re.match(r'^172\.(1[6-9]|2[0-9]|3[01])\.', ip)):
return ip
# If no private IPs found, return the first non-loopback
for ip in matches:
if not ip.startswith('127.'):
return ip
except Exception:
pass
# Method 4: Fallback using hostname
try:
hostname = socket.gethostname()
return socket.gethostbyname(hostname)
except Exception:
pass
return None
def get_remote_ip():
"""Get the remote/public IP address"""
services = [
'https://icanhazip.com',
'https://ipecho.net/plain',
'https://ifconfig.me/ip',
'https://api.ipify.org'
]
for service in services:
try:
with urllib.request.urlopen(service, timeout=10) as response:
ip = response.read().decode('utf-8').strip()
# Validate it looks like an IP address
if re.match(r'^\d+\.\d+\.\d+\.\d+$', ip):
return ip
except Exception:
continue
return None
def main():
if len(sys.argv) != 2 or sys.argv[1] not in ['local', 'remote']:
print("Usage: ip_info.py [local|remote]")
sys.exit(1)
mode = sys.argv[1]
speech_client = init_speech()
if mode == 'local':
print("Getting local IP address...")
ip = get_local_ip()
if ip:
formatted_ip = format_ip_for_speech(ip)
message = f"Local IP address: {formatted_ip}"
speak(speech_client, message)
print(f"Local IP: {ip}")
else:
message = "Could not determine local IP address"
speak(speech_client, message)
print(message)
elif mode == 'remote':
print("Getting remote IP address...")
ip = get_remote_ip()
if ip:
formatted_ip = format_ip_for_speech(ip)
message = f"Remote IP address: {formatted_ip}"
speak(speech_client, message)
print(f"Remote IP: {ip}")
else:
message = "Could not determine remote IP address. Check internet connection."
speak(speech_client, message)
print(message)
# Clean up speech client
if speech_client:
try:
speech_client.close()
except:
pass
if __name__ == "__main__":
main()