您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
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 using IndexedDB for storage.
// ==UserScript== // @name Remove & perma block instagram reels from Facebook // @namespace IG GONE // @version 1.2 // @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 using IndexedDB for storage. // @author Projekt Darkside - Brno city Bohemia // @match https://www.facebook.com/* // @grant none // ==/UserScript== (async function() { 'use strict'; const reelDurationMinutes = 2; let db; // Vícejazyčná podpora pro tlačítko "Další karta" const multilangNextButton = { 'en': 'Next card', 'cs': 'Další karta', 'sk': 'Ďalšia karta', 'fr': 'Carte suivante', 'es': 'Siguiente tarjeta', 'de': 'Nächste Karte', 'it': 'Prossima carta', 'pt': 'Próximo cartão', 'ru': 'Следующая карта', 'ja': '次のカード', }; // Vícejazyčná podpora pro text v badge const multilangBadgeText = { 'en': 'Skipped (count) IG reels, this script saved you (time) minutes.', 'cs': 'Přeskočeno (count) IG reelů, tento skript vám ušetřil (time) minut.', 'sk': 'Preskočených (count) IG reelov, tento skript vám ušetril (time) minút.', 'fr': '(count) IG reels ignorés, ce script vous a fait gagner (time) minutes.', 'es': 'Saltado (count) IG reels, este script te ahorró (time) minutos.', 'de': '(count) IG-Reels übersprungen, dieses Skript hat Ihnen (time) Minuten gespart.', 'it': 'Saltato (count) IG reels, questo script ti ha fatto risparmiare (time) minuti.', 'pt': 'Ignorado (count) IG reels, este script te poupou (time) minutos.', 'ru': 'Пропущено (count) IG рилов, этот скрипт сэкономил вам (time) минут.', 'ja': 'スキップされた (count) IGリール、このスクリプトはあなたの時間を (time) 分節約しました。', }; async function openDatabase() { return new Promise((resolve, reject) => { const request = indexedDB.open('InstagramReelsDB', 1); request.onupgradeneeded = function(event) { db = event.target.result; if (!db.objectStoreNames.contains('skippedURLs')) { db.createObjectStore('skippedURLs', { keyPath: 'url' }); } }; request.onsuccess = function(event) { db = event.target.result; resolve(db); }; request.onerror = function(event) { reject('Error opening database: ' + event.target.errorCode); }; }); } async function saveSkippedURL(url) { return new Promise((resolve, reject) => { const transaction = db.transaction(['skippedURLs'], 'readwrite'); const objectStore = transaction.objectStore('skippedURLs'); const request = objectStore.add({ url: url }); request.onsuccess = function(event) { updateSkippedCountBadge(); resolve(event.target.result); }; request.onerror = function(event) { if (event.target.error.name === 'ConstraintError') { resolve(false); // URL již existuje } else { reject('Error saving URL: ' + event.target.error); } }; }); } async function getSkippedURLs() { return new Promise((resolve, reject) => { const transaction = db.transaction(['skippedURLs']); const objectStore = transaction.objectStore('skippedURLs'); const request = objectStore.getAll(); request.onsuccess = function(event) { resolve(event.target.result); }; request.onerror = function(event) { reject('Error getting URLs: ' + event.target.error); }; }); } async function isURLSkipped(url) { return new Promise((resolve, reject) => { const transaction = db.transaction(['skippedURLs']); const objectStore = transaction.objectStore('skippedURLs'); const request = objectStore.get(url); request.onsuccess = function(event) { resolve(!!event.target.result); }; request.onerror = function(event) { reject('Error checking URL: ' + event.target.error); }; }); } function getBadgeText(count, time) { let language = detectBrowserLanguage().split('-')[0]; let template = multilangBadgeText[language] || multilangBadgeText['en']; return template.replace('(count)', count).replace('(time)', time); } async function updateSkippedCountBadge() { let skippedURLs = await getSkippedURLs(); let count = skippedURLs.length; let savedTime = count * reelDurationMinutes; 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: 10px; padding: 10px; cursor: pointer; z-index: 9999;'; badge.title = 'Celkový počet přeskočených Instagram Reels a ušetřený čas'; badge.onclick = exportSkippedURLs; document.body.appendChild(badge); } badge.textContent = getBadgeText(count, savedTime); } function showAndAutoHideBadge() { let badge = document.getElementById('skippedCountBadge'); if (badge) { badge.style.display = 'block'; setTimeout(() => { badge.style.display = 'none'; }, 4000); } } async function exportSkippedURLs() { let skippedURLs = await getSkippedURLs(); let urls = skippedURLs.map(item => item.url); let blob = new Blob([urls.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); } async function skipInstagramContent() { if (window.location.href.includes("/reel/")) { let isSkipped = await isURLSkipped(window.location.href); if (isSkipped) { let nextButton = findNextButton(); if (nextButton) { nextButton.click(); } return; } let foundInstagramContent = false; document.querySelectorAll('*').forEach(function(node) { if (node.offsetParent !== null && node.innerText && node.innerText.includes("Instagram")) { foundInstagramContent = true; } }); 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')) { foundInstagramContent = true; } }); if (foundInstagramContent) { let nextButton = findNextButton(); if (nextButton) { await saveSkippedURL(window.location.href); nextButton.click(); } } } } function findNextButton() { let language = detectBrowserLanguage().split('-')[0]; let ariaLabel = multilangNextButton[language]; if (ariaLabel) { return document.querySelector(`[aria-label="${ariaLabel}"]`); } else { return null; } } function detectBrowserLanguage() { return navigator.language || navigator.userLanguage || 'en'; } window.addEventListener('load', async () => { await openDatabase(); await updateSkippedCountBadge(); }); window.addEventListener('beforeunload', async () => { await updateSkippedCountBadge(); }); const observer = new MutationObserver(skipInstagramContent); observer.observe(document.body, { childList: true, subtree: true }); skipInstagramContent(); })();