Add local and remote ip address options to Accessories menu. Fixed a bug that allowed wine32 games to show up on the Raspberry Pi.
This commit is contained in:
@@ -916,8 +916,11 @@ if __name__ == "__main__":
|
||||
menu.add_item("Arcade", "Villains From Beyond", "GAME='Villains From Beyond' startx")
|
||||
menu.add_item("Arcade", "Wicked Quest", "GAME='Wicked Quest' startx")
|
||||
menu.add_item("Arcade", "Zombowl", "GAME='Zombowl' startx")
|
||||
menu.add_item("Arcade", "Kitchen's Sink", "GAME=\"Kitchen's Sink\" startx")
|
||||
menu.add_item("Arcade", "Swamp", "GAME='Swamp' startx")
|
||||
|
||||
# Add Kitchen's Sink and Swamp only on x86_64
|
||||
if platform.machine() == "x86_64":
|
||||
menu.add_item("Arcade", "Kitchen's Sink", "GAME=\"Kitchen's Sink\" startx")
|
||||
menu.add_item("Arcade", "Swamp", "GAME='Swamp' startx")
|
||||
|
||||
# Add board and card games section
|
||||
menu.add_section("Board and Card Games")
|
||||
@@ -1009,6 +1012,8 @@ if __name__ == "__main__":
|
||||
# Add accessories section
|
||||
menu.add_section("Accessories")
|
||||
menu.add_item("Accessories", "Music Player", "/usr/local/bin/music_player.py")
|
||||
menu.add_item("Accessories", "Local IP Address", "/usr/local/bin/ip_info.py local")
|
||||
menu.add_item("Accessories", "Remote IP Address", "/usr/local/bin/ip_info.py remote")
|
||||
menu.add_item("Accessories", "Web Browser", "GAME=Brave startx")
|
||||
|
||||
# Add system section
|
||||
|
||||
Executable
+185
@@ -0,0 +1,185 @@
|
||||
#!/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()
|
||||
Reference in New Issue
Block a user