Disable AMP Pages

Automatically redirects AMP pages to their original canonical links, and strips AMP hijacking from Google Search and News

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name         Disable AMP Pages
// @namespace    RGlzYWJsZSBBTVAgUGFnZXM
// @version      1.0
// @description  Automatically redirects AMP pages to their original canonical links, and strips AMP hijacking from Google Search and News
// @author       smed79
// @license      GPLv3
// @icon         https://i25.servimg.com/u/f25/11/94/21/24/amp10.png
// @match        *://*/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    const host = window.location.hostname;
    const href = window.location.href;

    // Helper: Safely extract Canonical URL
    const getCanonicalUrl = () => {
        const link = document.querySelector('link[rel="canonical"]');
        if (!link || !link.href) return null;
        try {
            const url = new URL(link.href);
            // Remove lingering amp query parameters
            if (url.searchParams.has("amp")) url.searchParams.delete("amp");
            return url.href;
        } catch (e) {
            return null;
        }
    };

    // --- 1. Clean Google Search & News Links ---
    const cleanGoogleLinks = () => {
        if (!host.includes('google.')) return;

        // Clean Google Search results (Removes AMP hijacking and tracking)
        const hijackAttrs = ['ping', 'data-ved', 'data-amp-cur', 'data-amp-title', 'data-amp', 'data-amp-vgi', 'jsaction', 'data-amp-cdn'];
        
        document.querySelectorAll('a[data-amp], a[data-amp-cdn], a[data-ved]:has(span + svg)').forEach(a => {
            hijackAttrs.forEach(attr => a.removeAttribute(attr));
            
            // Fix hardcoded AMP CDN URLs
            if (a.href.includes('cdn.ampproject.org/')) {
                const match = a.href.match(/cdn\.ampproject\.org\/(?:v|wp|c)\/s\/(.+)/);
                if (match && match[1]) {
                    a.href = 'https://' + decodeURIComponent(match[1]).split('?')[0];
                }
            }
            
            // Hide the AMP logo icon next to the link
            const icon = a.querySelector('[aria-label="AMP logo"], [aria-label="Logo AMP"]');
            if (icon) icon.style.display = 'none';
        });

        // Clean Google News (Decodes base64 jslog to find the real URL)
        if (host.includes('news.google.')) {
            document.querySelectorAll('a[jslog]:not([data-cleaned])').forEach(a => {
                const jslog = a.getAttribute('jslog');
                if (!jslog) return;
                
                try {
                    const b64 = jslog.substring(jslog.indexOf(":") + 1, jslog.indexOf(";"));
                    const decodedStr = atob(b64);
                    // Match any valid http/https URL inside the decoded payload
                    const urlMatch = decodedStr.match(/(https?:\/\/[^"'\s\]]+)/g);
                    
                    if (urlMatch) {
                        const realUrl = urlMatch.find(url => !url.includes('amp') && !url.includes('google.com'));
                        if (realUrl) {
                            a.href = realUrl;
                            a.dataset.cleaned = "true"; // Prevent processing twice
                            
                            // Force native click to bypass Google's JS listeners
                            a.addEventListener('click', (e) => {
                                e.preventDefault();
                                e.stopImmediatePropagation();
                                window.location.href = realUrl;
                            }, true);
                        }
                    }
                } catch (e) {}
            });
        }
    };

    // --- 2. Redirect standard AMP pages ---
    const checkAMPPage = () => {
        // Detects standard AMP properties natively rather than guessing URLs
        const isAMP = (document.documentElement && (
                      document.documentElement.hasAttribute('amp') || 
                      document.documentElement.hasAttribute('⚡'))) || 
                      document.querySelector('script[src*="cdn.ampproject.org"]');
        
        if (isAMP) {
            const canonical = getCanonicalUrl();
            if (canonical && canonical !== window.location.href) {
                window.location.replace(canonical);
                return true; // Indicates we are redirecting
            }
        }
        return false;
    };

    // --- 3. Redirect Yandex Turbo Pages ---
    const checkYandexTurbo = () => {
        if ((host.includes('yandex.ru') && href.includes('/turbo')) || host.includes('turbopages.org')) {
            const canonical = getCanonicalUrl();
            if (canonical) {
                window.location.replace(canonical);
                return true;
            }
        }
        return false;
    };

    // --- Execution ---
    const observer = new MutationObserver(() => {
        // 1. Run Google Checks First
        cleanGoogleLinks();

        // 2. Check standard AMP site redirects (If redirecting, stop processing)
        if (checkAMPPage()) return;

        // 3. Check Yandex Turbo
        checkYandexTurbo();
    });

    // Safely attach observer as early as possible
    if (document.documentElement) {
        observer.observe(document.documentElement, { childList: true, subtree: true });
    } else {
        const initObserver = new MutationObserver((mutations, me) => {
            if (document.documentElement) {
                observer.observe(document.documentElement, { childList: true, subtree: true });
                me.disconnect();
            }
        });
        initObserver.observe(document, { childList: true, subtree: true });
    }

})();