From 87ba820671e58ef20407645b1ad0d2408d50a76a Mon Sep 17 00:00:00 2001 From: NY Date: Thu, 5 Jun 2025 16:25:50 +0800 Subject: [PATCH] sec --- script_manager.py | 355 ++++++++++++++++++++++++++++++++++++---------- scripts.db | Bin 12288 -> 32768 bytes 2 files changed, 278 insertions(+), 77 deletions(-) diff --git a/script_manager.py b/script_manager.py index 15a322b..b0759d2 100644 --- a/script_manager.py +++ b/script_manager.py @@ -26,6 +26,7 @@ class ScriptManager: def _init_db(self): with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() + # 修改 scripts 表,添加 status 和 type 字段,移除 abbreviation cursor.execute(""" CREATE TABLE IF NOT EXISTS scripts ( id INTEGER PRIMARY KEY AUTOINCREMENT, @@ -34,10 +35,23 @@ class ScriptManager: ui_path TEXT NOT NULL, created_at TEXT NOT NULL, tags TEXT, - abbreviation TEXT, - usage_count INTEGER DEFAULT 0 + usage_count INTEGER DEFAULT 0, + status INTEGER DEFAULT 1, + type TEXT DEFAULT 'complex' ) """) + # 创建 tags 表 + cursor.execute(""" + CREATE TABLE IF NOT EXISTS tags ( + script_id INTEGER, + tag TEXT, + PRIMARY KEY (script_id, tag), + FOREIGN KEY (script_id) REFERENCES scripts(id) + ) + """) + # 为 tags 字段创建索引 + cursor.execute("CREATE INDEX IF NOT EXISTS idx_scripts_tags ON scripts(tags)") + cursor.execute("CREATE INDEX IF NOT EXISTS idx_tags_tag ON tags(tag)") conn.commit() def _init_scripts_dir(self): @@ -52,11 +66,9 @@ class ScriptManager: return suggested_tags def add_script(self, script_name: str, script_content: str = None, script_path: str = None, - ui_content: str = None) -> Dict: - if not script_path: - script_name_clean = script_name.replace(" ", "_").replace("/", "_").replace("\\", "_") - script_path = os.path.join(self.scripts_dir, f"{script_name_clean}.py") - + ui_content: str = None, script_type: str = "complex") -> Dict: + script_name_clean = script_name.replace(" ", "_").replace("/", "_").replace("\\", "_") + script_path = os.path.join(self.scripts_dir, f"{script_name_clean}.py") ui_path = os.path.join(self.scripts_dir, f"{script_name_clean}.ui.py") if not script_content: @@ -65,7 +77,49 @@ class ScriptManager: return [s.upper() for s in input_strings] ''' - if not ui_content: + if not ui_content and script_type == "simple": + ui_content = '''import tkinter as tk +from tkinter import ttk +import pyperclip + +def create_ui(parent, run_callback): + """创建简单脚本前端界面:单一输入输出""" + frame = ttk.Frame(parent) + frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) + frame.columnconfigure(1, weight=1) + + ttk.Label(frame, text="输入字符串:").grid(row=0, column=0, sticky=tk.W, pady=2) + input_entry = ttk.Entry(frame) + input_entry.grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2) + + ttk.Label(frame, text="输出结果:").grid(row=1, column=0, sticky=tk.W, pady=2) + output_entry = ttk.Entry(frame, state="readonly") + output_entry.grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2) + + def copy_output(event): + output = output_entry.get() + if output: + pyperclip.copy(output) + tk.messagebox.showinfo("提示", "输出已复制到剪贴板") + + output_entry.bind("", copy_output) + + def run(): + input_text = input_entry.get().strip() + if not input_text: + tk.messagebox.showerror("错误", "请输入字符串") + return + result = run_callback([input_text]) + output_entry.configure(state="normal") + output_entry.delete(0, tk.END) + output_entry.insert(0, result[0] if result else "") + output_entry.configure(state="readonly") + + ttk.Button(frame, text="运行脚本", command=run).grid(row=2, column=0, columnspan=2, pady=5) + + return frame +''' + elif not ui_content: ui_content = '''import tkinter as tk from tkinter import ttk import pyperclip @@ -114,77 +168,119 @@ def create_ui(parent, run_callback): with open(ui_path, 'w', encoding='utf-8') as f: f.write(ui_content) - abbr = ''.join(word[0].upper() for word in script_name.split('_') if word) suggested_tags = self._suggest_tags(script_name) with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() cursor.execute(""" - INSERT INTO scripts (name, path, ui_path, created_at, tags, abbreviation, usage_count) - VALUES (?, ?, ?, ?, ?, ?, ?) + INSERT INTO scripts (name, path, ui_path, created_at, tags, usage_count, status, type) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) """, ( script_name, script_path, ui_path, - datetime.datetime.now().isoformat(), + datetime.datetime.now().strftime("%Y年%m月%d日 %H:%M:%S"), json.dumps(suggested_tags), - abbr, - 0 + 0, + 1, + script_type )) + script_id = cursor.lastrowid + for tag in suggested_tags: + cursor.execute("INSERT OR IGNORE INTO tags (script_id, tag) VALUES (?, ?)", (script_id, tag)) conn.commit() return { - "id": cursor.lastrowid, + "id": script_id, "name": script_name, "path": script_path, "ui_path": ui_path, "suggested_tags": suggested_tags, - "abbreviation": abbr + "type": script_type } + def update_script(self, script_id: int, new_name: str, new_tags: List[str]) -> None: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute("SELECT name, path, ui_path FROM scripts WHERE id = ? AND status = 1", (script_id,)) + result = cursor.fetchone() + if not result: + raise ValueError("脚本未找到或已删除") + + old_name, old_path, old_ui_path = result + new_name_clean = new_name.replace(" ", "_").replace("/", "_").replace("\\", "_") + new_path = os.path.join(self.scripts_dir, f"{new_name_clean}.py") + new_ui_path = os.path.join(self.scripts_dir, f"{new_name_clean}.ui.py") + + # 重命名文件 + if old_name != new_name: + os.rename(old_path, new_path) + os.rename(old_ui_path, new_ui_path) + + # 更新 scripts 表 + cursor.execute(""" + UPDATE scripts SET name = ?, path = ?, ui_path = ?, tags = ? + WHERE id = ? AND status = 1 + """, (new_name, new_path, new_ui_path, json.dumps(new_tags), script_id)) + + # 更新 tags 表 + cursor.execute("DELETE FROM tags WHERE script_id = ?", (script_id,)) + for tag in new_tags: + cursor.execute("INSERT OR IGNORE INTO tags (script_id, tag) VALUES (?, ?)", (script_id, tag)) + conn.commit() + + def delete_script(self, script_id: int) -> None: + with sqlite3.connect(self.db_path) as conn: + cursor = conn.cursor() + cursor.execute("UPDATE scripts SET status = 0 WHERE id = ? AND status = 1", (script_id,)) + if cursor.rowcount == 0: + raise ValueError("脚本未找到或已删除") + conn.commit() + def list_scripts(self, tag: str = None, name: str = None) -> List[Dict]: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() - query = "SELECT * FROM scripts" + query = "SELECT s.id, s.name, s.path, s.created_at, s.tags, s.usage_count, s.ui_path, s.type " \ + "FROM scripts s WHERE s.status = 1" params = [] conditions = [] if tag: - conditions.append("tags LIKE ?") + query += " AND EXISTS (SELECT 1 FROM tags t WHERE t.script_id = s.id AND t.tag LIKE ?)" params.append(f'%{tag}%') if name: - conditions.append("name LIKE ?") + conditions.append("s.name LIKE ?") params.append(f'%{name}%') if conditions: - query += " WHERE " + " AND ".join(conditions) + query += " AND " + " AND ".join(conditions) cursor.execute(query, params) scripts = [] for row in cursor.fetchall(): try: - tags = json.loads(row[5]) if row[5] and row[5].strip() else [] + tags = json.loads(row[4]) if row[4] and row[4].strip() else [] except json.JSONDecodeError: - tags = [] # Fallback to empty list if JSON is invalid + tags = [] scripts.append({ "id": row[0], "name": row[1], "path": row[2], "created_at": row[3], "tags": tags, - "abbreviation": row[5], - "usage_count": row[6], - "ui_path":row[7] + "usage_count": row[5], + "ui_path": row[6], + "type": row[7] }) return scripts def run_script(self, script_id: int, input_strings: List[str]) -> List[str]: with sqlite3.connect(self.db_path) as conn: cursor = conn.cursor() - cursor.execute("SELECT path FROM scripts WHERE id = ?", (script_id,)) + cursor.execute("SELECT path FROM scripts WHERE id = ? AND status = 1", (script_id,)) result = cursor.fetchone() if not result: - raise ValueError("脚本未找到") + raise ValueError("脚本未找到或已删除") script_path = result[0] cursor.execute("UPDATE scripts SET usage_count = usage_count + 1 WHERE id = ?", (script_id,)) @@ -196,7 +292,6 @@ def create_ui(parent, run_callback): return module.process(input_strings) def load_ui_module(self, ui_path: str): - """加载前端界面模块""" if not ui_path or not os.path.isfile(ui_path): raise ValueError(f"前端界面文件不存在或路径无效:{ui_path}") try: @@ -222,54 +317,109 @@ class ScriptManagerGUI: self.root.rowconfigure(0, weight=1) def create_widgets(self): - # 使用 Notebook 创建选项卡 self.notebook = ttk.Notebook(self.root) self.notebook.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=10, pady=5) self.notebook.columnconfigure(0, weight=1) self.notebook.rowconfigure(0, weight=1) # 添加脚本选项卡 + self.create_add_tab() + + # 修改脚本选项卡 + self.create_edit_tab() + + # 索引运行脚本选项卡 + self.create_run_tab() + + def create_add_tab(self): add_frame = ttk.Frame(self.notebook, padding="10") - self.notebook.add(add_frame, text="添加脚本") + self.notebook.add(add_frame, text="添加【Add】") add_frame.columnconfigure(1, weight=1) add_frame.rowconfigure(3, weight=1) - # 脚本名称 ttk.Label(add_frame, text="脚本名称:").grid(row=0, column=0, sticky=tk.W, pady=5) self.script_name_var = tk.StringVar() ttk.Entry(add_frame, textvariable=self.script_name_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5) - # 脚本路径 - ttk.Label(add_frame, text="脚本路径(可选):").grid(row=1, column=0, sticky=tk.W, pady=5) + ttk.Label(add_frame, text="脚本类型:").grid(row=1, column=0, sticky=tk.W, pady=5) + self.script_type_var = tk.StringVar(value="simple") + ttk.OptionMenu(add_frame, self.script_type_var, "simple", "simple", "complex").grid(row=1, column=1, sticky=tk.W, pady=5) + + ttk.Label(add_frame, text="脚本路径(可选):").grid(row=2, column=0, sticky=tk.W, pady=5) self.script_path_var = tk.StringVar() - ttk.Entry(add_frame, textvariable=self.script_path_var).grid(row=1, column=1, sticky=(tk.W, tk.E), pady=5) - ttk.Button(add_frame, text="选择文件", command=self.browse_file).grid(row=1, column=2, padx=5) + ttk.Entry(add_frame, textvariable=self.script_path_var).grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5) + ttk.Button(add_frame, text="选择文件", command=self.browse_file).grid(row=2, column=2, padx=5) - # 标签 - ttk.Label(add_frame, text="标签(逗号分隔,可选):").grid(row=2, column=0, sticky=tk.W, pady=5) + ttk.Label(add_frame, text="标签(逗号分隔,可选):").grid(row=3, column=0, sticky=tk.W, pady=5) self.tags_var = tk.StringVar() - ttk.Entry(add_frame, textvariable=self.tags_var).grid(row=2, column=1, sticky=(tk.W, tk.E), pady=5) + ttk.Entry(add_frame, textvariable=self.tags_var).grid(row=3, column=1, sticky=(tk.W, tk.E), pady=5) - # 脚本内容 - ttk.Label(add_frame, text="脚本内容(可选):").grid(row=3, column=0, sticky=tk.W, pady=5) + ttk.Label(add_frame, text="脚本内容(可选):").grid(row=4, column=0, sticky=tk.W, pady=5) self.script_content_text = tk.Text(add_frame, height=5) - self.script_content_text.grid(row=3, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5) + self.script_content_text.grid(row=4, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5) - # 前端界面内容 - ttk.Label(add_frame, text="前端界面内容(可选):").grid(row=4, column=0, sticky=tk.W, pady=5) + ttk.Label(add_frame, text="前端界面内容(复杂脚本可选):").grid(row=5, column=0, sticky=tk.W, pady=5) self.ui_content_text = tk.Text(add_frame, height=5) - self.ui_content_text.grid(row=4, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5) + self.ui_content_text.grid(row=5, column=1, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5) - ttk.Button(add_frame, text="添加脚本", command=self.add_script).grid(row=5, column=0, columnspan=3, pady=5) + ttk.Button(add_frame, text="添加脚本", command=self.add_script).grid(row=6, column=0, columnspan=3, pady=5) - # 索引运行脚本选项卡 + def create_edit_tab(self): + edit_frame = ttk.Frame(self.notebook, padding="10") + self.notebook.add(edit_frame, text="修改【Modify】") + edit_frame.columnconfigure(0, weight=1) + edit_frame.rowconfigure(1, weight=1) + + # 搜索和脚本列表 + ttk.Label(edit_frame, text="搜索(名称或标签):").grid(row=0, column=0, sticky=tk.W, pady=5) + self.edit_search_var = tk.StringVar() + ttk.Entry(edit_frame, textvariable=self.edit_search_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5) + ttk.Button(edit_frame, text="搜索", command=self.refresh_edit_list).grid(row=0, column=2, padx=5) + + self.edit_tree = ttk.Treeview(edit_frame, columns=("ID", "名称", "标签", "使用次数", "创建时间", "类型"), + show="headings") + self.edit_tree.heading("ID", text="ID") + self.edit_tree.heading("名称", text="名称") + self.edit_tree.heading("标签", text="标签") + self.edit_tree.heading("使用次数", text="使用次数") + self.edit_tree.heading("创建时间", text="创建时间") + self.edit_tree.heading("类型", text="类型") + + self.edit_tree.column("ID", width=25, minwidth=25, stretch=False) + self.edit_tree.column("名称", width=150, minwidth=100, stretch=True) + self.edit_tree.column("标签", width=100, minwidth=80, stretch=True) + self.edit_tree.column("使用次数", width=80, minwidth=60, stretch=False) + self.edit_tree.column("创建时间", width=120, minwidth=100, stretch=True) + self.edit_tree.column("类型", width=80, minwidth=60, stretch=False) + + self.edit_tree.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S)) + self.edit_tree.bind("<>", self.on_edit_script_select) + + # 修改区域 + edit_input_frame = ttk.Frame(edit_frame) + edit_input_frame.grid(row=2, column=0, columnspan=3, pady=5, sticky=(tk.W, tk.E)) + edit_input_frame.columnconfigure(1, weight=1) + + ttk.Label(edit_input_frame, text="脚本名称:").grid(row=0, column=0, sticky=tk.W, pady=2) + self.edit_name_var = tk.StringVar() + ttk.Entry(edit_input_frame, textvariable=self.edit_name_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=2) + + ttk.Label(edit_input_frame, text="标签(逗号分隔):").grid(row=1, column=0, sticky=tk.W, pady=2) + self.edit_tags_var = tk.StringVar() + ttk.Entry(edit_input_frame, textvariable=self.edit_tags_var).grid(row=1, column=1, sticky=(tk.W, tk.E), pady=2) + + ttk.Button(edit_input_frame, text="修改脚本", command=self.update_script).grid(row=2, column=0, pady=5) + ttk.Button(edit_input_frame, text="删除脚本", command=self.delete_script).grid(row=2, column=1, sticky=tk.W, pady=5) + + self.refresh_edit_list() + + def create_run_tab(self): run_frame = ttk.Frame(self.notebook, padding="10") - self.notebook.add(run_frame, text="索引运行脚本") + self.notebook.add(run_frame, text="运行【Run】") run_frame.columnconfigure(0, weight=1) run_frame.columnconfigure(2, weight=1) run_frame.rowconfigure(0, weight=1) - # 左侧:搜索和脚本列表 left_frame = ttk.Frame(run_frame) left_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(0, 5)) left_frame.columnconfigure(0, weight=1) @@ -280,37 +430,32 @@ class ScriptManagerGUI: ttk.Entry(left_frame, textvariable=self.search_var).grid(row=0, column=1, sticky=(tk.W, tk.E), pady=5) ttk.Button(left_frame, text="搜索", command=self.search_scripts).grid(row=0, column=2, padx=5) - self.tree = ttk.Treeview(left_frame, columns=("ID", "名称", "标签", "缩写", "使用次数", "创建时间"), + self.tree = ttk.Treeview(left_frame, columns=("ID", "名称", "标签", "使用次数", "创建时间", "类型"), show="headings") - # Set column headings self.tree.heading("ID", text="ID") self.tree.heading("名称", text="名称") self.tree.heading("标签", text="标签") - self.tree.heading("缩写", text="缩写") self.tree.heading("使用次数", text="使用次数") self.tree.heading("创建时间", text="创建时间") + self.tree.heading("类型", text="类型") - # Set column widths (in pixels) - self.tree.column("ID", width=25, minwidth=25, stretch=False) # Narrow for ID - self.tree.column("名称", width=150, minwidth=100, stretch=True) # Wider for name - self.tree.column("标签", width=100, minwidth=80, stretch=True) # Medium for tags - self.tree.column("缩写", width=60, minwidth=50, stretch=False) # Narrow for abbreviation - self.tree.column("使用次数", width=80, minwidth=60, stretch=False) # Narrow for usage count - self.tree.column("创建时间", width=120, minwidth=100, stretch=True) # Medium for date + self.tree.column("ID", width=25, minwidth=25, stretch=False) + self.tree.column("名称", width=150, minwidth=100, stretch=True) + self.tree.column("标签", width=100, minwidth=80, stretch=True) + self.tree.column("使用次数", width=80, minwidth=60, stretch=False) + self.tree.column("创建时间", width=120, minwidth=100, stretch=True) + self.tree.column("类型", width=80, minwidth=60, stretch=False) - # Place the Treeview in the grid self.tree.grid(row=1, column=0, columnspan=3, sticky=(tk.W, tk.E, tk.N, tk.S)) self.tree.bind("<>", self.on_script_select) - # 分割线 + ttk.Separator(run_frame, orient=tk.VERTICAL).grid(row=0, column=1, sticky=(tk.N, tk.S), padx=5) - # 右侧:动态前端界面 self.io_frame = ttk.Frame(run_frame) self.io_frame.grid(row=0, column=2, sticky=(tk.W, tk.E, tk.N, tk.S), padx=(5, 0)) self.io_frame.columnconfigure(0, weight=1) self.io_frame.rowconfigure(0, weight=1) - # 加载脚本列表 self.refresh_script_list() def browse_file(self): @@ -327,9 +472,23 @@ class ScriptManagerGUI: script["id"], script["name"], ", ".join(script["tags"]), - script["abbreviation"], script["usage_count"], - script["created_at"] + script["created_at"], + script["type"] + )) + + def refresh_edit_list(self, search_term: str = None): + for item in self.edit_tree.get_children(): + self.edit_tree.delete(item) + scripts = self.manager.list_scripts(tag=search_term, name=search_term) + for script in scripts: + self.edit_tree.insert("", tk.END, values=( + script["id"], + script["name"], + ", ".join(script["tags"]), + script["usage_count"], + script["created_at"], + script["type"] )) def add_script(self): @@ -338,6 +497,7 @@ class ScriptManagerGUI: script_content = self.script_content_text.get("1.0", tk.END).strip() ui_content = self.ui_content_text.get("1.0", tk.END).strip() tags = [t.strip() for t in self.tags_var.get().split(",") if t.strip()] + script_type = self.script_type_var.get() if not script_name and not script_path: messagebox.showerror("错误", "脚本名称和脚本路径不能同时为空") @@ -350,9 +510,9 @@ class ScriptManagerGUI: try: result = self.manager.add_script(script_name, script_content or None, script_path or None, - ui_content or None) + ui_content or None, script_type) if tags: - self.manager.update_tags(result["id"], tags) + self.manager.update_script(result["id"], script_name, tags) messagebox.showinfo("成功", f"脚本 '{script_name}' 已添加!\n建议标签:{', '.join(result['suggested_tags'])}") self.script_name_var.set("") self.script_path_var.set("") @@ -360,6 +520,7 @@ class ScriptManagerGUI: self.ui_content_text.delete("1.0", tk.END) self.tags_var.set(", ".join(result["suggested_tags"])) self.refresh_script_list() + self.refresh_edit_list() except Exception as e: messagebox.showerror("错误", f"添加脚本失败:{str(e)}") @@ -370,9 +531,56 @@ class ScriptManagerGUI: self.selected_script_id = int(item["values"][0]) script = next(s for s in self.manager.list_scripts() if s["id"] == self.selected_script_id) self.refresh_io_frame(script["ui_path"], script["path"]) + self.refresh_script_list() # 实时更新使用次数 + + def on_edit_script_select(self, event): + selection = self.edit_tree.selection() + if selection: + item = self.edit_tree.item(selection[0]) + self.selected_script_id = int(item["values"][0]) + script = next(s for s in self.manager.list_scripts() if s["id"] == self.selected_script_id) + self.edit_name_var.set(script["name"]) + self.edit_tags_var.set(", ".join(script["tags"])) + + def update_script(self): + if not self.selected_script_id: + messagebox.showerror("错误", "请先选择一个脚本") + return + new_name = self.edit_name_var.get().strip() + new_tags = [t.strip() for t in self.edit_tags_var.get().split(",") if t.strip()] + if not new_name: + messagebox.showerror("错误", "脚本名称不能为空") + return + try: + self.manager.update_script(self.selected_script_id, new_name, new_tags) + messagebox.showinfo("成功", f"脚本 '{new_name}' 已更新") + self.edit_name_var.set("") + self.edit_tags_var.set("") + self.refresh_edit_list() + self.refresh_script_list() + except Exception as e: + messagebox.showerror("错误", f"更新脚本失败:{str(e)}") + + def delete_script(self): + if not self.selected_script_id: + messagebox.showerror("错误", "请先选择一个脚本") + return + if messagebox.askyesno("确认", "确定要删除此脚本吗?"): + try: + self.manager.delete_script(self.selected_script_id) + messagebox.showinfo("成功", "脚本已删除") + self.edit_name_var.set("") + self.edit_tags_var.set("") + self.refresh_edit_list() + self.refresh_script_list() + except Exception as e: + messagebox.showerror("错误", f"删除脚本失败:{str(e)}") + + def search_scripts(self): + search_term = self.search_var.get().strip() + self.refresh_script_list(search_term) def refresh_io_frame(self, ui_path: str = None, script_path: str = None): - # 清空现有界面 if self.current_ui_frame: self.current_ui_frame.destroy() @@ -386,14 +594,11 @@ class ScriptManagerGUI: return try: - # 加载前端界面模块 ui_module = self.manager.load_ui_module(ui_path) - - # 创建运行回调 def run_callback(input_strings): - return self.manager.run_script(self.selected_script_id, input_strings) - - # 调用前端界面的 create_ui 函数 + result = self.manager.run_script(self.selected_script_id, input_strings) + self.refresh_script_list() # 实时更新使用次数 + return result self.current_ui_frame = ui_module.create_ui(self.io_frame, run_callback) self.current_ui_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) except Exception as e: @@ -407,10 +612,6 @@ class ScriptManagerGUI: ) self.current_ui_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S)) - def search_scripts(self): - search_term = self.search_var.get().strip() - self.refresh_script_list(search_term) - if __name__ == "__main__": root = tk.Tk() diff --git a/scripts.db b/scripts.db index f5f13bce51244e48009ce108fce67509d21da33c..6eaf2a8b207b04d95eeb0df36a2ad61c088eeffc 100644 GIT binary patch literal 32768 zcmeI5OKclO7{_`DFfBtpkS|W?mYNXO2!sevtEwOf+gWI2A;RsD~O^0V%T2BhW<{6>2uk~8%X=*ml&)TSD@?@0{|rPQH;Z97tGZJDxBQQ2i?`KNmg?ixxx zm)hgx^PED_oY0Gt>Oo^t)om+p<}yWN!pK=&jz~_QFuXg}q14_XKkog`Jht7pN=Ds?jYYn`VEA*Vk<6W2I`%Zhdx1A2ZUKyq&XDuU%@^IH23(mKyU!%yh*n z-y~n8qeHE=zhvo_?bUO;zHV2aHCb53qoOa9pD2tQM>>>f>q+u`I1(Yp^Gp3V)#vqT zC(oODoTa#glk$7m>%Q7P)x2B{-D&?f-T6Ww81C#O``pevG|ncG>5_5CHgXxGRGSoQ zhhuHwMn0Un*qu@OlEAyaLk@2ChnaP*;|9BykP$JRSG z@H`%*n%Xp;f0ZHcJ=FS`H@Nr^sk|C8`CQ2=>LwdqTyeT^uu{au?VQO7 zC{gyJeqiuXw+%ss&z}WhTPPTAZzKDhc9~hPDNGAjBzr~=?s_J*m%W^pO4a9gIaO_B zV$t1A!SE9iVpeqc?>4T(iwBmesutqvyfoKXiYm-BiM}S#pXnufnniGd00@8p2!H?x zfB*=900@8p2!H?x+(QBniiyy$W*J8;txMGk#XS4RNl6=hSlmj6HTGWytxH>Y_wwTP zX&#xGTX^fdHY#++cRSK9q3DFqvB)YPA2Qr`|4~dQTe-w6GQtdP|_U=r8xMaZm*UAOHd&00JNY0w4eaAOHd&00JOz z{|KxLh*9D@0Jy$VQd2;T_<0ha|I73;p?}ev^jG>L{gz&*mnppS?_VFGCJ+Dt5C8!X z009sH0T2KI5C8!XSR&BSC<<%i@sKPE8(epQP>@G2z4P1GQ?x-8+N)RgLlQ4@+y{c9 zD6D7x1UV%j3K7rGKqjKl#(fXC|G!MH5c&tbLI0-T(JS;PI>&xqrPFkJsd~gf00ck) z1V8`;KmY_l00ck)1V8`;?wUZeL^cq~oyRxP_XTO4MA}J1^%TCrk&%6w--F^>5|1}3 z;s)a8$xhUn{|DEI?WE>rr_7oEOR~70u=&3zHnDYoZ~h;U#kLTi|5sTapkL7w?)raK zE}|d+0w4eaAOHd&00JNY0w4eaAOHd@5a<@i*w*{I*{r|9X#hDj8|H}IRO|}Ez2K|9~0L;-VD>Mt)AOHd&00JNY0w4eaAOHd&00JNY0{4eN)uMmZ z8ov{D4hfW(xdQl0{k6;go=*VZ|1Y&{5$Nl!-?aS6BDg>R1V8`;KmY_l00ck)1V8`; zZYOZGPf~=z^uShPgd*j0XXj@>DPK6V_~}RUv!A&h+Viv5=4anv`Q8a^BdbeoDon;> z@nreStFg@sADoCK7tWklyJP*y-u|Ax<*UHnneg%*Dz{Ch-}^qsqtA+t>BHP~cMJLa z?78X&ES{Y%e{r!qcg)wmy3~rM$NS^H>Gck*uQa4iRW%KHGN1^l;enk*4@LM<_wJr| z*A<@i#=^zV-LCMPv6{?EjYxF&$9n6Xq~Cl;HPqN1Ac_#(I*=f##z@gPY!plEI~1*= hnH%$U)#l!AUyt*AB>NM|{&?bFzDht^K~1$0{{Z7E?`Z%4 literal 12288 zcmeI0%WD%s9LHyqP^l)VMWlybhCQ?mO~Yn4X_|o4wXPCP)0%F<5<}RgYh7uRbazt} zJlL0_g7u&ldg`Hi5UnDLL5qJ)9)d?N9-X{OVm2WjdXe9dVPt{5iPhF*xX$Hg)w44^wlMU0GQohsd}luVmz8Le?4|&5gU%_;RR3 z*GW7be;gnH1b_e#00KY&2mk>f z00e+Q8v<*rsT&DVezJ#>ZfmJz;l+pIx6S<4M)A{L{@qUD;B(>0Vd3ek>iPUeI~!N} zF3Ygq5oUCR@rrIHz_|mA&*k@fM%|t$U2>(JbR`3sRFV|7pXIk-(y=Snj#6Y4l4XrE zccWmOA3sCMh4;^YeBa1r_jB1dL~!x#>sI~wS;gJ&FDb;E3vDfK8RpLFW z8#%^#u9p(XO^&Q;ZLUE^v!E05^*1~_kk