Greasy Fork is available in English.

Aniworld.to Autoplay

Autoplay for Aniworld.to

// Configurable Settings
const OUTRO_SKIP_THRESHOLD = 90; // Time in seconds remaining to skip at the outro
const SKIP_FORWARD_TIME = 85; // Time in seconds to skip forward when 'V' is pressed
const SKIP_AHEAD_TIME = 10; // Time to skip ahead with right arrow button in seconds. This is so you don't have to click on the slider
const SKIP_BACKWARD_TIME = 10; // Time to skip back with left arrow button in seconds. This is so you don't have to click on the slider
const VIDEO_PLAYER = "sandratableother.com";

// Press F to fullscreen.
// Press V to skip intro (press when Intro beginns)

// I'll try to keep it updated at all times. UPDATES AT https://greasyfork.org/en/scripts/518391
// But if it isn't working you have to change the const VIDEO_PLAYER url to the current one.
// You'll get a pop up with the new url to copy if I didn't update it already.

// ==UserScript==
// @name         Aniworld.to Autoplay
// @namespace    http://tampermonkey.net/
// @version      5.1
// @description  Autoplay for Aniworld.to
// @exclude      *://facebook.com/*
// @exclude      *://platform.twitter.com/*
// @exclude      *://voe.sx/*
// @match        *://aniworld.to/*
// @match        *://*/*
// @grant        none
// @license MIT
// ==/UserScript==

(function () {
    'use strict';

// Load skip state from localStorage, default to true if not set
    let skipToNextEpisodeEnabled = JSON.parse(localStorage.getItem('skipToNextEpisodeEnabled')) ?? true;

    function toggleSkipToNextEpisode() {
        skipToNextEpisodeEnabled = !skipToNextEpisodeEnabled;
        localStorage.setItem('skipToNextEpisodeEnabled', JSON.stringify(skipToNextEpisodeEnabled));

        const toggleButton = document.querySelector('.skip-toggle-button .Autoplay-button');
        const tooltip = document.querySelector('.skip-toggle-button .plyr__tooltip');
        if (toggleButton && tooltip) {
            updateToggleSwitch(toggleButton, tooltip);
        }
    }


    // Extract the URL from the video element and compare it
    function checkVideoPlayerUrl() {
        const videoElement = document.querySelector('video#voe-player');
        if (videoElement) {
            const videoSrc = videoElement.getAttribute('src'); 
            if (!videoSrc) {
                console.error("Video src attribute is missing or empty.");
                return;
            }

            // Parse the URL from the `src` attribute if it's a full URL or blob
            const parsedUrl = videoSrc.startsWith("blob:") ? new URL(videoSrc.slice(5)) : new URL(videoSrc);
            const videoHost = parsedUrl.hostname; 

            if (videoHost !== VIDEO_PLAYER) { 
                alert(`The video player URL has changed                                                    Copy -> ${videoHost} and change it in the script.`);
            } else {
                console.log("Video player URL matches.");
            }
        } else {
            console.error("Video element with ID 'voe-player' not found.");
        }
    }

    // Call the function on page load
    window.addEventListener('load', function () {
        checkVideoPlayerUrl();
    });

// add skip button
    function addSkipToggleButton() {
        const controls = document.querySelector('.plyr__controls');
        if (controls) {
            const button = document.createElement('button');
            button.classList.add('plyr__controls__item', 'plyr__control', 'skip-toggle-button', 'Autoplay-button');
            button.type = 'button';
            button.setAttribute('aria-label', skipToNextEpisodeEnabled ? 'Disable skip to next episode' : 'Enable skip to next episode');

            const toggleContainer = document.createElement('div');
            toggleContainer.classList.add('Autoplay-button-container');

            const toggleSwitch = document.createElement('div');
            toggleSwitch.classList.add('Autoplay-button');
            toggleSwitch.setAttribute('aria-checked', skipToNextEpisodeEnabled.toString());

            const tooltip = document.createElement('span');
            tooltip.classList.add('plyr__tooltip');
            tooltip.textContent = skipToNextEpisodeEnabled ? 'Autoplay is enabled' : 'Autoplay is disabled';

            toggleContainer.appendChild(toggleSwitch);
            button.appendChild(toggleContainer);
            button.appendChild(tooltip);

            button.addEventListener('click', toggleSkipToNextEpisode);
            controls.insertBefore(button, controls.lastChild);

            updateToggleSwitch(toggleSwitch, tooltip);
        }
    }

// Updater for the autoplay button
    function updateToggleSwitch(toggleSwitch, tooltip) {
        if (skipToNextEpisodeEnabled) {
            toggleSwitch.style.backgroundColor = '#ffffff';
            toggleSwitch.style.transform = 'translateX(12px)';
            tooltip.textContent = 'Autoplay On';
        } else {
            toggleSwitch.style.backgroundColor = '#bbb';
            toggleSwitch.style.transform = 'translateX(0px)';
            tooltip.textContent = 'Autoplay Off';
        }
    }


// Function to press the play button
    function playVideo() {
        if (!skipToNextEpisodeEnabled) return;
        const playButton = document.querySelector('button.plyr__controls__item.plyr__control[data-plyr="play"]');
        if (playButton) {
            playButton.click();
            console.log("Play button clicked.");
        } else {
            console.log("Play button not found.");
        }
    }
// Function to skip 90seconds/Intro
    function skipForward() {
        const video = document.querySelector('video');
        if (video) {
            video.currentTime = Math.min(video.currentTime + SKIP_FORWARD_TIME, video.duration);
        } else {
            console.error("Video element not found for skipping");
        }
    }

// Function to check for end of slider/outro
    function checkAndPostMessage() {
        if (skipToNextEpisodeEnabled) {
            const video = document.querySelector('video');
            if (video) {
                if (video.duration - video.currentTime <= OUTRO_SKIP_THRESHOLD) {
                    window.parent.postMessage({ action: 'skipToNextEpisode' }, '*');
                }
            }
        }
    }
// Function to get the url of the next episode/searies
    function getNextEpisodeUrl() {
        const currentEpisodeUrl = window.location.href;
        const episodeMatch = currentEpisodeUrl.match(/\/episode-(\d+)/);
        if (episodeMatch && episodeMatch[1]) {
            const currentEpisodeNumber = parseInt(episodeMatch[1], 10);

            const episodeLinks = Array.from(document.querySelectorAll('ul li a[data-episode-id]'));
            const totalEpisodes = episodeLinks.length;

            if (currentEpisodeNumber < totalEpisodes) {
                const nextEpisodeNumber = currentEpisodeNumber + 1;
                return currentEpisodeUrl.replace(/\/episode-\d+/, `/episode-${nextEpisodeNumber}`);
            } else {
                const currentSeasonMatch = currentEpisodeUrl.match(/\/staffel-(\d+)\//);
                if (currentSeasonMatch && currentSeasonMatch[1]) {
                    const currentSeason = parseInt(currentSeasonMatch[1], 10);
                    const nextSeason = currentSeason + 1;
                    return currentEpisodeUrl.replace(/\/staffel-\d+\/episode-\d+/, `/staffel-${nextSeason}/episode-1`);
                }
            }
        }
        return null;
    }

// Fullscreen handler
    function handleFullscreen() {
        if (window.location.host.includes('aniworld.to')) {
            const iframe = document.querySelector('.inSiteWebStream iframe');
            if (iframe) {
                try {
                    iframe.focus();
                    console.log("Focused on iframe.");
                    iframe.contentWindow.postMessage({ action: 'clickFullscreen' }, '*');
                    console.log("Message sent to iframe for fullscreen.");
                } catch (err) {
                    console.error("Failed to communicate with iframe:", err);
                }
            } else {
                console.log("Iframe not found in inSiteWebStream.");
            }
        } else if (window.location.host.includes(VIDEO_PLAYER)) {
            const fullscreenButton = document.querySelector('button[data-plyr="fullscreen"]');
            if (fullscreenButton) {
                fullscreenButton.click();
                console.log("Fullscreen button clicked in iframe.");
            } else {
                console.log("Fullscreen button not found in iframe.");
            }
        }
    }

// Function to inject a simulated user interaction
    function simulateUserInteraction() {
        const iframe = document.querySelector('.inSiteWebStream iframe');
        if (iframe) {
            try {

// Create and dispatch a click event on the iframe
                const rect = iframe.getBoundingClientRect();
                const clickEvent = new MouseEvent('click', {
                    bubbles: true,
                    cancelable: true,
                    clientX: rect.left + 5,
                    clientY: rect.top + 5,
                });
                iframe.dispatchEvent(clickEvent);
                console.log("Simulated click on iframe.");

// Send a mousemove event
                const mouseMoveEvent = new MouseEvent('mousemove', {
                    bubbles: true,
                    cancelable: true,
                    clientX: rect.left + 5,
                    clientY: rect.top + 5,
                });
                iframe.dispatchEvent(mouseMoveEvent);
                console.log("Simulated mouse move on iframe.");
            } catch (err) {
                console.error("Failed to simulate user interaction:", err);
            }
        } else {
            console.log("Iframe not found.");
        }
    }


// Manual F key functionality
    document.addEventListener('keydown', function (e) {
        if (e.key.toLowerCase() === 'f') {
            console.log("F key pressed. Triggering fullscreen...");
            handleFullscreen();
        }
    });

// Handle messages from the iframe for cross-origin interaction
    if (window.location.host.includes(VIDEO_PLAYER)) {
        window.addEventListener('message', function (event) {
            if (event.data.action === 'clickFullscreen') {
                const fullscreenButton = document.querySelector('button[data-plyr="fullscreen"]');
                if (fullscreenButton) {
                    fullscreenButton.click();
                    console.log("Fullscreen button clicked in iframe via message.");
                } else {
                    console.log("Fullscreen button not found in iframe.");
                }
            }
        });
    }



// Function to send play message
    function sendPlayMessage() {
        if (!skipToNextEpisodeEnabled) return;
        const iframe = document.querySelector(`iframe[src*="${VIDEO_PLAYER}"]`);
        if (iframe) {
            iframe.contentWindow.postMessage({ action: 'play' }, '*');
        }
    }

// Function to skip ahead
    function skipAhead() {
        const video = document.querySelector('video');
        if (video) {
            video.currentTime = Math.min(video.currentTime + SKIP_AHEAD_TIME, video.duration);
        } else {
            console.error("Video element not found for skipping ahead");
        }
    }

// Function to skip backward
    function skipBackward() {
        const video = document.querySelector('video');
        if (video) {
            video.currentTime = Math.max(video.currentTime - SKIP_BACKWARD_TIME, 0);
        } else {
            console.error("Video element not found for skipping backward");
        }
    }


// Event listener for keydown
    window.addEventListener('keydown', function (event) {
        if (!event.target.closest('input, textarea')) {
            switch (event.key) {
                case 'ArrowRight': // Right arrow key for skipping ahead
                    skipAhead();
                    break;
                case 'ArrowLeft': // Left arrow key for skipping backward
                    skipBackward();
                    break;
            }
        }
    });

// Behavior for Video Player
    if (window.location.hostname === VIDEO_PLAYER) {
        setInterval(checkAndPostMessage, 5000);

        window.addEventListener("message", function (event) {
            if (event.data.action === "play") {
                playVideo();
            }
        });

        window.addEventListener('load', function () {
            if (skipToNextEpisodeEnabled) {
                playVideo();
            }
        });

        window.addEventListener('keydown', function (event) {
            if ((event.key === 'V' || event.key === 'v') && !event.target.closest('input, textarea')) {
                skipForward();
            }
        });
    }

// Behavior for aniworld.to
    if (window.location.hostname === "aniworld.to") {
        window.addEventListener('message', function (event) {
            if (event.origin.includes(VIDEO_PLAYER) && event.data.action === 'skipToNextEpisode') {
                const nextEpisodeUrl = getNextEpisodeUrl();
                if (nextEpisodeUrl) {
                    window.location.href = nextEpisodeUrl;
                    if (skipToNextEpisodeEnabled) {
                        setTimeout(sendPlayMessage, 2000);
                    }
                } else {
                    console.error("Next episode URL could not be determined.");
                }
            }
        });

        window.addEventListener('load', function () {
            if (skipToNextEpisodeEnabled) {
                sendPlayMessage();
            }
        });
    }

// Autoplay button Style
    const style = document.createElement('style');
    style.textContent = `
    .Autoplay-button-container {
        width: 24px;
        height: 12px;
        background-color: rgba(221, 221, 221, 0.5);
        border-radius: 6px;
        position: absolute;
        top: 50%;
        transform: translateY(-50%);
        right: -4px;
        cursor: pointer;
        display: inline-block;
        z-index: 10;
    }

    .Autoplay-button {
        width: 12px;
        height: 12px;
        background-color: #bbb;
        border-radius: 50%;
        position: absolute;
        top: 0;
        left: 0;
        transition: all 0.2s ease;
    }

    .Autoplay-button[aria-checked="true"] {
        background-color: #ffffff;
        transform: translateX(12px);
    }

    .plyr__tooltip {
        position: absolute;
        bottom: 35px;
        left: 50%;
        transform: translateX(-50%);
        padding: 4px 8px;
        background: rgba(0, 0, 0, 0.75);
        color: #fff;
        border-radius: 4px;
        font-size: 12px;
        white-space: nowrap;
        opacity: 0;
        transition: opacity 0.2s ease;
        pointer-events: none;
    }

    .skip-toggle-button:hover .plyr__tooltip {
        opacity: 1;
    }
`;
    document.head.appendChild(style);


    window.addEventListener('load', function () {
        addSkipToggleButton();
    });
})();