// 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();
});
})();