Lemmy Post Keyword Filter

Automatically hide posts that match keywords from Lemmy sites.

// ==UserScript==
// @name         Lemmy Post Keyword Filter
// @namespace    https://zetaphor.com/
// @homepageURL	 https://github.com/Zetaphor/lemmy-keyword-filter
// @supportURL	 https://github.com/Zetaphor/lemmy-keyword-filter/issues
// @version      1.1
// @license	     WTFPL
// @description  Automatically hide posts that match keywords from Lemmy sites.
// @author       Zetaphor
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @run-at       document-end
// @match        *://*/*
// ==/UserScript==

(function () {
  'use strict';

  // Check if the main Lemmy selector is present
  const lemmySelectorPresent = document.querySelector('#app.lemmy-site');
  if (!lemmySelectorPresent) {
    console.log('Not a Lemmy site. Script will not run.');
    return;
  }

  // Function to hide the post element and the preceding <hr> tag
  function hidePost(postElement) {
    postElement.style.display = 'none';
    const precedingHR = postElement.previousElementSibling;
    if (precedingHR && precedingHR.tagName === 'HR') {
      precedingHR.style.display = 'none';
    }
  }

  // Function to check if the post title contains any of the keywords
  function checkKeywords(postElement, keywords) {
    const postTitle = postElement.querySelector('.post-title span');
    if (!postTitle) return;

    const titleText = postTitle.innerText.toLowerCase();
    for (const keyword of keywords) {
      if (titleText.includes(keyword.toLowerCase())) {
        hidePost(postElement);
        break;
      }
    }
  }

  // Main function to apply the keyword filtering
  function filterPostsByKeywords(keywords) {
    // Do nothing if the keyword list is empty
    if (keywords.length === 0) return;

    const postListings = document.querySelectorAll('.post-listing');
    postListings.forEach((postElement) => {
      checkKeywords(postElement, keywords);
    });
  }

  // Settings page to edit the list of keywords
  function createSettingsPage() {
    const settingsHTML = `
      <div>
        <h2 style="color: white;">Lemmy Keyword Filter Settings</h2>
        <label for="keyword-list" style="color: white;">Enter keywords (comma-separated):</label>
        <br>
        <input type="text" id="keyword-list" style="width: 300px;" value="">
        <br><br>
        <button id="save-button">Save</button>
      </div>
    `;

    const popupDiv = document.createElement('div');
    popupDiv.style.position = 'fixed';
    popupDiv.style.top = '20%';
    popupDiv.style.left = '20%';
    popupDiv.style.width = '60%';
    popupDiv.style.backgroundColor = 'grey';
    popupDiv.style.color = 'white';
    popupDiv.style.padding = '20px';
    popupDiv.innerHTML = settingsHTML;
    document.body.appendChild(popupDiv);

    const saveButton = document.getElementById('save-button');
    const keywordListInput = document.getElementById('keyword-list');

    // Load the saved keywords and display them in the input field
    const savedKeywords = GM_getValue('lemmyKeywords', []);
    keywordListInput.value = savedKeywords.join(', ');

    // Save the keywords when the Save button is clicked
    saveButton.addEventListener('click', () => {
      let keywords = keywordListInput.value.split(',').map((keyword) => keyword.trim());
      keywords = keywords.filter(keyword => keyword.length > 0); // filter out empty strings
      GM_setValue('lemmyKeywords', keywords);
      filterPostsByKeywords(keywords);
      popupDiv.remove(); // Close the settings page after saving
    });
  }

  // Function to open the settings page
  function openSettingsPage() {
    createSettingsPage();
  }

  // Add the settings page option to the Tampermonkey menu
  GM_registerMenuCommand('Lemmy Keyword Filter Settings', openSettingsPage);

  // Get the saved keywords and apply the filtering
  const savedKeywords = GM_getValue('lemmyKeywords', []);
  filterPostsByKeywords(savedKeywords);
})();