2026-08-20 10:43:07 -04:00
|
|
|
from selenium.common.exceptions import WebDriverException, JavascriptException
|
2026-08-19 14:03:22 -04:00
|
|
|
from selenium import webdriver
|
|
|
|
|
|
2026-08-21 10:04:40 -04:00
|
|
|
GHOST_TAB_URLS = (
|
|
|
|
|
"https://ntp.msn.com/edge/ntp?locale=en-US&title=New%20tab&fre=1&dsp=1&sp=Bing&feed_dis=always&en_widget_reg=false&prerender=1&PC=U531", # has fre
|
|
|
|
|
"https://ntp.msn.com/edge/ntp?locale=en-US&title=New%20tab&dsp=1&sp=Bing&feed_dis=always&en_widget_reg=false&prerender=1&PC=U531" # no fre
|
|
|
|
|
)
|
2026-08-19 14:03:22 -04:00
|
|
|
|
|
|
|
|
class TabUtils:
|
|
|
|
|
def __init__(self, driver: webdriver.Edge):
|
|
|
|
|
self.driver = driver
|
|
|
|
|
self.problematic_tabs = set()
|
|
|
|
|
|
2026-08-20 10:35:35 -04:00
|
|
|
def ensure_focus(self):
|
2026-08-20 10:43:07 -04:00
|
|
|
try:
|
|
|
|
|
self.driver.execute_script("""
|
2026-08-20 10:35:35 -04:00
|
|
|
Object.defineProperty(document, 'hidden', { get: () => false });
|
|
|
|
|
Object.defineProperty(document, 'visibilityState', { get: () => 'visible' });
|
|
|
|
|
Document.prototype.hasFocus = function() { return true; };
|
|
|
|
|
window.hasFocus = function() { return true; };
|
|
|
|
|
document.dispatchEvent(new Event('visibilitychange'));
|
|
|
|
|
""")
|
2026-08-20 10:43:07 -04:00
|
|
|
except JavascriptException: pass # it's probably a property redef exc
|
2026-08-20 10:35:35 -04:00
|
|
|
|
2026-08-19 14:03:22 -04:00
|
|
|
def switch_to_other_tab(self):
|
|
|
|
|
current_window = self.driver.current_window_handle
|
|
|
|
|
|
|
|
|
|
for handle in self.driver.window_handles:
|
|
|
|
|
if handle != current_window and handle not in self.problematic_tabs:
|
|
|
|
|
self.driver.switch_to.window(handle)
|
2026-08-20 09:28:54 -04:00
|
|
|
|
2026-08-21 10:04:40 -04:00
|
|
|
if self.driver.current_url in GHOST_TAB_URLS:
|
|
|
|
|
print(f"[INFO] Found ghost tab with handle {handle} and URL {self.driver.current_url}.")
|
|
|
|
|
continue
|
2026-08-20 10:35:35 -04:00
|
|
|
|
|
|
|
|
self.ensure_focus()
|
2026-08-19 14:03:22 -04:00
|
|
|
return
|
|
|
|
|
|
|
|
|
|
def close_all_other_tabs(self, exceptions: list[str] = None):
|
|
|
|
|
if exceptions is None:
|
2026-08-29 23:41:57 +05:30
|
|
|
try:
|
|
|
|
|
exceptions = [self.driver.current_window_handle]
|
|
|
|
|
except WebDriverException:
|
|
|
|
|
handles = self.driver.window_handles
|
|
|
|
|
exceptions = [handles[0]] if handles else []
|
2026-08-19 14:03:22 -04:00
|
|
|
|
2026-08-29 23:41:57 +05:30
|
|
|
switch_back_to = exceptions[0] if exceptions else None
|
2026-08-19 14:03:22 -04:00
|
|
|
|
2026-08-29 23:41:57 +05:30
|
|
|
for handle in list(self.driver.window_handles):
|
2026-08-19 14:03:22 -04:00
|
|
|
if handle not in exceptions and handle not in self.problematic_tabs:
|
2026-08-29 23:41:57 +05:30
|
|
|
try:
|
|
|
|
|
self.driver.switch_to.window(handle)
|
2026-08-20 09:28:54 -04:00
|
|
|
|
2026-08-29 23:41:57 +05:30
|
|
|
if self.driver.current_url in GHOST_TAB_URLS:
|
|
|
|
|
print(f"[INFO] Found ghost tab with handle {handle} and URL {self.driver.current_url}, not closing.")
|
|
|
|
|
continue
|
2026-08-20 11:19:35 -04:00
|
|
|
|
2026-08-29 23:41:57 +05:30
|
|
|
tab_url = self.driver.current_url
|
2026-08-20 09:28:54 -04:00
|
|
|
|
2026-08-20 11:19:35 -04:00
|
|
|
self.driver.close()
|
2026-08-21 10:04:40 -04:00
|
|
|
print(f"[INFO] Closed tab with handle {handle} and URL {tab_url}.")
|
2026-08-20 11:19:35 -04:00
|
|
|
|
2026-08-19 14:03:22 -04:00
|
|
|
except WebDriverException:
|
2026-08-29 23:41:57 +05:30
|
|
|
print(f"[WARNING] Could not close tab with handle {handle}.")
|
2026-08-19 14:03:22 -04:00
|
|
|
self.problematic_tabs.add(handle)
|
|
|
|
|
pass
|
|
|
|
|
|
2026-08-29 23:41:57 +05:30
|
|
|
handles = self.driver.window_handles
|
|
|
|
|
if switch_back_to and switch_back_to in handles:
|
|
|
|
|
try:
|
|
|
|
|
self.driver.switch_to.window(switch_back_to)
|
|
|
|
|
except WebDriverException:
|
|
|
|
|
if handles:
|
|
|
|
|
self.driver.switch_to.window(handles[0])
|
|
|
|
|
elif handles:
|
|
|
|
|
self.driver.switch_to.window(handles[0])
|
|
|
|
|
|
|
|
|
|
self.ensure_focus()
|