zbluebugz / facebook-clean-my-feeds

Clean up Facebook feeds by hiding sponsored, suggestions and other posts based on keywords.
GNU General Public License v3.0
115 stars 12 forks source link

Instagram reels skip function here #69

Open Dark3n89 opened 3 months ago

Dark3n89 commented 3 months ago

I've been working on the removal script for a long time, it's almost unreal ... Here I made a function that automatically skips INSTAGRAM REELS and remembers "infected" url addresses, for the next faster rewind. I like your project, you saved me a lot of time and I would like to return the favor :) As a bonus, you can save the list of unwanted urls for future use when you click on the icon :)

` // ==UserScript== // @name Skip Instagram Content on Facebook Reels with URL Tracking // @namespace Skip Instagram // @version 1.0 // @description Automatically skip URLs that have been previously skipped and click "Next" if Instagram content is detected on Facebook Reels. Displays total skipped reels count in a popup and allows exporting skipped URLs to a text file. // @author Projekt Darkside - Brno city Bohemia. // @match https://www.facebook.com/* // @grant none // ==/UserScript==

(function() { 'use strict';

// Multilanguage support for "Next card" button
const multilangNextButton = {
    'en': 'Next card',
    'cs': 'Další karta',
    // Add more languages as needed
};

// Function to save skipped URL
function saveSkippedURL(url) {
    let skippedURLs = JSON.parse(localStorage.getItem('skippedURLs')) || [];
    if (!skippedURLs.includes(url)) {
        skippedURLs.push(url);
        localStorage.setItem('skippedURLs', JSON.stringify(skippedURLs));
        updateSkippedCountBadge(skippedURLs.length);
        showAndAutoHideBadge();
    }
}

// Function to get all skipped URLs
function getSkippedURLs() {
    return JSON.parse(localStorage.getItem('skippedURLs')) || [];
}

// Function to check if URL is skipped
function isURLSkipped(url) {
    let skippedURLs = getSkippedURLs();
    return skippedURLs.includes(url);
}

// Function to detect browser language
function detectBrowserLanguage() {
    return navigator.language || navigator.userLanguage || 'en';
}

// Function to update the skipped count badge
function updateSkippedCountBadge(count) {
    let badge = document.getElementById('skippedCountBadge');
    if (!badge) {
        badge = document.createElement('div');
        badge.id = 'skippedCountBadge';
        badge.style.cssText = 'position: fixed; bottom: 10px; left: 10px; background-color: #007bff; color: #fff; border-radius: 50%; padding: 5px; cursor: pointer; z-index: 9999; display: none;';
        badge.title = 'Total skipped Instagram Reels';
        document.body.appendChild(badge);
    }
    badge.textContent = count;
}

// Function to show badge and automatically hide it after a short delay
function showAndAutoHideBadge() {
    let badge = document.getElementById('skippedCountBadge');
    if (badge) {
        badge.style.display = 'block';
        setTimeout(() => {
            badge.style.display = 'none';
        }, 4000); // Hide badge after 4 seconds
    }
}

// Function to export skipped URLs to a text file
function exportSkippedURLs() {
    let skippedURLs = getSkippedURLs();
    let blob = new Blob([skippedURLs.join('\n')], { type: 'text/plain' });
    let url = URL.createObjectURL(blob);
    let a = document.createElement('a');
    a.style.display = 'none';
    a.href = url;
    a.download = 'skipped_urls.txt';
    document.body.appendChild(a);
    a.click();
    window.URL.revokeObjectURL(url);
}

function skipInstagramContent() {
    if (window.location.href.includes("/reel/")) {
        if (isURLSkipped(window.location.href)) {
            // If URL is already skipped, click on the "Next card" button
            let nextButton = findNextButton();
            if (nextButton) {
                console.log("Skipping already skipped URL:", window.location.href);
                nextButton.click();
            }
            return;
        }

        let foundInstagramContent = false;

        // Check visible elements containing the word "Instagram"
        document.querySelectorAll('*').forEach(function(node) {
            if (node.offsetParent !== null && node.innerText && node.innerText.includes("Instagram")) {
                console.log("Found Instagram content in text:", node);
                foundInstagramContent = true;
            }
        });

        // Check visible images containing the specified URL
        document.querySelectorAll('img').forEach(function(img) {
            if (img.offsetParent !== null && img.src.includes('https://static.xx.fbcdn.net/rsrc.php/v3/yy/r/1M3EBv90kJA.png')) {
                console.log("Found Instagram content in image:", img);
                foundInstagramContent = true;
            }
        });

        // If Instagram content is found, click on "Next card" and save URL
        if (foundInstagramContent) {
            let nextButton = findNextButton();
            if (nextButton) {
                console.log("Clicking next button:", nextButton);
                saveSkippedURL(window.location.href);
                nextButton.click();
            }
        }
    }
}

// Function to find the "Next card" button based on language
function findNextButton() {
    let language = detectBrowserLanguage().split('-')[0]; // Extract language code
    let ariaLabel = multilangNextButton[language];
    if (ariaLabel) {
        return document.querySelector(`[aria-label="${ariaLabel}"]`);
    } else {
        console.warn(`No translation found for language: ${language}`);
        return null;
    }
}

// Initialize check on page load
skipInstagramContent();

// Observe DOM changes and apply function to newly loaded posts
const observer = new MutationObserver(skipInstagramContent);
observer.observe(document.body, { childList: true, subtree: true });

})(); `

Dark3n89 commented 3 months ago

Allready working at pure extenssion... i have big problems with same seasson or localstorage load back. ..

image

zbluebugz commented 3 months ago

Userscript looks good - parts of it is likely to be implemented in fb-cmf.

re issue with storage: - Are you referring to the userscript or the extension?

If userscript, FB will wipe out the "unauthorised" cookies and most storage options.

The following options would work:

fb-cmf uses the Indexed DB option to store user's settings. Relies on the idb-keyval library to manage the storage. (https://unpkg.com/browse/idb-keyval@6.0.3/README.md)

If extension, In Firefox use this: browser.storage.local.set(...) / browser.storage.local.get(...) In Chromium use this: chrome.storage.local.set(...) / chrome.storage.local.get(...)

In the extension, you might need the "permissions" option "unlimitedStorage" in the manifest.json file - this allows more than 5Mb of data to be stored.

Dark3n89 commented 3 months ago

I was talking about my code. It should remember the offending URLs and skip them much faster next time. You will notice this feature when 3-4-6 Instagram reels are skipped in a row.

Maybe it's my fault, I have a complexly secured system. Anyway, I can't keep the list of non-compliant URLs saved. The values are reset to zero very often, or in a new window.

Damn it, the main thing is already working and working damn well.

Here is the newest version: https://github.com/Dark3n89/Instagram-reel-remover but still +/- same bug.

zbluebugz commented 3 months ago

FYI, the indexedDB data is wiped out when the browser clears the cache.

I do note that sometimes the script stops working if db is not opened/ready.

Below is a suggestion on tweaking the code that detects IG content (you'll need to test it more):

// -- This html pattern occurs 1-2 times per reel post
const elements = Array.from(document.querySelectorAll('div > span[dir] > span > div'));
for (const node of elements) {
    if (node.offsetParent !== null && node.innerText && node.innerText.includes("Instagram")) {
        foundInstagramContent = true;
        break;
    }
};

if (foundInstagramContent === false) {
    // -- Try again, but query for a sprite image that has the IG icon
    // -- (do not specify the filename - fb has multiple copies with different filenames)
    // -- Has to be in a certain HTML structure/pattern that is unique to the IG reel posts
    foundInstagramContent = (document.querySelector('span > div > div > span > i[style*="background-image"]') !== null);
}
Dark3n89 commented 3 months ago

I am currently working on a version of a regular extension where everything works perfectly and holds the data until the user reloads the extension.

I experimented with an external database, in my new project the reels are destroyed immediately after loading the site even as suggestions.

But it will still take some time, I assume that the external database will help all people globally to get rid of ballast.