Tiktok revanced

Auto AD Skip tiktok + 2x speed button

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==UserScript==
// @name         Tiktok revanced
// @name:pt-br   Pulador de anúncios do tiktok
// @namespace    http://tampermonkey.net/
// @version      28-12-2025
// @description:pt-br   Scrolla os anúncios do tiktok automaticamente e adiciona um botão que coloca velocidade 2x
// @description         Auto AD Skip tiktok + 2x speed button
// @author       Potly
// @match        https://www.tiktok.com/*
// @icon         https://www.tiktok.com/favicon.ico
// @grant        none
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const TOGGLE_KEY = "autoAdSkip_enabled";
    let enabled = localStorage.getItem(TOGGLE_KEY);
    if (enabled === null) enabled = "true";
    enabled = enabled === "true";

    function saveState() {
        localStorage.setItem(TOGGLE_KEY, enabled ? "true" : "false");
    }

    // ---------------------------
    // BOTÃO TOGGLE
    // ---------------------------
    function createToggle() {
        const wrapper = document.createElement("div");
        wrapper.style.position = "fixed";
        wrapper.style.top = "30px";
        wrapper.style.left = "170px";
        wrapper.style.zIndex = "999999";
        wrapper.style.display = "flex";
        wrapper.style.alignItems = "center";
        wrapper.style.gap = "10px";
        wrapper.style.userSelect = "none";

        // texto
        const label = document.createElement("span");
        label.textContent = "Auto AD Skip";
        label.style.fontSize = "18px";
        label.style.fontFamily = "Arial, sans-serif";
        label.style.fontWeight = "600";
        label.style.color = "#ffffff";
        wrapper.appendChild(label);

        // container do toggle
        const toggle = document.createElement("div");
        toggle.style.width = "50px";
        toggle.style.height = "26px";
        toggle.style.borderRadius = "50px";
        toggle.style.background = enabled ? "#4caf50" : "#ccc";
        toggle.style.position = "relative";
        toggle.style.cursor = "pointer";
        toggle.style.transition = "0.25s";
        toggle.style.boxShadow = "0 0 5px rgba(0,0,0,0.2)";

        // bolinha
        const knob = document.createElement("div");
        knob.style.width = "22px";
        knob.style.height = "22px";
        knob.style.background = "#fff";
        knob.style.borderRadius = "50%";
        knob.style.position = "absolute";
        knob.style.top = "2px";
        knob.style.left = enabled ? "26px" : "2px";
        knob.style.transition = "0.25s";
        knob.style.boxShadow = "0 2px 5px rgba(0,0,0,0.3)";

        toggle.appendChild(knob);
        wrapper.appendChild(toggle);
        document.body.appendChild(wrapper);

        toggle.onclick = () => {
            enabled = !enabled;
            saveState();

            // animação on e off
            toggle.style.background = enabled ? "#4caf50" : "#ccc";
            knob.style.left = enabled ? "26px" : "2px";
        };
    }

    if (document.readyState !== "loading") createToggle();
    else document.addEventListener("DOMContentLoaded", createToggle);

    // ---------------------------
    // Detecta se é ad
    // ---------------------------

    const selector = "div.css-3fgk4e-7937d88b--DivItemTagsContainer.e1d0egbk0 > div";
    const clickButtonSelector = "#main-content-homepage_hot > aside > div > div:nth-child(2) > button";

    const adKeywords = [
        "anúncio", "anuncio", "patrocinado", "patrocinada",
        "publicidade", "publi", "sponsored", "ad", "promo"
    ];

    const processed = new WeakSet();

    function isAd(el) {
        const text = (el.innerText || "").toLowerCase();
        return adKeywords.some(k => text.includes(k));
    }
 // acho q ter um delayzinho entre cada clique é bom, pq um pc ruim pode bugar

    let lastClick = 0;
function clickButton() {
    if (!enabled) return;
    const now = Date.now();
    if (now - lastClick < 500) return; // evita spam
    lastClick = now;
    const btn = document.querySelector(clickButtonSelector);
    if (btn) btn.click();

    }

    function handleNewAds() {
        document.querySelectorAll(selector).forEach(el => {
            if (processed.has(el)) return;
            if (!isAd(el)) return;

            processed.add(el);

            const io = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        if (entry.isIntersecting && enabled) {
            clickButton();
            io.disconnect(); // para evitar vazamento de memoria
        }
    });
}, { threshold: 0.01 });


            io.observe(el);
        });
    }


//-----------------------------------------------------------

const SPEED_WHILE_HOLD = 2.0;
    const DEFAULT_SPEED = 1.0;

        const targetContainerSelector =
"section[class*='SectionActionBarContainer']";


//pega o vídeo que está assistindo no momento
function getCurrentVideo() {
        const videos = document.querySelectorAll("video");
        for (const v of videos) {
            const r = v.getBoundingClientRect();
            if (r.width > 0 && r.height > 0) return v;
        }
return null;
    }

function setSpeed(speed) {
        const video = getCurrentVideo();
        if (video) video.playbackRate = speed;
    }

        function createHoldButton(container) {
    if (container.querySelector("#hold-speed-wrapper")) return;

    const wrapper = document.createElement("div");
    wrapper.id = "hold-speed-wrapper";
    wrapper.style.position = "absolute";
    wrapper.style.left = "50%";
    wrapper.style.transform = "translateX(-50%)";
    wrapper.style.bottom = "100%";
    wrapper.style.marginBottom = "12px";
    wrapper.style.display = "flex";
    wrapper.style.flexDirection = "column";
    wrapper.style.alignItems = "center";
    wrapper.style.zIndex = "999999";


// ícone fast-forward (CSS)
const style = document.createElement("style");
style.textContent = `
.ff-icon {
    display: flex;
    gap: -3px;
    margin-left: 3px;
}

.ff-icon span {
    width: 0;
    height: 0;
    border-top: 8px solid transparent;
    border-bottom: 8px solid transparent;
    border-left: 12px solid white;
}
`;
document.head.appendChild(style);


    const btn = document.createElement("div");

    btn.innerHTML = `
  <div class="ff-icon">
    <span></span>
    <span></span>
  </div>
`;

    btn.style.display = "flex";
btn.style.justifyContent = "center";
btn.style.alignItems = "center";

btn.style.width = "48px";
btn.style.height = "48px";
btn.style.borderRadius = "50%";

btn.style.backgroundColor = "rgba(255, 255, 255, 0.12)";
btn.style.cursor = "pointer";

btn.style.transition = "200ms ease-in-out";
btn.style.marginTop = "8px";
btn.style.marginBottom = "6px";

btn.style.fontSize = "0px"; // igual TikTok
btn.style.userSelect = "none";


    const label = document.createElement("div");
    label.innerHTML = "<strong>2.0X</strong>";
    label.style.fontSize = "12px";
    label.style.marginTop = "4px";
    label.style.color = "rgba(255, 255, 255, 0.75)";
    label.style.opacity = "0.9";

// --- HOLD EVENTS ---
btn.addEventListener("mousedown", () => setSpeed(SPEED_WHILE_HOLD));
btn.addEventListener("mouseup", () => setSpeed(DEFAULT_SPEED));
btn.addEventListener("mouseleave", () => setSpeed(DEFAULT_SPEED));
btn.addEventListener("touchstart", () => setSpeed(SPEED_WHILE_HOLD));
btn.addEventListener("touchend", () => setSpeed(DEFAULT_SPEED));
btn.addEventListener("touchcancel", () => setSpeed(DEFAULT_SPEED));

// monta corretamente
wrapper.appendChild(btn);
wrapper.appendChild(label);

container.style.position = "relative";
container.prepend(wrapper);}


    function tryInjectButton() {
    document
        .querySelectorAll("section[class*='SectionActionBarContainer']")
        .forEach(container => {
            createHoldButton(container);
        });
}

//espera aparecer os botão do lado, pq o vídeo carrega antes doos botão e isso pode bugar a extensão se n esperar blablabla
function waitForFirstActionBar() {
    return new Promise(resolve => {
        const check = () => {
            const bar = document.querySelector(
                "section[class*='SectionActionBarContainer']"
            );
            if (bar) {
                resolve();
            } else {
                requestAnimationFrame(check);
            }
        };
        check();
    });
}

    // Observer pra feed infinito
   const mo = new MutationObserver(() => {
    tryInjectButton();
    handleNewAds();
});

mo.observe(document.body, {
    childList: true,
    subtree: true
});

// inicial
waitForFirstActionBar().then(() => {
    tryInjectButton();
    handleNewAds();
});

//evita vazamento de memoria
const io = new IntersectionObserver(entries => {
    entries.forEach(entry => {
        if (entry.isIntersecting && enabled) {
            clickButton();
            io.disconnect(); // <- IMPORTANTE
        }
    });
}, { threshold: 0.01 });


})();