feat(browser): Vivaldi app-mode with uBlock single window #2
Labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
slaid098/voice_assistant#2
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Контекст
Голосовой ассистент для незрячих пользователей (мама, Паркинсон, слепота). Основное использование — YouTube. Текущая реализация браузера (
services/browser.py:32) используетwebbrowser.open(url)— открывает новую вкладку при каждом запросе «ютуб X» и никогда их не закрывает.BrowserState(browser.py:18-22) хранит только URL-строку, не handle окна → нечем закрыть. За десятки команд накапливается сотня вкладок → браузер перегружается → ПК зависает. Для незрячего пользователя панель вкладок невидима → копится незаметно.Реклама:
README.md:90даёт неверный совет — утверждает что «Vivaldi блокирует рекламу по умолчанию, без расширений». На самом деле встроенный блокировщик Vivaldi выключен по умолчанию и неэффективен против YouTube-рекламы. Нужен uBlock Origin (расширение) в активном профиле. Код не указывает профиль → зависит от того, какой активен. «Иногда не блокирует» = чистый/сбросившийся профиль.Задача
Заменить
webbrowser.openна запуск Vivaldi в app-режиме (--app=<url>) с указанным профилем (где установлен uBlock Origin). App-режим открывает URL в отдельном окне без панели вкладок — вкладки физически не копятся. Каждый новый запуск = закрываем старое app-окно и открываем новое. PID не сохраняем (требование пользователя) — закрываем по маркеру профиля черезtaskkill.Изменения в коде
config.py— новые поля:browser_path: str— путь кvivaldi.exe, default пустой (авто-detect). Авто-detect: проверятьC:\Users\{user}\AppData\Local\Vivaldi\Application\vivaldi.exe,C:\Program Files\Vivaldi\Application\vivaldi.exe,C:\Program Files (x86)\Vivaldi\Application\vivaldi.exe.browser_profile: str— путь к профилю Vivaldi с предустановленным uBlock Origin. Default пустой. Если пустой — fallback на--app=без--user-data-dir(использует default профиль).BROWSER_PATH,BROWSER_PROFILE.services/browser.py— полная переработка:webbrowserимпорт.BrowserState: хранить_profile_marker(строка-маркер изbrowser_profileдляtaskkillфильтра по заголовку окна), НЕ хранить PID.open_url(url):_profile_markerзадан —taskkill /IM vivaldi.exe /FI "WINDOWTITLE eq *{marker}*"(закрыть старое app-окно, без сохранения PID).subprocess.Popen([browser_path, f"--app={url}", f"--user-data-dir={browser_profile}"])(если profile задан) илиsubprocess.Popen([browser_path, f"--app={url}"])(без profile).browser_pathесли не задан в env.webbrowser.open(Linux для dev/CI).README.md:BROWSER_PROFILE..env.template— новые переменные:Тесты
tests/test_browser.py— переписать:subprocess.Popen— проверка что вызывается с--app=<url>и--user-data-dir=<profile>.taskkill(мок subprocess) с фильтром по маркеру профиля.webbrowser.openна не-Windows.webbrowser.open.Контракты
open_browser_url(url: str) -> None— публичная функция (browser.py:56-62), вызывается изyoutube_flow.py:102. Сигнатура не меняется.youtube_flow._play_video(youtube_flow.py:99-103) — не меняется, вызываетopen_browser_url(url).webbrowser.open.Инварианты
taskkill /FI "WINDOWTITLE eq ...".--app=режим: окно без панели вкладок, без адресной строки — идеально для accessibility.Граничные случаи
speak("Браузер не найден"), не падать.BROWSER_PROFILEпустой → запуск без--user-data-dir(default профиль Vivaldi). Реклама может не блокироваться — логировать warning.taskkillне находит окно по маркеру (первый запуск, ничего не открыто) — silently ignore (exit code 128 = no match, не ошибка).--app=откроет новое окно в том же процессе.taskkillпо маркеру закроет только app-окно (фильтр по заголовку), не тронет обычные окна.taskkillперед каждым--app=гарантирует одно окно.subprocess.Popenсencoding="utf-8"на Windows.Влияние на связанные компоненты
services/youtube_flow.py:102— вызываетopen_browser_url, не меняется.services/commands.py— не затрагивается (нет команд закрытия).nlu/handlers.py— не затрагивается.README.md:88-90— переписать секцию «YouTube без рекламы».README.md.Вне scope
Критерии приемки
webbrowser.openзаменён наsubprocess.Popen([browser_path, "--app=<url>", ...])taskkillпо маркеру профиля (PID не сохраняется)BROWSER_PATH,BROWSER_PROFILEвconfig.pyи.env.templatewebbrowser.openна не-WindowsREADME.md— убрано неверное про «блокирует по умолчанию», добавлена инструкция uBlocktest_browser.pyпереписаны: мок subprocess, проверкаtaskkill+--app=ruff check src/ tests/— чистоmypy src/— чистоpytest— зелёный, coverage >= 75%