Commit 4c26f5ad authored by Robocoders's avatar Robocoders

Made Tkinter interface configurable using config.ini

parent e2d6d245
......@@ -18,3 +18,11 @@ toggle_others = smblur_shine
tease = smblur_tease
tease_all = smblur_teaseall
open = smblur_clean
[Tkinter]
window_title = SHM Cam Studio
window_width = 300
window_height = 400
button_width = 20
button_height = 2
font_size = 12
......@@ -33,15 +33,15 @@ import vlc
# Read configuration
config = configparser.ConfigParser()
config.read('config.ini')
config.read("config.ini")
# Setup logging
log_file = config.get('General', 'log_file', fallback='/tmp/streaming_control.log')
log_level = config.get('General', 'log_level', fallback='INFO')
log_file = config.get("General", "log_file", fallback="/tmp/streaming_control.log")
log_level = config.get("General", "log_level", fallback="INFO")
logging.basicConfig(
level=getattr(logging, log_level),
format='%(asctime)s - %(levelname)s - %(message)s',
format="%(asctime)s - %(levelname)s - %(message)s",
handlers=[
RotatingFileHandler(log_file, maxBytes=1024*1024, backupCount=5),
logging.StreamHandler(sys.stdout)
......@@ -53,7 +53,7 @@ logger = logging.getLogger(__name__)
flask_app = Flask(__name__)
# Command Mapping
COMMANDS = dict(config['Commands'])
COMMANDS = dict(config["Commands"])
def run_command(command):
try:
......@@ -65,13 +65,13 @@ def run_command(command):
logger.error(f"Error executing command {command}: {e}")
return f"Error: {e}"
@flask_app.route('/')
@flask_app.route("/")
def index():
return render_template('index.html', commands=COMMANDS)
return render_template("index.html", commands=COMMANDS)
@flask_app.route('/execute', methods=['POST'])
@flask_app.route("/execute", methods=["POST"])
def execute():
command_key = request.form.get('command')
command_key = request.form.get("command")
if command_key in COMMANDS:
result = run_command(COMMANDS[command_key])
......@@ -79,13 +79,13 @@ def execute():
else:
return "Invalid command", 400
@flask_app.route('/stream')
@flask_app.route("/stream")
def stream():
stream_url = config.get('Web', 'stream_url', fallback="https://192.168.42.1/HLS/record/Live.m3u8")
return render_template('stream.html', stream_url=stream_url)
stream_url = config.get("Web", "stream_url", fallback="https://192.168.42.1/HLS/record/Live.m3u8")
return render_template("stream.html", stream_url=stream_url)
def create_daemon():
if os.name == 'posix': # Unix-like systems
if os.name == "posix": # Unix-like systems
try:
# First fork
pid = os.fork()
......@@ -93,11 +93,11 @@ def create_daemon():
# Exit first parent
sys.exit(0)
except OSError as err:
logger.error(f'Fork #1 failed: {err}')
logger.error(f"Fork #1 failed: {err}")
sys.exit(1)
# Decouple from parent environment
os.chdir('/')
os.chdir("/")
os.setsid()
os.umask(0)
......@@ -108,211 +108,53 @@ def create_daemon():
# Exit from second parent
sys.exit(0)
except OSError as err:
logger.error(f'Fork #2 failed: {err}')
logger.error(f"Fork #2 failed: {err}")
sys.exit(1)
# Redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = open(os.devnull, 'r')
so = open(os.devnull, 'a+')
se = open(os.devnull, 'a+')
si = open(os.devnull, "r")
so = open(os.devnull, "a+")
se = open(os.devnull, "a+")
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
elif os.name == 'nt': # Windows
try:
# Hide the console window
si = subprocess.STARTUPINFO()
si.dwFlags |= subprocess.STARTF_USESHOWWINDOW
# Start the script as a new process
subprocess.Popen([sys.executable, __file__],
startupinfo=si,
creationflags=subprocess.CREATE_NEW_PROCESS_GROUP)
def create_tkinter_interface():
root = tk.Tk()
root.title(config.get("Tkinter", "window_title", fallback="SHM Cam Studio"))
root.geometry(f"{config.get(Tkinter, window_width, fallback=300)}x{config.get(Tkinter, window_height, fallback=400)}")
# Exit the current process
sys.exit(0)
except Exception as err:
logger.error(f'Failed to create background process: {err}')
sys.exit(1)
button_font = tkFont.Font(size=int(config.get("Tkinter", "font_size", fallback="12")))
button_width = int(config.get("Tkinter", "button_width", fallback="20"))
button_height = int(config.get("Tkinter", "button_height", fallback="2"))
else:
logger.error(f'Unsupported operating system: {os.name}')
sys.exit(1)
for command_name, command in COMMANDS.items():
button = tk.Button(root, text=command_name, command=lambda cmd=command: run_command(cmd),
font=button_font, width=button_width, height=button_height)
button.pack(pady=5)
def check_port_available(port):
"""Check if a port is available"""
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
return s.connect_ex(('localhost', port)) != 0
root.mainloop()
def run_flask_app(port=5000, daemon_mode=False):
"""Run Flask app with optional daemon mode"""
if not check_port_available(port):
logger.error(f"Port {port} is already in use")
sys.exit(1)
def run_flask():
port = config.get("Web", "port", fallback="5000")
flask_app.run(host="0.0.0.0", port=int(port))
logger.info(f"Starting Flask app on port {port}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="SHM Cam Studio")
parser.add_argument("--daemon", action="store_true", help="Run as daemon")
args = parser.parse_args()
if daemon_mode and sys.platform != 'win32':
if args.daemon:
create_daemon()
flask_app.run(host='0.0.0.0', port=port, debug=False, use_reloader=False)
class VideoPlayer:
def __init__(self, master, video_url):
self.master = master
# VLC player setup
args = []
_isLinux = sys.platform.startswith('linux')
if _isLinux:
args.append('--vout=mmal_vout')
# Create a VLC instance
self.Instance = vlc.Instance(args)
# Create a new MediaPlayer
self.player = self.Instance.media_player_new()
# Set the media
media = self.Instance.media_new(video_url)
self.player.set_media(media)
# Create a frame for the video
self.video_frame = self.master
self.video_frame.pack(fill=tk.BOTH, expand=True)
self.canvas = tk.Canvas(self.video_frame, width=800)
self.canvas.pack(fill=tk.BOTH, expand=True)
# Embed the VLC Video
win_id = self.canvas.winfo_id()
if _isLinux:
self.player.set_xwindow(win_id)
else:
self.player.set_hwnd(win_id)
# Play the video
self.player.play()
def create_tkinter_gui():
# Create the main window
window = tk.Tk()
window.title("Streaming Control Panel")
helv36 = tkFont.Font(family='Helvetica', size=13, weight='bold')
# Frame for the left side
fleft = tk.Frame(window)
fleft.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# URL of your HLS stream
video_url = "rtmp://192.168.42.1/record/Live"
VideoPlayer(fleft, video_url)
flask_thread = threading.Thread(target=run_flask)
flask_thread.start()
# Frame for the right side
fright = tk.Frame(window)
fright.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
create_tkinter_interface()
# Frame for the first two rows in the right frame
frame1 = tk.Frame(fright)
frame1.pack(fill=tk.BOTH, expand=True)
# Buttons configuration
buttons_row0 = [
('PRIVATE STEFY', 'smblur_private_stefy'),
('PRIVATE LEELOO', 'smblur_private_leeloo'),
('PRIVATE JASMIN', 'smblur_private_jasmin'),
('PRIVATE OTHER', 'smblur_private')
]
buttons_row1 = [
('OPEN/CLOSE STEFY', 'smblur_stefy'),
('OPEN/CLOSE LEELOO', 'smblur_leeloo'),
('OPEN/CLOSE JASMIN', 'smblur_jasmin'),
('OPEN/CLOSE OTHERS', 'smblur_shine')
]
# Create buttons for the first two rows
for j, (text, command) in enumerate(buttons_row0):
button = tk.Button(frame1, text=text, font=helv36, width=25, height=15, bg="green", fg="white",
command=lambda cmd=command: run_command(cmd))
button.grid(row=0, column=j, sticky='nsew')
for j, (text, command) in enumerate(buttons_row1):
button = tk.Button(frame1, text=text, font=helv36, width=25, height=15, bg="green", fg="white",
command=lambda cmd=command: run_command(cmd))
button.grid(row=1, column=j, sticky='nsew')
# Configure the columns in the first frame
for i in range(4):
frame1.grid_columnconfigure(i, weight=1)
# Frame for the third row in the right frame
frame2 = tk.Frame(fright)
frame2.pack(fill=tk.BOTH, expand=True)
# Row 2 with 3 buttons
buttons_row2 = [
('TEASE', 'smblur_tease'),
('TEASE ALL', 'smblur_teaseall'),
('OPEN', 'smblur_clean')
]
# Create buttons for the third row
for j, (text, command) in enumerate(buttons_row2):
button = tk.Button(frame2, text=text, font=helv36, width=30, height=25, bg="blue", fg="white",
command=lambda cmd=command: run_command(cmd))
button.grid(row=0, column=j, sticky='nsew')
# Configure the columns in the second frame
for i in range(3):
frame2.grid_columnconfigure(i, weight=1)
# Add a button to open web interface
web_button = tk.Button(frame2, text="Open Web Interface",
command=lambda: webbrowser.open('http://localhost:5000'),
bg="purple", fg="white", font=helv36)
web_button.grid(row=1, column=1, sticky='nsew')
return window
def main():
# Setup argument parser
parser = argparse.ArgumentParser(description='Streaming Control Panel')
parser.add_argument('--web-only', action='store_true',
help='Start only the web interface')
parser.add_argument('--daemon', action='store_true',
help='Run in daemon mode (Unix-like systems only)')
parser.add_argument('--port', type=int, default=5000,
help='Port for the web interface (default: 5000)')
# Parse arguments
args = parser.parse_args()
try:
# Daemon mode for web interface
if args.web_only or args.daemon:
run_flask_app(port=args.port, daemon_mode=args.daemon)
else:
# Start web interface in a background thread
web_thread = threading.Thread(
target=run_flask_app,
kwargs={'port': args.port},
daemon=True
)
web_thread.start()
# Launch Tkinter GUI
window = create_tkinter_gui()
window.mainloop()
except Exception as e:
logger.error(f"Unexpected error: {e}")
sys.exit(1)
# Cleanup
flask_thread.join()
if __name__ == '__main__':
main()
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment