Automatically clicks the Skip Intro button on Crunchyroll.com when available and makes the video fullscreen
当前为
// ==UserScript==
// @name Crunchyroll Auto Skip Intro/Outro, Fullscreen Video & Mouse Volume Control
// @namespace https://greasyfork.org/en/users/807108-jeremy-r
// @version 5
// @description Automatically clicks the Skip Intro button on Crunchyroll.com when available and makes the video fullscreen
// @author JRem
// @match https://*.crunchyroll.com/watch/*
// @match https://static.crunchyroll.com/vilos-v2/web/vilos/player.html
// @grant GM_addStyle
// @grant GM.xmlHttpRequest
// @license MIT
// ==/UserScript==
////////////////////////
// USER CUSTOMIZATION //
////////////////////////
// 1 = Enabled / 0 = Disabled
const enableFullscreen=1;
const enableSkipIntro=1;
const enableSkipCredits=1;
const enableVolumeControl=1;
// Volume +/- percentage
const volumePercentage = 5; // Default 5, Set the percentage of volume change (+/-)
// Global user settings for toast appearance and positioning
const toastSettings = {
toastPositionX: '45', // Default='45' (LeftCenter), Range '0' to '100' on the X axis
toastPositionY: '0', // Default='0' (Top), Range '0' to '100' on the Y axis
fontSize: '16px', // Font size for the toast message
fontFamily: 'Arial, sans-serif', // Font family for the toast message
backgroundColor: '#333', // Background color for the toast
textColor: 'white', // Text color for the toast
padding: '10px', // Padding around the toast text
margin: '5px', // Margin between toasts
borderRadius: '5px', // Border radius for rounded corners
toastDuration: 3500, // Duration to display the toast (in ms)
fadeDuration: 300, // Duration of the fade-in/out animation (in ms)
};
// Function to show or update toast message
function showToast(message) {
// Create a toast container if it doesn't already exist
let toastContainer = document.getElementById('toast-container');
if (!toastContainer) {
toastContainer = document.createElement('div');
toastContainer.id = 'toast-container';
document.body.appendChild(toastContainer);
// Add styles for the toast container
console.log (`transform: translateX(${toastSettings.toastPositionX}%);`)
console.log (`transform: translateY(${toastSettings.toastPositionY}%);`)
const style = document.createElement('style');
style.innerHTML = `
#toast-container {
position: fixed;
z-index: 9999;
${toastSettings.position}: 10px;
${toastSettings.align}: 50%;
transform: translateX(${toastSettings.toastPositionX}vw);
max-width: 90%;
pointer-events: none; /* Prevent interaction with toasts */
}
.toast {
background-color: ${toastSettings.backgroundColor};
color: ${toastSettings.textColor};
padding: ${toastSettings.padding};
margin: ${toastSettings.margin};
border-radius: ${toastSettings.borderRadius};
font-family: ${toastSettings.fontFamily};
font-size: ${toastSettings.fontSize};
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
opacity: 0;
transform: translateY(${toastSettings.toastPositionY}vh);
animation: fadeIn ${toastSettings.fadeDuration / 1000}s forwards, fadeOut 3s forwards ${toastSettings.toastDuration / 1000 - toastSettings.fadeDuration / 1000}s;
}
@keyframes fadeIn {
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fadeOut {
to {
opacity: 0;
transform: translateY(20px);
}
}
`;
document.head.appendChild(style);
}
// Check if there's an existing toast being displayed
let currentToast = toastContainer.querySelector('.toast');
if (currentToast) {
// If a toast is already visible, update its text content
currentToast.textContent = message;
// Reset the animation so that the toast updates instantly
currentToast.style.animation = 'none';
currentToast.offsetHeight; // Trigger reflow to restart animation
currentToast.style.animation = `fadeIn ${toastSettings.fadeDuration / 1000}s forwards, fadeOut 3s forwards ${toastSettings.toastDuration / 1000 - toastSettings.fadeDuration / 1000}s`;
} else {
// If no toast is visible, create a new toast
const toast = document.createElement('div');
toast.classList.add('toast');
toast.textContent = message;
toastContainer.appendChild(toast);
}
// Remove the toast after the duration is finished
setTimeout(() => {
if (currentToast) {
toastContainer.removeChild(currentToast);
}
}, toastSettings.toastDuration);
}
// Fullscreen CSS Edit
if (enableFullscreen == 1) {
var css = '.video-player-wrapper { max-height: calc(100vh - 5.625rem) !important; height: calc(100vh) !important; }';
css += '.erc-header { flex: 0 0 1.55rem !important; }';
css += '.erc-header .header-content { height: 0 !important; }';
GM_addStyle(css);
showToast('Fullscreen enabled'); };
// Volume Control via mouse scroll
// 1 Scroll = 5%
if (enableVolumeControl == 1) {
// Function to simulate the click event
function simulate(element, event) {
const evt = new MouseEvent(event, { bubbles: true, cancelable: true });
element.dispatchEvent(evt);
}
// Get the current video element
const video = document.querySelector('video');
// Function to adjust volume
function adjustVolume(video, percentage) {
if (!video) {
console.error("Video element not found.");
return;
}
// Get the current volume (between 0 and 1)
let currentVolume = video.volume;
// Calculate the new volume by adjusting it with the percentage
let volumeChange = currentVolume + (percentage / 100);
// Ensure the volume is within the valid range of 0 to 1
if (volumeChange > 1) {
volumeChange = 1;
} else if (volumeChange < 0) {
volumeChange = 0;
}
// Apply the new volume to the video
video.volume = volumeChange;
var newVol = (video.volume * 100).toFixed(2);
showToast(`Volume: ${newVol}%`);
}
// Listen for the mouse wheel event over the video
if (document.getElementById("vilos")) {
document.getElementById("vilos").addEventListener('wheel', (event) => {
// Check the direction of the scroll
if (event.deltaY < 0) {
// Scroll up (increase volume)
adjustVolume(video, volumePercentage);
} else if (event.deltaY > 0) {
// Scroll down (decrease volume)
adjustVolume(video, -volumePercentage);
}
// Prevent the default action to avoid scrolling the page
event.preventDefault();
});
}
};
// Check for and click Skip Intro
if (enableSkipIntro == 1 || enableSkipCredits == 1) {
setInterval(function () {
// Check for skip intro button
if (enableSkipIntro ==1 ) {
const skipIntroBtn = document.querySelector('div[data-testid="skipIntroText"]');
if (skipIntroBtn !== null && (skipIntroBtn.textContent.includes("SKIP INTRO"))) {
simulate(skipIntroBtn, "click");
console.log('Skip Btn Found');
showToast('Intro Skipped');
} };
// Check for skip credits button
if (enableSkipIntro ==1 ) {
const skipCreditsBtn = document.querySelector('div[data-testid="skipIntroText"]');
if (skipCreditsBtn !== null && (skipCreditsBtn.textContent.includes("SKIP CREDITS"))) {
simulate(skipCreditsBtn, "click");
console.log('Skip Btn Found');
showToast('Credits Skipped');
}}
}, 1000)
};