Greasy Fork is available in English.

Google Discover Toggle

Enable/disable Google Discover by toggling ?gl=nz. Adds a non-blocking prompt for first-time users with snooze/never options. Persists across sessions.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name         Google Discover Toggle
// @namespace    https://github.com/ymhomer/ym_Userscript
// @version      1.3
// @description  Enable/disable Google Discover by toggling ?gl=nz. Adds a non-blocking prompt for first-time users with snooze/never options. Persists across sessions.
// @author       ymhomer
// @match        https://www.google.com/*
// @match        https://www.google.*/*
// @grant        GM_registerMenuCommand
// @grant        GM_setValue
// @grant        GM_getValue
// @run-at       document-start
// @noframes
// @license      MIT
// ==/UserScript==

;(async function () {
  'use strict';

  const STORAGE_KEY = 'discoverEnabled';
  const PROMPT_NEVER_KEY = 'discoverPromptNever';
  const SNOOZE_UNTIL_KEY = 'discoverSnoozeUntil';
  const GL_PARAM = 'gl';
  const DISCOVER_GL = 'nz';
  const SNOOZE_MS = 24 * 60 * 60 * 1000; // 1 day
  const REDIRECT_GUARD_KEY = 'gdt_last_redirect';
  const REDIRECT_GUARD_MS = 8000;

  const GMAPI = (typeof GM?.getValue === 'function')
    ? {
        get: (k, d) => GM.getValue(k, d),
        set: (k, v) => GM.setValue(k, v),
        menu: (label, cb) => GM.registerMenuCommand(label, cb),
      }
    : {
        get: (k, d) => Promise.resolve(GM_getValue(k, d)),
        set: (k, v) => Promise.resolve(GM_setValue(k, v)),
        menu: (label, cb) => GM_registerMenuCommand(label, cb),
      };

  const topWindow = (window.top === window.self);
  if (!topWindow) return;

  const path = location.pathname;
  const isEligiblePath = (path === '/' || path === '/search');

  function getGL(urlLike) {
    try {
      const u = new URL(urlLike || location.href);
      return u.searchParams.get(GL_PARAM);
    } catch {
      return null;
    }
  }

  function withGL(urlLike, value) {
    try {
      const u = new URL(urlLike || location.href);
      const sp = u.searchParams;
      if (value == null) {
        sp.delete(GL_PARAM);
      } else {
        sp.set(GL_PARAM, value);
      }
      return u.toString();
    } catch {
      return urlLike || location.href;
    }
  }

  function shouldGuardRedirect() {
    try {
      const last = sessionStorage.getItem(REDIRECT_GUARD_KEY);
      const now = Date.now();
      if (last && (now - Number(last) < REDIRECT_GUARD_MS)) return true;
      sessionStorage.setItem(REDIRECT_GUARD_KEY, String(now));
      return false;
    } catch {
      return false;
    }
  }

  // Persistent values
  const enabled = await GMAPI.get(STORAGE_KEY, undefined);
  const promptNever = await GMAPI.get(PROMPT_NEVER_KEY, false);
  const snoozeUntil = Number(await GMAPI.get(SNOOZE_UNTIL_KEY, 0)) || 0;

  // If user already enabled, enforce gl=nz if needed
  if (enabled === true) {
    const currentGL = getGL(location.href);
    if (currentGL !== DISCOVER_GL && !shouldGuardRedirect()) {
      location.replace(withGL(location.href, DISCOVER_GL));
      return;
    }
  }

  // Menu toggle
  const menuLabel = (() => {
    if (enabled === true) return 'Disable Google Discover';
    if (enabled === false) return 'Enable Google Discover';
    return 'Enable Google Discover (not set)';
  })();

  GMAPI.menu(menuLabel, async () => {
    const newState = !(enabled === true);
    await GMAPI.set(STORAGE_KEY, newState);
    if (newState) {
      if (getGL(location.href) !== DISCOVER_GL) {
        location.replace(withGL(location.href, DISCOVER_GL));
        return;
      }
    }
    // if disabling, do not touch current gl — just reload to apply menu label if needed
    location.reload();
  });

  // First-time prompt logic (only if no decision yet)
  const shouldPrompt =
    enabled === undefined &&
    !promptNever &&
    Date.now() >= snoozeUntil &&
    isEligiblePath;

  if (!shouldPrompt) return;

  // Wait for body to exist before injecting UI
  if (!document.body) {
    await new Promise((res) => {
      const obs = new MutationObserver(() => {
        if (document.body) {
          obs.disconnect();
          res();
        }
      });
      obs.observe(document.documentElement, { childList: true, subtree: true });
    });
  }

  // Render prompt (Shadow DOM)
  const host = document.createElement('div');
  host.setAttribute('data-gdt', 'host');
  host.style.position = 'fixed';
  host.style.top = '16px';
  host.style.right = '16px';
  host.style.zIndex = '2147483647';
  host.style.all = 'initial'; // avoid leaking styles
  document.body.appendChild(host);

  const shadow = host.attachShadow({ mode: 'closed' });
  const wrap = document.createElement('div');

  const style = document.createElement('style');
  style.textContent = `
    :host, * { box-sizing: border-box; }
    .card {
      font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
      font-size: 13px;
      line-height: 1.35;
      color: #1f1f1f;
      background: rgba(255,255,255,0.96);
      backdrop-filter: saturate(150%) blur(6px);
      border: 1px solid rgba(0,0,0,0.08);
      border-radius: 12px;
      box-shadow: 0 8px 30px rgba(0,0,0,0.12);
      width: 280px;
      padding: 12px 12px 10px;
    }
    @media (prefers-color-scheme: dark) {
      .card {
        color: #eaeaea;
        background: rgba(32,32,32,0.92);
        border-color: rgba(255,255,255,0.08);
        box-shadow: 0 8px 30px rgba(0,0,0,0.48);
      }
      .btn { color: #eaeaea; border-color: rgba(255,255,255,0.18); }
      .btn--primary { background: #1a73e8; color: white; border-color: transparent; }
    }
    .title { font-weight: 600; margin-bottom: 6px; }
    .desc  { opacity: 0.8; margin-bottom: 10px; }
    .row {
      display: flex; gap: 8px; justify-content: flex-end;
    }
    .btn {
      appearance: none;
      border: 1px solid rgba(0,0,0,0.18);
      background: transparent;
      border-radius: 8px;
      padding: 6px 10px;
      cursor: pointer;
      font: inherit;
      transition: transform .06s ease, background .12s ease;
    }
    .btn:hover { background: rgba(0,0,0,0.04); }
    .btn:active { transform: translateY(1px); }
    .btn--primary {
      background: #1a73e8;
      color: white;
      border-color: transparent;
    }
    .sr { position:absolute; width:1px; height:1px; clip:rect(1px,1px,1px,1px); overflow:hidden; white-space:nowrap; }
  `;

  wrap.innerHTML = `
    <div class="card" role="dialog" aria-label="Google Discover setting">
      <div class="title">Enable Google Discover?</div>
      <div class="desc">Add <code>?gl=${DISCOVER_GL}</code> to keep Discover feed consistent on this device.</div>
      <div class="row">
        <button class="btn" data-action="never" aria-label="Never show again">Never</button>
        <button class="btn" data-action="later" aria-label="Not now">Not now</button>
        <button class="btn btn--primary" data-action="enable" aria-label="Enable">Enable</button>
      </div>
      <span class="sr">Use Tab to navigate buttons</span>
    </div>
  `;

  shadow.appendChild(style);
  shadow.appendChild(wrap);

  function removePrompt() {
    try { host.remove(); } catch {}
  }

  async function onAction(action) {
    if (action === 'enable') {
      await GMAPI.set(STORAGE_KEY, true);
      removePrompt();
      if (getGL(location.href) !== DISCOVER_GL) {
        location.replace(withGL(location.href, DISCOVER_GL));
        return;
      }
      location.reload();
    } else if (action === 'later') {
      await GMAPI.set(SNOOZE_UNTIL_KEY, Date.now() + SNOOZE_MS);
      removePrompt();
    } else if (action === 'never') {
      await GMAPI.set(PROMPT_NEVER_KEY, true);
      await GMAPI.set(STORAGE_KEY, false);
      removePrompt();
    }
  }

  wrap.addEventListener('click', (e) => {
    const t = e.target;
    if (!(t instanceof Element)) return;
    const act = t.getAttribute('data-action');
    if (act) onAction(act);
  });

})();