collapserage / Onliner.by - Hide Disliked Comments

// ==UserScript==
// @name         Onliner.by - Hide Disliked Comments
// @namespace    https://onliner.by/
// @version      1.0
// @match        https://*.onliner.by/*
// @grant        GM_addStyle
// @copyright    2021, collapserage (https://openuserjs.org/users/collapserage)
// @license      MIT
// @updateURL    https://openuserjs.org/meta/collapserage/Onliner.by_-_Hide_Disliked_Comments.meta.js
// @downloadURL  https://openuserjs.org/install/collapserage/Onliner.by_-_Hide_Disliked_Comments.user.js
// ==/UserScript==

(function () {
  'use strict';

  const COMMENTS_ROOT_SELECTOR = '#fast-comments-root';
  const COMMENT_SELECTOR = '.news-comment__unit';
  const DISLIKE_SELECTOR = '.news-comment__button_counter_down';
  const LIKE_SELECTOR = '.news-comment__button_counter_up';
  const DISLIKE_TO_LIKE_RATIO = 1.5;
  const MINIMUM_NUMBER_OF_DISLIKES = 5;

  GM_addStyle(`
        .negative {
            filter: blur(3px) opacity(0.6);
        }

        .negative:hover {
            transition: filter 300ms 600ms;
            filter: none;
        }
    `);

  function getNumberFromNode(node) {
    if (!node) return;

    return Number(node.textContent);
  }

  function hideNegativeComments(commentNode) {
    const dislikes = getNumberFromNode(commentNode.querySelector(DISLIKE_SELECTOR));
    const likes = getNumberFromNode(commentNode.querySelector(LIKE_SELECTOR));

    if (!dislikes || !likes) return;

    if (dislikes / likes >= DISLIKE_TO_LIKE_RATIO && dislikes >= MINIMUM_NUMBER_OF_DISLIKES && !commentNode.classList.contains('negative')) {
      commentNode.classList.add('negative');
    }
  }

  const commentsRootNode = document.querySelector(COMMENTS_ROOT_SELECTOR);

  const observer = new MutationObserver((mutationsList) => {
    mutationsList
      .flatMap((mutation) => Array.from(mutation.addedNodes))
      .filter((node) => node.nodeType === Node.ELEMENT_NODE)
      .flatMap((node) => Array.from(node.querySelectorAll(COMMENT_SELECTOR)))
      .forEach(hideNegativeComments)
  });

  if (commentsRootNode) {
    observer.observe(commentsRootNode, {
      childList: true,
      subtree: true
    });

    commentsRootNode.querySelectorAll(COMMENT_SELECTOR).forEach(hideNegativeComments);
  }
})();