Google: News Filter

Show or Hide news whatever you want.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name                Google: News Filter
// @name:zh-TW          Google 新聞過濾篩選
// @name:zh-CN          Google 新闻过滤筛选
// @name:ja             Googleニュースフィルター
// @name:ko             Google 뉴스 필터
// @name:ru             Новостной фильтр Google
// @version             1.0.6
// @description         Show or Hide news whatever you want.
// @description:zh-TW   可自行設定指定的新聞報社顯示或隱藏。
// @description:zh-CN   可自行设定指定的新闻报社显示或隐藏。
// @description:ja      好きなようにニュースを表示または非表示にします。
// @description:ko      원하는 뉴스를 표시하거나 숨 깁니다.
// @description:ru      Показать или скрыть новости, что вы хотите.
// @author              Hayao-Gai
// @namespace           https://github.com/HayaoGai
// @icon                https://i.imgur.com/zHU2Zt3.png
// @match               https://news.google.com/*
// @grant               GM_setValue
// @grant               GM_getValue
// ==/UserScript==

/* jshint esversion: 6 */

(function() {
    'use strict';

    // icon made by https://www.flaticon.com/authors/freepik
    const svg = `<svg width="15px" height="15px" viewBox="0 0 192.701 192.701" fill="#5f6368"><path d="M20.746,104.169l75.61-74.528l75.61,74.54c4.74,4.704,12.439,4.704,17.179,0s4.74-12.319,0-17.011l-84.2-82.997 c-4.559-4.511-12.608-4.535-17.191,0l-84.2,83.009c-4.74,4.692-4.74,12.319,0,17.011C8.307,108.873,16.006,108.873,20.746,104.169 z"/><path d="M104.946,88.373c-4.559-4.511-12.608-4.535-17.191,0l-84.2,82.997c-4.74,4.704-4.74,12.319,0,17.011 c4.74,4.704,12.439,4.704,17.179,0l75.622-74.528l75.61,74.54c4.74,4.704,12.439,4.704,17.179,0s4.74-12.319,0-17.011 L104.946,88.373z"/></svg>`;
    const css =
`.article {
    max-height: 100px;
    overflow: hidden;
    transition: all 0.3s;
}
.hide {
    max-height: 0px;
    padding: 0px !important;
}
.panel {
    border: 1px solid #dadce0;
    border-radius: 8px;
    padding: 8px;
    margin-right: 10px;
}
.title {
    font-size: 1rem;
    font-weight: 500;
    font-family: 'Google Sans', sans-serif;
    display: flex;
}
.hover {
    position: fixed;
    width: 450px;
    max-height: 1000px;
    right: 8px;
    top: 60px;
    border: 1px solid #dadce0;
    border-radius: 8px;
    z-index: 999;
    background: white;
    overflow: hidden;
    transition: max-height 0.3s;
}
.collapse1 {
    max-height: 0px;
}
.collapse2 {
    border: 0px;
}
.arrow {
    margin-left: 15px;
    padding-top: 3px;
    cursor: pointer;
    transform: rotate(0deg);
    transition: all 0.3s ease-in-out;
}
.rotateArrow {
    transform: rotate(180deg);
}
.pressed {
    background-color: #498ce4 !important;
    color: white !important;
}`;
    let scrolling = false;

    CSS();
    locationChange();
    window.addEventListener("load", init);
    window.addEventListener("scroll", update);

    function init(retry = 0) {
        // get all news title
        const titles = document.querySelectorAll("a.wEwyrc");
        // check
        if (!titles.length && retry < 5) {
            setTimeout(() => init(retry + 1), 500);
            return;
        }
        // title text
        const text = [...titles].map(title => title.innerText);
        const news = [...new Set(text)].sort();
        addMenu(news);
    }

    function addMenu(news) {
        // remove exist
        const exist1 = document.querySelector(".panel");
        const exist2 = document.querySelector(".hover");
        if (exist1) {
            exist2.firstElementChild.remove();
            addOption(exist2, news);
            return;
        }
        // get dynamic class.
        let dynamicClass = "";
        document.querySelector("[ng-non-bindable][data-ogsr-up]").classList.forEach(eachClass => {
            dynamicClass += `.${eachClass}`;
        });
        const parent = document.querySelector(dynamicClass);
        // create
        const panel = document.createElement("div");
        panel.className = "panel";
        parent.insertBefore(panel, parent.firstElementChild);
        const title = document.createElement("h2");
        title.className = "title";

        switch(document.querySelector("html").lang) {
            case "zh":
                title.innerText = "Google 新聞過濾篩選";
                break;
            case "ja":
                title.innerText = "Googleニュースフィルター";
                break;
            case "ko":
                title.innerText = "Google 뉴스 필터";
                break;
            case "ru":
                title.innerText = "Новостной фильтр Google";
                break;
            default:
                title.innerText = "Google News Filter";
        }

        panel.appendChild(title);
        const icon = document.createElement("div");
        icon.className = "arrow rotateArrow";
        icon.innerHTML = svg;
        icon.addEventListener("click", () => {
            const toggle = hover.classList.toggle("collapse1");
            setTimeout(() => hover.classList.toggle("collapse2"), toggle ? 300 : 0);
            icon.classList.toggle("rotateArrow");
        });
        title.appendChild(icon);
        const hover = document.createElement("div");
        hover.className = "hover collapse1 collapse2";
        document.body.appendChild(hover);
        // option
        addOption(hover, news);
    }

    function addOption(parent, news) {
        // create
        const div = document.createElement("div");
        div.className = "ndSf3d ttg1Pb j7vNaf Pz9Pcd a8arzf";
        // append
        parent.appendChild(div);
        // news
        news.forEach(text => singleOption(div, text));
    }

    function singleOption(div, text) {
        // create
        const div1 = document.createElement("div");
        div1.className = "To2ZZb u9jkpc hpDt6e DbQnIe rrijPb R7GTQ keNKEd";
        div1.style.cursor = "pointer";
        div1.addEventListener("click", () => setOption(div1, text));
        getOption(div1, text);
        const div2 = document.createElement("div");
        div2.className = "K9tMQ";
        const div3 = document.createElement("div");
        div3.className = "VgnMrb";
        const span1 = document.createElement("span");
        span1.className = "Ix4NZd";
        const span2 = document.createElement("span");
        span2.className = "pPbimc ljLXBd";
        span2.innerText = text;
        // append
        div.appendChild(div1);
        div1.appendChild(div2);
        div2.appendChild(div3);
        div3.appendChild(span1);
        span1.appendChild(span2);
    }

    function getOption(div, text) {
        // change color
        const isCollapse = GM_getValue(text, false);
        if (isCollapse) {
            div.classList.add("pressed");
        }
        // collapse or expand
        execution(isCollapse, text);
    }

    function setOption(div, text) {
        // change color and record
        const isCollapse = div.classList.toggle("pressed");
        GM_setValue(text, isCollapse);
        // collapse or expand
        execution(isCollapse, text);
    }

    function execution(isCollapse, text) {
        // add article class
        document.querySelectorAll("article:not(.article)").forEach(article => article.classList.add("article"));
        // collapse
        if (isCollapse) {
            document.querySelectorAll("article.article:not(.hide)").forEach(article => {
                const title = article.querySelector("a.wEwyrc").innerText;
                if (title.includes(text)) {
                    article.classList.add("hide");
                }
            });
        }
        // expand
        else {
            document.querySelectorAll("article.article.hide").forEach(article => {
                const title = article.querySelector("a.wEwyrc").innerText;
                if (title.includes(text)) {
                    article.classList.remove("hide");
                }
            });
        }
    }

    function update() {
        if (scrolling) return;
        scrolling = true;
        if (document.querySelectorAll("article:not(.article)").length) init();
        setTimeout(() => { scrolling = false; }, 1000);
    }

    function CSS() {
        const style = document.createElement("style");
        style.type = "text/css";
        style.innerHTML = css;
        document.head.appendChild(style);
    }

    function locationChange() {
        window.addEventListener('locationchange', init);
        // situation 1
        history.pushState = (f => function pushState(){
            var ret = f.apply(this, arguments);
            window.dispatchEvent(new Event('pushState'));
            window.dispatchEvent(new Event('locationchange'));
            return ret;
        })(history.pushState);
        // situation 2
        history.replaceState = (f => function replaceState(){
            var ret = f.apply(this, arguments);
            window.dispatchEvent(new Event('replaceState'));
            window.dispatchEvent(new Event('locationchange'));
            return ret;
        })(history.replaceState);
        // situation 3
        window.addEventListener('popstate', () => {
            window.dispatchEvent(new Event('locationchange'));
        });
    }

})();