diff --git a/Galactic.py b/Galactic.py index 09a0848..9f4f36e 100644 --- a/Galactic.py +++ b/Galactic.py @@ -18,6 +18,9 @@ import hashlib import asyncio import tempfile import platform +import win32gui +import win32process +import win32con import requests import requests.adapters import importlib.util @@ -771,6 +774,51 @@ class Browser(InspectRequestsMixin, DriverCommonMixin, Chrome): except Exception: return '' + @property + def window_titles(self): + """ + Return to title list. + """ + result = [] + try: + targets = self.execute_cdp_cmd('Target.getTargets', {}) + for target in targets['targetInfos']: + if (target['type'] == 'page') == 1: + result.append(target['title']) + except Exception: + pass + return result[::-1] + + @property + def window_urls(self): + """ + Return to url list. + """ + result = [] + try: + targets = self.execute_cdp_cmd('Target.getTargets', {}) + for target in targets['targetInfos']: + if (target['type'] == 'page') == 1: + result.append(target['url']) + except Exception: + pass + return result[::-1] + + @property + def window_handles(self): + """ + Return to window handle list. + """ + result = [] + try: + targets = self.execute_cdp_cmd('Target.getTargets', {}) + for target in targets['targetInfos']: + if (target['type'] == 'page') == 1: + result.append(target['targetId']) + except Exception: + pass + return result[::-1] + @property def window_inner_size(self) -> tuple: """ @@ -842,7 +890,6 @@ class Browser(InspectRequestsMixin, DriverCommonMixin, Chrome): except Exception: pass - @calculate_execution_time def quit_backend(self): """ Exit the browser backend. @@ -1004,6 +1051,14 @@ class Browser(InspectRequestsMixin, DriverCommonMixin, Chrome): self.switch_to.default_content() self.wait(0.2) + def tab_active(self): + """ + Activate current tab. + """ + self.switch_to.window(self.current_window_handle) + self.wait(0.2) + self._update_cdp_command() + def tab_create(self, url: str = None): """ Create a new tab and open the URL. @@ -1651,18 +1706,35 @@ class BrowserManager: continue running.update_status_running() + def _get_user_process_id(self, user_id: str): + try: + return int(self.data_storage['browser_user'][user_id]['process_id']) + except KeyError: + return None + def _get_user_name(self, user_id: str): - return str(self.data_storage['browser_user'][user_id]['user_name'] or '') + try: + return str(self.data_storage['browser_user'][user_id]['user_name']) + except KeyError: + return None def _get_user_data_dir(self, user_id: str): - return os.path.join(self.browser_data_home, self.data_storage['browser_user'][user_id]['user_data_dir']) + try: + return os.path.join(self.browser_data_home, self.data_storage['browser_user'][user_id]['user_data_dir']) + except KeyError: + return None def _get_user_remote_debugging_port(self, user_id: str): - return int(self.data_storage['browser_user'][user_id]['remote_debugging_port']) + try: + return int(self.data_storage['browser_user'][user_id]['remote_debugging_port']) + except KeyError: + return None def _get_user_app_id(self, user_id: str): - user_name = self.data_storage['browser_user'][user_id]['user_name'] - return user_name or user_id + try: + return self.data_storage['browser_user'][user_id]['user_name'] or user_id + except KeyError: + return user_id def _initialize_user_running(self, user_id: str): return BrowserManagerUserRunning( @@ -1698,6 +1770,23 @@ class BrowserManager: except Exception as e: print(e, file=sys.stderr) + @staticmethod + def get_chrome_hwnd(pid: int): + if pid: + def callback(hwnd, hwnds): + if win32gui.IsWindowVisible(hwnd) and win32gui.GetParent(hwnd) == 0: + _, found_pid = win32process.GetWindowThreadProcessId(hwnd) + if found_pid == pid and 'Chrome_' in win32gui.GetClassName(hwnd): + ws = win32gui.GetWindowLong(hwnd, win32con.GWL_STYLE) + if (ws & win32con.WS_EX_TOOLWINDOW) == 0 and (ws & win32con.WS_EX_PALETTEWINDOW) == 0: + hwnds.append(hwnd) + return False + hwnds = [] + win32gui.EnumWindows(callback, hwnds) + return hwnds[0] if hwnds else None + else: + return None + def run_browser(self, user_data_dir: str, remote_debugging_port: int, proxy_server: str = None): options = [ self.binary, @@ -1714,7 +1803,7 @@ class BrowserManager: options.append('--remote-debugging-port=%s' % (remote_debugging_port,)) if proxy_server: options.append('--proxy-server=%s' % (proxy_server,)) - return subprocess.Popen(options, shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True) + return subprocess.Popen(options, shell=False, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, start_new_session=True) @staticmethod def clear_dirs(dirs): @@ -1933,7 +2022,6 @@ class BrowserManager: self.user_operate_complete(user_id) raise - @func_set_timeout(0.55) @calculate_execution_time def user_focus_window(self, user_id: str): if (user_id in self.user_ids()) == 0: @@ -1941,13 +2029,21 @@ class BrowserManager: if (user_id in self.user_ids_online()) == 0: raise FileExistsError('User ID is not running.') try: - self.user_running[user_id].driver.minimize_window() - self.user_running[user_id].driver.set_window_rect( - self.geometry_config['browser_window_x'], - self.geometry_config['browser_window_y'], - self.geometry_config['browser_window_w'], - self.geometry_config['browser_window_h'] - ) + chrome_hwnd = self.get_chrome_hwnd(self._get_user_process_id(user_id)) + if chrome_hwnd: + for _ in range(1 + int(bool(win32gui.IsIconic(chrome_hwnd)))): + win32gui.ShowWindow(chrome_hwnd, win32con.SW_RESTORE) + win32gui.ShowWindow(chrome_hwnd, win32con.SW_RESTORE) + win32gui.SetForegroundWindow(chrome_hwnd) + win32gui.SetWindowPos( + chrome_hwnd, + win32con.HWND_NOTOPMOST, + self.geometry_config['browser_window_x'], + self.geometry_config['browser_window_y'], + self.geometry_config['browser_window_w'], + self.geometry_config['browser_window_h'], + win32con.SWP_NOZORDER + ) except Exception: pass @@ -2013,7 +2109,10 @@ class BrowserManager: running = BrowserManagerUserRunning(self.user_running[user_id]) running.active = 1 if (self.is_user_data_occupied(user_id)) == 0: - self.run_browser(user_data_dir=user_data_dir, remote_debugging_port=remote_debugging_port, proxy_server='127.0.0.1:%s' % (mitmproxy_port,) if self.use_selenium_wire else None) + browser_process = self.run_browser(user_data_dir=user_data_dir, remote_debugging_port=remote_debugging_port, proxy_server='127.0.0.1:%s' % (mitmproxy_port,) if self.use_selenium_wire else None) + self.data_storage['browser_user'][user_id]['process_id'] = browser_process.pid + self.data_storage.save() + print('The browser starts, and the process ID is %s.' % (browser_process.pid,), file=sys.stderr) driver = Browser( driver=self.driver, binary=self.binary, @@ -2446,8 +2545,6 @@ class WebServer: try: self.browser_manager.user_focus_window(data.data['user_id']) return self.message(0) - except FunctionTimedOut: - return self.message(0) except Exception as e: return self.message(1, '%s' % (e,)) @@ -2536,7 +2633,7 @@ class MainRunner: self.app_data = os.path.join(appdata, 'Galactic') if appdata else os.path.join(os.path.dirname(__file__), 'data') self.app_running_file = os.path.join(self.app_data, 'running') self.app_name = 'Galactic' - self.app_version = '1.0.0.3' + self.app_version = '1.0.0.4' self.web_server_host = '127.0.0.1' self.web_server_port = 8095 self.web_server = None diff --git a/requirements.txt b/requirements.txt index cd21c45..1919d04 100644 Binary files a/requirements.txt and b/requirements.txt differ diff --git a/www/index.html b/www/index.html index fc1c08a..2a3c2b6 100644 --- a/www/index.html +++ b/www/index.html @@ -85,6 +85,6 @@
- + \ No newline at end of file