""" * Author: "PepDebian(peppermintosteam@proton.me) * * License: SPDX-License-Identifier: GPL-3.0-or-later * * This is for the Kumo SSB Gui """ import os import re from urllib.parse import urljoin from tkinter import filedialog import sqlite3 import tkinter as tk import requests import ttkbootstrap as ttk import bsconf # setup the window pwin = bsconf.bbstyle pwin.resizable(False, False) WINDOW_HEIGHT = 380 WINDOW_WIDTH = 640 pwin.title('Peppermint Kumo (SSB Manager)') # Set the user paths used gusr = os.environ.get('USER') spath = "/home/" + gusr + "/.local/share/pmostools/peptools" dpath = "/home/" + gusr + "/.local/share/applications/" ipath = "/home/" + gusr + "/Pictures/" # Set the window icon pwin.tk.call('wm', 'iconphoto', pwin, tk.PhotoImage( file=spath + '/images/kumosm.png')) # Set the database connection string dcon = sqlite3.connect(spath + '/welval.db') pcur = dcon.cursor() # Create the table if not exists pcur.execute(""" CREATE TABLE IF NOT EXISTS kumoapp (id integer PRIMARY KEY AUTOINCREMENT, ssbname text, lnk text);""" ) import os import subprocess def determine_browser(): """Verifica o navegador padrão no sistema ou retorna um valor alternativo""" try: # Tenta detectar o navegador padrão do sistema com 'xdg-settings' browser = subprocess.check_output(['xdg-settings', 'get', 'default-web-browser']).decode('utf-8').strip() # Verifica se o comando foi bem-sucedido e retorna o navegador if browser: print(f"Navegador padrão detectado: {browser}") return "xdg-open" # O comando 'xdg-open' serve para abrir URLs no navegador padrão except subprocess.CalledProcessError as e: print("Erro ao tentar detectar o navegador padrão:", e) # Caso não consiga detectar o navegador, retorna 'xdg-open' como fallback print("Nenhum navegador padrão detectado. Usando 'xdg-open'.") return "xdg-open" def download_favicon(url, output_folder=ipath, request_timeout=3): """ This function will try a regex to find and locate the favicon of a website.Depending on the website it may not find the favicon. the goals is to try and stay within the python stndard library """ # Send a GET request to the website response = requests.get(url, timeout=request_timeout) response.raise_for_status() # Raise an error for bad responses # Use a regular expression to find the favicon URL in the HTML match = re.search( r']*?rel=["\']?icon["\']?[^>]*?href=["\'](.*?)["\']', response.text, re.IGNORECASE ) if match: favicon_url = match.group(1) favicon_url = urljoin(url, favicon_url) # Download the favicon response = requests.get(favicon_url,timeout=request_timeout, stream=True) response.raise_for_status() if not os.path.exists(output_folder): os.makedirs(output_folder) filename = os.path.join(output_folder, os.path.basename(favicon_url) ) with open(filename, 'wb') as f: for chunk in response.iter_content(chunk_size=8192): f.write(chunk) return filename return None def delete_ssb(): """ Delete the ssb that is selected """ get_name = cmbo.get() link_address = """ DELETE FROM kumoapp WHERE ssbname = ? """ pcur.execute(link_address, (get_name,)) dcon.commit() runaddr_value.delete('1.0', tk.END) for dfile in os.listdir(dpath): if dfile.startswith(get_name) and dfile.endswith('.desktop'): del_path = os.path.join(dpath, dfile) os.remove(del_path) pwin.destroy() os.system('python3 refresh.py') def center_screen(): """Gets the coordinates of the center of the screen""" screen_width = pwin.winfo_screenwidth() screen_height = pwin.winfo_screenheight() x_cordinate = (screen_width // 2) - (WINDOW_WIDTH // 2) y_cordinate = (screen_height // 2) - (WINDOW_HEIGHT // 2) pwin.geometry(f"{WINDOW_WIDTH}x{WINDOW_HEIGHT}+{x_cordinate}+{y_cordinate}") def update_ui(): """Reorganiza os componentes para uma melhor apresentação""" # Ajuste as posições, margens, etc., se necessário para garantir um layout mais agradável pwin.geometry(f"{WINDOW_WIDTH}x{WINDOW_HEIGHT}") def make_desktop_file(): # Obter valores das entradas get_name = ssb_value.get("1.0", 'end-1c').strip() get_url = urladdr_value.get("1.0", 'end-1c').strip() get_local = cmbomenu.get() get_icon = icon_value.get("1.0", 'end-1c').strip() write_path = dpath + get_name + '.desktop' # Obter a categoria reversa selected_category_key = categories_reverse.get(get_local, 'Applications') # Defina um valor padrão # Determinar o comando do navegador command = determine_browser() if not command: print("No suitable browser found. .desktop file not created") return # Usar o comando de execução adequado sem o '&' exec_command = f'xdg-open "{get_url}"' # Definir o conteúdo do arquivo .desktop app_content = f""" [Desktop Entry] Version=1.0 Name={get_name} Exec={exec_command} Icon={get_icon} Categories={selected_category_key} Type=Application Terminal=false """ # Verificar se o diretório de destino existe, criar se não folder = os.path.dirname(write_path) if not os.path.exists(folder): os.makedirs(folder) # Criar e escrever no arquivo .desktop with open(write_path, 'w') as app: app.write(app_content) # Tornar o arquivo executável os.chmod(write_path, 0o755) print(f"Desktop file created at {write_path}") def add_new_ssb(): """ Add new ssb """ make_desktop_file() ssb_name = ssb_value.get("1.0", 'end-1c') ssb_address = urladdr_value.get("1.0", 'end-1c') sql_insert = """ INSERT INTO kumoapp(ssbname,lnk) VALUES(?,?);""" pcur.execute(sql_insert, (ssb_name, ssb_address,)) dcon.commit() ssb_value.delete('1.0', tk.END) urladdr_value.delete('1.0', tk.END) pwin.destroy() os.system('python3 ' + spath + '/refresh.py') pwin.destroy() os.system('python3 refresh.py') def fill_dropdown(): """ set the combobox value """ cursor = dcon.execute('SELECT ssbname FROM kumoapp') result = [row[0] for row in cursor.fetchall()] return result def fill_url_address(): """ get the url of the ssb and run the it in min""" get_name = cmbo.get() link_address = """ SELECT lnk FROM kumoapp WHERE ssbname = ? """ pcur.execute(link_address, (get_name,)) use_address = pcur.fetchone() runaddr_value.delete('1.0', tk.END) runaddr_value.insert("end-1c", use_address) def run_url_address(): """Run the browser with the appropriate profile and address.""" command = determine_browser() if command: os.system(command) else: print("There no suitebable browser installed!") def select_icon(): """ Select the icon to be used for the SSB in the system The starting folder is the home pictures folder """ ssb_address = urladdr_value.get("1.0", 'end-1c') output_filename = download_favicon(ssb_address) initial_dir = ipath file_path = filedialog.askopenfilename( title="Select Icon", initialdir=initial_dir, filetypes=[("Icon files", "*.ico"), ("Icon files", "*.png"), ("Icon files", "*.gif"), ("Icon files", "*.ppm"), ("Icon files", "*.pgm")] ) if file_path: icon_value.delete(1.0, tk.END) icon_value.insert(tk.END, file_path) elif output_filename: icon_value.delete(1.0, tk.END) icon_value.insert(tk.END, output_filename) else: icon_value.delete(1.0, tk.END) icon_value.insert(tk.END, "No icon selected") ### Create SSB side objects used ### Title new_label = ttk.Label(pwin, text="Create new SSBs", bootstyle="dark", font=("Helvetica", 14) ) new_label.place(x=10, y=20) ssb_label = ttk.Label(pwin, text="Give the ssb a name:") ssb_label.place(x=10, y=55) ssb_value = tk.Text(pwin, height=1, width=25) ssb_value.place(x=10, y=80) lblcmbomenu = ttk.Label(pwin, text="Menu Location:") lblcmbomenu.place(x=10, y=113) categories = { 'AudioVideo' : 'AudioVideo', 'Audio':'Audio', 'Video':'Video', 'Development':'Development', 'Education':'Education', 'Game':'Game', 'Graphics':'Graphics', 'Network':'Internet', 'Office':'Office', 'Settings':'Settings','System':'System', 'Utility':'Utility' } categories_reverse = {value: key for key, value in categories.items()} cmbomenu = ttk.Combobox(pwin) cmbomenu.place(x=10, y=135) cmbomenu['values'] = list(categories.values()) icon_default_text = 'Set the icon with the "Icon" button' icon_value = tk.Text(pwin, height=1, width=32) icon_value.insert(tk.END, icon_default_text) icon_value.place(x=10, y=280) icon_button = ttk.Button(pwin, text="Icon", width=7, cursor="hand2", bootstyle="danger", command=select_icon ) icon_button.place(x=90, y=324) url_default_text = "example: https://www.example.com" urladdr_label = ttk.Label(pwin, text="Enter the Url:") urladdr_label.place(x=10, y=172) urladdr_value = tk.Text(pwin, height=3, width=32) urladdr_value.insert(tk.END, url_default_text) urladdr_value.place(x=10, y=200) btnsv = ttk.Button( pwin, text="Save", cursor="hand2", bootstyle="danger", width=5, command=add_new_ssb ) btnsv.place(x=10, y=324) ### The Separator for the window separator = ttk.Separator(pwin, orient='vertical') separator.place(relx=.495, rely=0, relheight=1) ### Manage SSBs side) manage_label = ttk.Label(pwin, text="Manage SSBs", bootstyle="dark", font=("Helvetica", 14) ) manage_label.place(x=330, y=20) lblcmbo = ttk.Label(pwin, text="Select SSB to Manage:") lblcmbo.place(x=330, y=55) cmbo = ttk.Combobox(pwin) cmbo.place(x=330, y=80) cmbo['values'] = fill_dropdown() runaddr_label = ttk.Label(pwin, text="Url Address:") runaddr_label.place(x=330, y=125) runaddr_value = tk.Text(pwin, height=4, width=32) runaddr_value.place(x=330, y=150) btnrun = ttk.Button( pwin, text="Run", cursor="hand2", bootstyle="danger", width=7, command=run_url_address ) btnrun.place(x=330, y=324) btndelete = ttk.Button( pwin, text="Delete", cursor="hand2", bootstyle="danger", width=7, command=delete_ssb ) btndelete.place(x=430, y=324) def set_state(event): """ Function that managse the state of the buttons and the Url address for the Manage SSBs section, this is an event function """ selected_value = cmbo.get() if selected_value == "": btndelete["state"] = "disabled" btnrun["state"] = "disabled" else: btndelete["state"] = "normal" btnrun["state"] = "normal" fill_url_address() cmbo.bind("<>", set_state) set_state(None) center_screen() pwin.mainloop()