Я давно пользуюсь FVD Speed Dial как основной экспресс‑панелью. Однажды после перенастройки сети (VPN, прокси, DNS) заметил неприятный эффект: любое слово, набранное в строке поиска новой вкладки, всегда улетало в Yahoo. Никаких настроек выбора поисковика в интерфейсе расширения не было — только встроенное поле, жёстко завязанное на внутреннюю логику FVD.

Системный поисковик Chrome я менял, но это никак не влияло на поведение FVD Speed Dial: расширение упрямо перенаправляло все запросы в Yahoo.

Поиск в Сети привел к статье на Хабр датированной 3 авг 2013. Данные устарели, но идею подхватил.

Где живёт расширение и что в нём есть

Расширение FVD Speed Dial (версия 81.8.3, ID llaficoajjainaijghjlofdfmbjpebpa) у меня стоит в портативной сборке Cent Browser:

CentBrowserPortable\User Data\Default\Extensions\llaficoajjainaijghjlofdfmbjpebpa\81.8.3_0\
js\newtab\search.js
styles\newtab\style.css

В обычном Chrome/Chromium путь к расширениям примерно такой:

  • Windows:
    C:\Users\<имя>\AppData\Local\Google\Chrome\User Data\Default\Extensions\<id>\<версия>_0\

  • Linux:
    ~/.config/google-chrome/Default/Extensions/<id>/<версия>_0\

Найти свою папку проще всего через chrome://extensions → «Режим разработчика» → «Подробнее» → поле «Путь».

Дальше я отдал файлы js/newtab/search.js и styles/newtab/style.css ИИ‑ассистенту с просьбой понять, почему всё летит в Yahoo и можно ли добавить нормальный выбор поисковой системы прямо в новой вкладке.

Разбор логики: скрытый автодетект провайдера

ИИ быстро раскопал несколько ключевых моментов в search.js:

  • глобальный объект Search.prototype.searchProviders — здесь перечислены системные провайдеры (fvdyandexbingyahoo и т.д.), каждый со своим URL поиска;

  • настройки пользователя хранятся в sd.searchprovider, но в интерфейсе новой вкладки выбора поисковика нет — пользователь до этих настроек не добирается;

  • функция doSearch() делает так:

    • берёт текущий провайдер (this.getProvider()),

    • если это fvd, вызывает this.detectProvider(),

    • detectProvider() по списку локалей и IP выбирает реальный провайдер (в моём случае стабильно попадала в ветку с Yahoo).

Получается, что поведение «всегда Yahoo» — это не вирус и не подмена поиска, а агрессивный автодетект, который после изменений сети стал считать Yahoo «правильным» вариантом.

Цель: добавить нормальный выбор ПС и отключить навязчивый автодетект

Я сформулировал задачу ИИ так:

  1. Добавить выбор поисковой системы прямо в интерфейсе FVD Speed Dial (Google, Яндекс, DuckDuckGo и т.д.).

  2. Сделать так, чтобы при явном выборе никакой автодетект провайдера не срабатывал.

  3. Визуально отображать текущую ПС через иконку рядом со строкой поиска.

ИИ предложил использовать уже существующую инфраструктуру в search.js:

  • список провайдеров searchProviders,

  • настройки sd.searchprovider,

  • структуру UI: логотип #searchLogo, список #searchList.

Оказалось, выбор ПС уже заложен в код, но не доведён до нормального UI.

Доработка JavaScript: реальные провайдеры и сохранение выбора

В Search.prototype.searchProviders мы оставили существующие записи и добавили явные системные поисковики:

Search.prototype.searchProviders = {
  fvd: {
    name: "Speed Dial",
    url: "https://fvdmedia.com/addon/search?qq={q}&from=chromefvdsd&installtime={time}&searchtype={type}"
  },
  yandex: {
    name: "Yandex",
    url: "https://yandex.ru/yandsearch?clid=2028026&text={q}",
    locale: ["ru", "by", "kz", "uz", "uk", "kg"],
    ip: ["ru", "by", "kz", "uz", "uk", "ua", "kg"],
    replace: function(url) { /* логика доменов yandex.ru / yandex.fr и т.д. */ }
  },
  bing: {
    name: "Bing",
    url: "https://search.fvdspeeddial.com/results.aspx?gd=SY1002769&searchsource=69&q={q}"
  },
  yahoo: {
    name: "Yahoo",
    url: "https://search.fvdspeeddial.com/results.aspx?gd=SY1002769&searchsource=69&q={q}"
  },

  google: {
    name: "Google",
    url: "https://www.google.com/search?q={q}"
  },

  duckduckgo: {
    name: "DuckDuckGo",
    url: "https://duckduckgo.com/?q={q}"
  }
};

Функция fill() уже умела:

  • очищать #searchList,

  • пробегаться по searchProviders,

  • создавать <li provider="<ключ>" class="provider-<ключ>"> с именем поисковой системы,

  • выставлять атрибут provider на #searchLogo и подсвечивать активный пункт.

Чтобы выбор сразу отражался в UI, мы поправили обработчик клика:

Search.prototype.clickProvider = function(option) {
  const provider = option.attr("provider");
  this.setProvider(provider); // сохраняет в sd.searchprovider
  this.fill();                // немедленно обновляет логотип и меню
  this.menu("close");
};

Ключевой момент — поведение doSearch():

jsSearch.prototype.doSearch = async function(query) {
  const fvdSpeedDial = this.fvdSpeedDial;
  const Prefs = fvdSpeedDial.Prefs;
  let url;

  if (!query) {
    const q = document.getElementById("q");
    if (q.hasAttribute("clickUrl")) {
      query = q.getAttribute("clickUrl");
    } else {
      query = q.value;
    }
  }

  if (typeof query === "object" && query.clickurl) {
    url = query.clickurl;
  } else {
    let provider = this.getProvider(); // читаем выбор пользователя

    // Автодетект оставляем только в режиме "Speed Dial"
    if (provider === "fvd") {
      provider = this.detectProvider();
    }

    const providerData = this.searchProviders[provider];

    if (String(query).trim().length === 0) {
      return false;
    }

    await Analytics.fireSearchEvent(query, providerData?.name);

    url = String(providerData.url)
      .replace("{q}", encodeURIComponent(query))
      .replace("{time}", Prefs.get("sd.installtime"))
      .replace("{type}", Utils.getInstallVersion(fvdSpeedDial) >= 6930 ? 0 : 1)
      .replace("{version}", Utils.getCurrentVersion());

    if (typeof providerData.replace === "function") {
      url = providerData.replace(url);
    }
  }

  document.location = url;
};

Такое поведение даёт простой эффект:

  • если я явно выбрал Google, Яндекс или DuckDuckGo — всегда используется именно этот URL;

  • если оставил «родной» режим FVD (fvd) — включается автодетект, и расширение само решает, куда отправить запрос (хочешь — пользуйся этим режимом, хочешь — нет).

Доработка CSS: иконки провайдеров и маленький баг с комментариями

Вторая часть истории — визуальный выбор. В styles/newtab/style.css уже был блок для логотипа #searchLogo, но часть правил оказалась закомментирована, из‑за чего иконка всегда оставалась дефолтной, даже если JS уже правильно выставлялprovider

ИИ помог быстро найти нужный фрагмент:

css.searchLogo {
  cursor: pointer;
  width: 32px;
  height: 32px;
  display: inline-block;
  background-repeat: no-repeat;
  background-size: 32px 32px;
  background-position: center center;
  margin-right: 5px;
  margin-top: -2px;
  position: relative;
  opacity: 1;
  transition: opacity 75ms;
  background-image: url(images/providerfvd.png);
}

.searchLogo.fade {
  opacity: 0;
}

.searchLogo:after {
  content: "";
  position: absolute;
  width: 13px;
  height: 0px;
  box-shadow: 0px 0px 10px 1px #fff;
  top: 36px;
  left: 10px;
  background: #ccc;
}

/* иконки поисковых систем */
.searchLogo[provider="fvd"]         { background-image: url(images/providerfvd.png); }
.searchLogo[provider="autodetect"]  { background-image: url(images/providerautodetect.png); }
.searchLogo[provider="yandex"]      { background-image: url(images/provideryandex.png); }
.searchLogo[provider="yahoo"]       { background-image: url(images/provideryahoo.png); }
.searchLogo[provider="bing"]        { background-image: url(images/providerbing.png); }
.searchLogo[provider="google"]      { background-image: url(images/providergoogle.png); }
.searchLogo[provider="duckduckgo"]  { background-image: url(images/providerduckduckgo.png); }

Раньше этот блок был «убит» комментариями и странными селекторами вида .searchLogoprovidergoogle. После небольших правок и распаковки комментариев логотип начал корректно менять иконку при смене провайдера.

Сами изображения (providergoogle.pngproviderduckduckgo.pngprovideryandex.png и т.д.) уже были в images/ — их не пришлось искать или рисовать, достаточно было просто вернуть CSS к жизни.

Результат

В итоге с помощью ИИ и пары правок в двух файлах:

  • js/newtab/search.js

  • styles/newtab/style.css

я получил то, чего не было «из коробки»:

  • полноценно работающий список поисковых систем в строке FVD Speed Dial (Google, Яндекс, DuckDuckGo, Bing, Yahoo и др.);

  • сохранение выбора между перезапусками браузера;

  • адекватное поведение автодетекта (только в режиме FVD, а не поверх моего выбора);

  • нормальные иконки провайдеров, которые меняются вместе с поисковой системой.

И главное — навязчивый Yahoo исчез из моей ежедневной рутины, а вместо ручного reverse‑engineering большую часть анализа кода сделал за меня ИИ.