├── README.md └── main.py /README.md: -------------------------------------------------------------------------------- 1 | Usage 2 | 3 | Save the file as cookie_gui_importer.py. 4 | 5 | Run it: 6 | 7 | python3 cookie_gui_importer.py 8 | 9 | 10 | In the GUI: 11 | 12 | Select Chrome or Edge. 13 | 14 | Click Choose Cookie File… → select your Netscape-format cookie file. 15 | 16 | Double-click a domain (or click Open Selected Domain) → opens in a new browser tab with cookies applied. 17 | 18 | Click Open All Domains → opens all domains in separate tabs. 19 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | import sys, os, traceback 2 | from typing import Dict, List 3 | from PySide6.QtWidgets import ( 4 | QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, 5 | QPushButton, QFileDialog, QTableWidget, QTableWidgetItem, QMessageBox, 6 | QLabel, QComboBox, QStatusBar 7 | ) 8 | from PySide6.QtCore import Qt 9 | 10 | from selenium import webdriver 11 | from selenium.webdriver.chrome.service import Service as ChromeService 12 | from selenium.webdriver.edge.service import Service as EdgeService 13 | from webdriver_manager.chrome import ChromeDriverManager 14 | from webdriver_manager.microsoft import EdgeChromiumDriverManager 15 | 16 | 17 | def parse_netscape_file(path: str) -> Dict[str, List[dict]]: 18 | cookies_by_domain: Dict[str, List[dict]] = {} 19 | with open(path, "r", encoding="utf-8", errors="ignore") as f: 20 | for raw in f: 21 | line = raw.strip() 22 | if not line or line.startswith("#"): 23 | continue 24 | parts = line.split("\t") 25 | if len(parts) < 7: 26 | continue 27 | domain, include_sub, path_cookie, secure, expiry, name, value = parts[:7] 28 | cookie = { 29 | "name": name, 30 | "value": value, 31 | "domain": domain, 32 | "path": path_cookie if path_cookie else "/", 33 | "secure": (secure.upper() == "TRUE"), 34 | } 35 | try: 36 | expiry_int = int(expiry) 37 | if expiry_int > 0: 38 | cookie["expiry"] = expiry_int 39 | except: 40 | pass 41 | cookies_by_domain.setdefault(domain, []).append(cookie) 42 | return cookies_by_domain 43 | 44 | 45 | def domain_to_url(domain: str, secure_preferred: bool = True) -> str: 46 | d = domain.lstrip(".") 47 | scheme = "https" if secure_preferred else "http" 48 | return f"{scheme}://{d}/" 49 | 50 | 51 | class CookieImporterGUI(QMainWindow): 52 | def __init__(self): 53 | super().__init__() 54 | self.setWindowTitle("Netscape Cookie Importer GUI") 55 | self.resize(980, 640) 56 | 57 | self.cookies_by_domain: Dict[str, List[dict]] = {} 58 | self.cookies_path: str = "" 59 | self.driver = None 60 | self.browser_choice = "Chrome" 61 | 62 | container = QWidget() 63 | main_layout = QVBoxLayout(container) 64 | 65 | # Top controls 66 | top_bar = QHBoxLayout() 67 | self.btn_choose = QPushButton("Choose Cookie File…") 68 | self.label_file = QLabel("No file selected") 69 | self.label_file.setStyleSheet("color:#666") 70 | self.combo_browser = QComboBox() 71 | self.combo_browser.addItems(["Chrome", "Edge"]) 72 | self.btn_launch = QPushButton("Launch Browser") 73 | 74 | top_bar.addWidget(self.btn_choose) 75 | top_bar.addWidget(self.label_file, stretch=1) 76 | top_bar.addWidget(QLabel("Browser:")) 77 | top_bar.addWidget(self.combo_browser) 78 | top_bar.addWidget(self.btn_launch) 79 | main_layout.addLayout(top_bar) 80 | 81 | # Table 82 | self.table = QTableWidget(0, 5) 83 | self.table.setHorizontalHeaderLabels(["Domain", "Cookies", "Secure?", "Sample Path", "Has Expiry?"]) 84 | self.table.horizontalHeader().setStretchLastSection(True) 85 | self.table.setEditTriggers(QTableWidget.NoEditTriggers) 86 | self.table.setSelectionBehavior(QTableWidget.SelectRows) 87 | self.table.setSelectionMode(QTableWidget.SingleSelection) 88 | self.table.doubleClicked.connect(self.open_selected_domain) 89 | main_layout.addWidget(self.table) 90 | 91 | # Bottom actions 92 | actions = QHBoxLayout() 93 | self.btn_open_selected = QPushButton("Open Selected Domain") 94 | self.btn_open_all = QPushButton("Open All Domains") 95 | self.btn_open_selected.setEnabled(False) 96 | self.btn_open_all.setEnabled(False) 97 | actions.addWidget(self.btn_open_selected) 98 | actions.addWidget(self.btn_open_all) 99 | actions.addStretch(1) 100 | main_layout.addLayout(actions) 101 | 102 | self.status = QStatusBar() 103 | self.setStatusBar(self.status) 104 | self.setCentralWidget(container) 105 | 106 | # Signals 107 | self.btn_choose.clicked.connect(self.choose_file) 108 | self.btn_launch.clicked.connect(self.launch_browser) 109 | self.btn_open_selected.clicked.connect(self.open_selected_domain) 110 | self.btn_open_all.clicked.connect(self.open_all_domains) 111 | self.combo_browser.currentTextChanged.connect(self.on_browser_change) 112 | 113 | def on_browser_change(self, text): 114 | self.browser_choice = text 115 | 116 | def choose_file(self): 117 | path, _ = QFileDialog.getOpenFileName(self, "Select Netscape Cookie File", "", "Cookies (*.txt *.cookies *.*)") 118 | if not path: 119 | return 120 | try: 121 | data = parse_netscape_file(path) 122 | if not data: 123 | QMessageBox.warning(self, "Error", "Invalid file or no cookies found.") 124 | return 125 | self.cookies_by_domain = data 126 | self.cookies_path = path 127 | self.label_file.setText(os.path.basename(path)) 128 | self.populate_table() 129 | self.btn_open_selected.setEnabled(True) 130 | self.btn_open_all.setEnabled(True) 131 | self.status.showMessage(f"Loaded {len(self.cookies_by_domain)} domains.", 6000) 132 | except Exception as e: 133 | QMessageBox.critical(self, "File Error", f"{e}") 134 | traceback.print_exc() 135 | 136 | def populate_table(self): 137 | self.table.setRowCount(0) 138 | for domain, cookies in sorted(self.cookies_by_domain.items(), key=lambda x: x[0]): 139 | row = self.table.rowCount() 140 | self.table.insertRow(row) 141 | sample_path = cookies[0].get("path", "/") 142 | any_secure = any(c.get("secure") for c in cookies) 143 | any_exp = any("expiry" in c for c in cookies) 144 | self.table.setItem(row, 0, QTableWidgetItem(domain)) 145 | self.table.setItem(row, 1, QTableWidgetItem(str(len(cookies)))) 146 | self.table.setItem(row, 2, QTableWidgetItem("Yes" if any_secure else "No")) 147 | self.table.setItem(row, 3, QTableWidgetItem(sample_path)) 148 | self.table.setItem(row, 4, QTableWidgetItem("Yes" if any_exp else "Session")) 149 | for col in range(5): 150 | self.table.item(row, col).setData(Qt.UserRole, domain) 151 | self.table.resizeColumnsToContents() 152 | 153 | def ensure_driver(self): 154 | if self.driver is not None: 155 | return True 156 | try: 157 | if self.browser_choice == "Chrome": 158 | chrome_opts = webdriver.ChromeOptions() 159 | chrome_opts.add_argument("--user-data-dir=./uci-chrome-profile") 160 | chrome_opts.add_argument("--disable-notifications") 161 | chrome_opts.add_argument("--start-maximized") 162 | self.driver = webdriver.Chrome( 163 | service=ChromeService(ChromeDriverManager().install()), 164 | options=chrome_opts 165 | ) 166 | else: 167 | edge_opts = webdriver.EdgeOptions() 168 | edge_opts.add_argument("--user-data-dir=./uci-edge-profile") 169 | edge_opts.add_argument("--disable-notifications") 170 | edge_opts.add_argument("--start-maximized") 171 | self.driver = webdriver.Edge( 172 | service=EdgeService(EdgeChromiumDriverManager().install()), 173 | options=edge_opts 174 | ) 175 | return True 176 | except Exception as e: 177 | QMessageBox.critical(self, "Browser Error", f"{e}") 178 | traceback.print_exc() 179 | return False 180 | 181 | def launch_browser(self): 182 | if self.ensure_driver(): 183 | self.status.showMessage(f"{self.browser_choice} is ready.", 5000) 184 | 185 | def open_selected_domain(self): 186 | row = self.table.currentRow() 187 | if row < 0: 188 | QMessageBox.information(self, "No Selection", "Please select a domain first.") 189 | return 190 | domain = self.table.item(row, 0).data(Qt.UserRole) 191 | self.open_domain_with_cookies(domain) 192 | 193 | def open_all_domains(self): 194 | if not self.cookies_by_domain: 195 | QMessageBox.warning(self, "No Domains", "Load a cookie file first.") 196 | return 197 | if not self.ensure_driver(): 198 | return 199 | count = 0 200 | for domain in self.cookies_by_domain.keys(): 201 | ok = self.open_domain_with_cookies(domain, show_errors=False) 202 | if ok: 203 | count += 1 204 | QApplication.processEvents() 205 | self.status.showMessage(f"Opened {count} domains in new tabs.", 8000) 206 | 207 | def open_domain_with_cookies(self, domain: str, show_errors: bool = True) -> bool: 208 | if not self.ensure_driver(): 209 | return False 210 | cookies = self.cookies_by_domain.get(domain, []) 211 | if not cookies: 212 | if show_errors: 213 | QMessageBox.warning(self, "No Cookies", f"No cookies found for {domain}") 214 | return False 215 | 216 | url = domain_to_url(domain, any(c.get("secure") for c in cookies)) 217 | 218 | try: 219 | self.driver.switch_to.new_window('tab') 220 | except Exception: 221 | try: 222 | self.driver.execute_script("window.open('about:blank','_blank');") 223 | self.driver.switch_to.window(self.driver.window_handles[-1]) 224 | except Exception as e: 225 | if show_errors: 226 | QMessageBox.critical(self, "Tab Error", f"{e}") 227 | return False 228 | 229 | try: 230 | self.driver.get(url) 231 | except Exception: 232 | try: 233 | fallback = domain_to_url(domain, secure_preferred=False) 234 | self.driver.get(fallback) 235 | except Exception as e: 236 | if show_errors: 237 | QMessageBox.critical(self, "Load Error", f"{domain}\n{e}") 238 | return False 239 | 240 | added = 0 241 | for ck in cookies: 242 | try: 243 | self.driver.add_cookie(ck) 244 | added += 1 245 | except Exception: 246 | ck2 = dict(ck) 247 | ck2["domain"] = ck2["domain"].lstrip(".") 248 | try: 249 | self.driver.add_cookie(ck2) 250 | added += 1 251 | except Exception: 252 | pass 253 | 254 | try: 255 | self.driver.refresh() 256 | except Exception: 257 | pass 258 | 259 | self.status.showMessage(f"{domain}: {added}/{len(cookies)} cookies applied.", 6000) 260 | return True 261 | 262 | def closeEvent(self, event): 263 | try: 264 | if self.driver is not None: 265 | pass 266 | except: 267 | pass 268 | event.accept() 269 | 270 | 271 | def main(): 272 | app = QApplication(sys.argv) 273 | win = CookieImporterGUI() 274 | win.show() 275 | sys.exit(app.exec()) 276 | 277 | 278 | if __name__ == "__main__": 279 | main() 280 | --------------------------------------------------------------------------------