- // ==UserScript==
- // @name Pornhub Pro-ish
- // @namespace https://www.reddit.com/user/Alpacinator
- // @version 3.5.7
- // @include *://*.pornhub.com/*
- // @grant none
- // @description Alters and improves the PH experience, see addition info
- // ==/UserScript==
-
- (function() {
- 'use strict';
-
- // central logging function
- function log(message) {
- console.log(`Pornhub Pro-ish: ${message}`);
- }
-
- // still gotta find a better place for this
- let inputFilterWords;
-
- // these are the toggles that are dynamically created.
- // Only the changeEvent should be created manually.
- // the creation of the locally stored states is done automatically thanks to createToggle & getToggleState
- const toggles = [{
- label: 'Sort within playlists',
- key: 'sortWithinPlaylistsState',
- changeEvent: initializeSortWithinPlaylists,
- id: 'sortWithinPlaylistsToggle',
- defaultState: false
- }, {
- label: 'Sort videos by 🏆',
- key: 'sortByTrophyState',
- changeEvent: initializeSortByTrophy,
- id: 'sortByTrophyToggle',
- defaultState: false
- }, {
- label: 'Sort videos by duration',
- key: 'sortByDurationState',
- changeEvent: initializeSortByDuration,
- id: 'sortByDurationToggle',
- defaultState: false
- }, {
- label: 'Hide watched videos',
- key: 'hideWatchedState',
- changeEvent: hideVideos,
- id: 'hideWatchedToggle',
- defaultState: false
- }, {
- label: 'Hide paid content',
- key: 'hidePaidContentState',
- changeEvent: hideVideos,
- id: 'hidePaidContentToggle',
- defaultState: true
- }, {
- label: 'Always use English',
- key: 'redirectToEnglishState',
- changeEvent: redirectToEnglish,
- id: 'redirectToEnglishToggle',
- defaultState: true
- }, {
- label: 'Mute by default',
- key: 'muteState',
- changeEvent: initializeMuteVideos,
- id: 'muteToggle',
- defaultState: false
- }, {
- label: 'Hide cursor on video',
- key: 'cursorHideState',
- changeEvent: initializeCursorHide,
- id: 'cursorHideToggle',
- defaultState: true
- }];
-
- function createSideMenu() {
- log('Creating menu..');
- let menuShowState = getToggleState('menuShowState', true); // Get initial state from localStorage for the menu, default is true(show)
- const sideMenu = document.createElement('div');
- sideMenu.id = 'sideMenu'; // Assign an ID for easier reference
- sideMenu.style.position = 'fixed';
- sideMenu.style.top = '0';
- sideMenu.style.left = '0';
- sideMenu.style.padding = '60px 20px 20px 20px'; // Top padding 40px, rest 20px
- sideMenu.style.height = '100%'; // Full height for mobile view
- sideMenu.style.backgroundColor = 'rgba(0, 0, 0, 0.8)';
- sideMenu.style.zIndex = '9999';
- sideMenu.style.display = 'flex';
- sideMenu.style.flexDirection = 'column'; // Stack items vertically
- sideMenu.style.justifyContent = 'center';
- sideMenu.style.alignItems = 'left';
-
- // Add the toggles dynamically to the side menu
- // using const toggles and createToggle
- toggles.forEach(({
- label,
- key,
- changeEvent,
- id,
- defaultState
- }) => {
- const toggle = createToggle(label, key, changeEvent, id, defaultState);
- sideMenu.appendChild(toggle);
- });
-
-
- // create the two manual buttons
- var sortByTrophyManualButton = createButton(
- 'Put 🏆 first manually',
- 'black',
- sortByTrophyButton
- );
- sideMenu.appendChild(sortByTrophyManualButton);
-
- var sortBylengthManualButton = createButton(
- 'Sort by duration',
- 'black',
- sortByDurationButton
- );
- sideMenu.appendChild(sortBylengthManualButton);
-
- // this shows a little label above the filter input for the user
- var filterInfo = document.createElement('span');
- filterInfo.textContent = 'Words to filter out:';
- filterInfo.style.color = 'white';
- filterInfo.style.marginTop = '20px';
- filterInfo.style.paddingLeft = '20%';
- filterInfo.style.lineHeight = '20px'; // Match the height of the toggle for vertical alignment
- filterInfo.style.alignItems = 'center';
- filterInfo.style.justifyContent = 'center';
- filterInfo.style.fontSize = '14px'; // Adjust font size if needed
-
- sideMenu.appendChild(filterInfo);
-
- // create the text input for the filter
- inputFilterWords = createTextInput('inputFilterWords', 'Seperate with space or comma', updateFilterWords);
- var savedFilterWords = localStorage.getItem('savedFilterWords');
- if (savedFilterWords) {
- inputFilterWords.value = savedFilterWords; // Set the value of the input field
- }
-
- sideMenu.appendChild(inputFilterWords);
-
- // Insert the menu into the body
- document.body.insertBefore(sideMenu, document.body.firstChild);
-
- // Add the expand menu toggle
- createMenuToggle();
-
- // load the visibility state of the side menu and apply the according styling
- syncSideMenu();
- }
-
- // this block is responsible for hiding and showing the side menu
- // creating the toggle, and syncing the state with the saved show/hide menu state
- function createMenuToggle() {
- const symbol = document.createElement('div');
- const menuShowState = getToggleState('menuShowState');
- symbol.id = 'menuToggle';
- symbol.textContent = menuShowState ? 'Hide Menu' : 'Show Menu';
- symbol.style.position = 'fixed';
- symbol.style.left = '5px'; // Position on the right
- symbol.style.top = '5px';
- symbol.style.fontSize = '12pt';
-
- symbol.style.color = 'orange';
- symbol.style.cursor = 'pointer';
-
- symbol.style.zIndex = '10000';
- symbol.style.transition = 'all 0.3s';
-
- symbol.style.padding = '5px 10px';
- symbol.style.backgroundColor = 'black';
- symbol.style.border = '1px solid orange';
- symbol.style.borderRadius = '15px';
-
- symbol.addEventListener('click', toggleMenuShow);
- document.body.appendChild(symbol);
- }
-
- function showMenu() {
- const sideMenu = document.getElementById('sideMenu');
- if (sideMenu) {
- // Show menu
- sideMenu.style.visibility = 'visible';
- sideMenu.style.transition = 'opacity 0.5s ease, transform 0.5s ease, visibility 0s ease';
- sideMenu.style.opacity = '1';
- sideMenu.style.transform = 'translateX(0)';
-
- const menuToggle = document.getElementById('menuToggle');
- menuToggle.textContent = 'Hide Menu';
- }
- }
-
- function hideMenu() {
- const sideMenu = document.getElementById('sideMenu');
- if (sideMenu) {
- // Hide menu
- sideMenu.style.visibility = 'hidden';
- sideMenu.style.transition = 'opacity 0.5s ease, transform 0.5s ease, visibility 0s ease 0.5s';
- sideMenu.style.opacity = '0';
- sideMenu.style.transform = 'translateX(-100%)';
-
- const menuToggle = document.getElementById('menuToggle');
- menuToggle.textContent = 'Show Menu';
- }
- }
-
- function toggleMenuShow() {
- const sideMenu = document.getElementById('sideMenu');
- let menuShowState = getToggleState('menuShowState');
- if (sideMenu) {
- if (!menuShowState) {
- showMenu();
- } else {
- hideMenu();
- }
-
- menuShowState = !menuShowState;
- localStorage.setItem('menuShowState', menuShowState);
-
- }
- }
-
- function syncSideMenu() {
- let menuShowState = getToggleState('menuShowState');
- if (menuShowState) {
- showMenu();
- } else {
- hideMenu();
- }
- }
- // end block for showing/hiding menu
-
- // Update the toggle creation to include default states
- function createToggle(labelText, localStorageKey, changeEvent, id, defaultState = false) {
- var container = document.createElement('div');
- container.style.display = 'flex';
- container.style.alignItems = 'center';
- container.style.marginBottom = '15px'; // Add space between toggle and next element if needed
-
- var toggle = document.createElement('div');
- toggle.style.position = 'relative';
- toggle.style.width = '40px';
- toggle.style.height = '20px';
- toggle.style.backgroundColor = getToggleState(localStorageKey, defaultState) ? 'orange' : 'grey';
- toggle.style.borderRadius = '20px';
- toggle.style.cursor = 'pointer';
- toggle.style.transition = 'background-color 0.2s';
- toggle.id = id;
-
- var slider = document.createElement('div');
- slider.style.position = 'absolute';
- slider.style.left = getToggleState(localStorageKey, defaultState) ? '22px' : '2px';
- slider.style.width = '16px';
- slider.style.height = '16px';
- slider.style.backgroundColor = 'white';
- slider.style.borderRadius = '50%';
- slider.style.transition = 'left 0.2s';
- slider.style.top = '2px'; // Vertically center the slider within the toggle
-
- toggle.appendChild(slider);
-
-
- // this is used to save the state of the toggle to localStorage automatically
- toggle.addEventListener('click', function() {
- var currentState = getToggleState(localStorageKey, defaultState);
- localStorage.setItem(localStorageKey, !currentState);
- toggle.style.backgroundColor = !currentState ? 'orange' : 'grey';
- slider.style.left = !currentState ? '22px' : '2px';
- changeEvent();
- });
-
- var span = document.createElement('span');
- span.textContent = labelText;
- span.style.color = 'white';
- span.style.marginLeft = '15px'; // Space between toggle and text
- span.style.lineHeight = '20px'; // Match the height of the toggle for vertical alignment
- span.style.fontSize = '14px'; // Adjust font size if needed
- span.style.paddingTop = '3px'; // Adjust font size if needed
-
- container.appendChild(toggle);
- container.appendChild(span);
-
- return container;
- }
-
- // this checks the current state of the toggles using the ID and what they should be according to the saved values in LocalStorage
- function updateToggleStates() {
- toggles.forEach(({
- id,
- key
- }) => {
- const toggleElement = document.getElementById(id);
- const currentState = getToggleState(key);
-
- if (toggleElement) {
- const expectedColor = currentState ? 'orange' : 'grey';
- const slider = toggleElement.querySelector('div');
-
- toggleElement.style.backgroundColor = expectedColor;
- if (slider) {
- slider.style.left = currentState ? '22px' : '2px';
- }
- }
- });
- }
-
- function createButton(text, bgColor, clickEvent) {
- var button = document.createElement('button');
- button.textContent = text;
- button.style.marginRight = '0px';
- button.style.marginBottom = '15px';
- button.style.padding = '5px 10px';
- button.style.backgroundColor = bgColor;
- button.style.color = 'white';
- button.style.border = '1px solid white';
- button.style.borderRadius = '10px';
- button.style.cursor = 'pointer';
- button.style.transition = 'background-color 0.3s, color 0.3s, border-color 0.3s';
-
- // JavaScript hover effects
- button.addEventListener('mouseover', function() {
- button.style.color = 'orange';
- button.style.borderColor = 'orange';
- });
- button.addEventListener('mouseout', function() {
- button.style.color = 'white';
- button.style.borderColor = 'white';
- });
-
- button.addEventListener('click', function() {
- button.style.backgroundColor = 'orange';
- setTimeout(function() {
- button.style.backgroundColor = bgColor;
- }, 100);
-
- clickEvent();
- });
-
- return button;
- }
- // dynamically create text inputs function for the menu
- function createTextInput(id, placeholder, inputEvent) {
- var input = document.createElement('input');
- input.type = 'text';
- input.id = id;
- input.placeholder = placeholder;
- input.style.marginRight = '0px';
- input.style.marginBottom = '15px';
- input.style.border = '1px solid grey';
- input.style.borderRadius = '15px';
- input.style.padding = '5px 10px';
- input.addEventListener('input', inputEvent);
- return input;
- }
-
- // this is used to fetch the state of a setting in LocalStorage
- function getToggleState(localStorageKey, defaultState = false) {
- const savedState = localStorage.getItem(localStorageKey);
- if (savedState === null) { // No saved state exists
- localStorage.setItem(localStorageKey, defaultState); // Set the default state in localStorage
- return defaultState;
- }
- return savedState === 'true';
- }
-
- // manage the filter words to hide certain videos if the title includes certain words
- function updateFilterWords() {
- var inputFilterWordsValue = inputFilterWords.value;
- localStorage.setItem('savedFilterWords', inputFilterWordsValue);
- hideVideos();
- }
-
- // Check whatever the state of the toggles is and execute the functions accordingly
- function initializeMuteVideos() {
- var muteVideosEnabled = getToggleState('muteState');
- if (muteVideosEnabled) {
- clickMuteButton();
- }
- }
-
- function initializeSortByTrophy() {
- var reorderItemsEnabled = getToggleState('sortByTrophyState');
- if (reorderItemsEnabled) {
- sortByTrophy();
- }
- }
-
- function initializeSortByDuration() {
- var sortByDurationEnabled = getToggleState('sortByDurationState');
- if (sortByDurationEnabled) {
- sortByDuration();
- }
-
- }
-
- // this one will only be run when the toggle is flipped because it consists of two other initializes that are already called upon mutation/page load
- function initializeSortWithinPlaylists() {
- initializeSortByTrophy();
- initializeSortByDuration();
- }
-
- function initializeCursorHide() {
- var cursorHideStateEnabled = getToggleState('cursorHideState');
- if (cursorHideStateEnabled) {
- cursorHide(true);
- } else {
- cursorHide(false);
- }
- }
-
- function hideVideos() {
- var hideWatchedEnabled = getToggleState('hideWatchedState');
- var hidePaidContentEnabled = getToggleState('hidePaidContentState');
-
- // Use findVideoULs to get the <ul> elements
- const ulElements = findVideoULs(true);
-
- // Get all <li> elements within the found <ul> elements
- const liElements = ulElements.flatMap(ul => Array.from(ul.querySelectorAll('li')));
-
- const savedFilterWords = localStorage.getItem('savedFilterWords') || ''; // Handle null case
- const filterWords = savedFilterWords ? savedFilterWords.split(/,\s*|\s+/).map(word => word.trim().toLowerCase()) : [];
- const hidePaidContentState = getToggleState('hidePaidContentState');
- const hideWatchedState = getToggleState('hideWatchedState');
-
- liElements.forEach(function(li) {
- const liTextContent = li.textContent.toLowerCase();
-
- // Check if the current <li> has a watched indicator, excluding those with the 'hidden' class
- const watchedDiv = li.querySelector('.watchedVideoText, .watchedVideo');
- const isWatched = watchedDiv && !(watchedDiv.classList.contains('watchedVideoText') && watchedDiv.classList.contains('hidden'));
-
- // Selectors for paid/premium/private content
- const priceSpan = li.querySelector('span.price');
- const premiumIcon = li.querySelector('.premiumicon'); // Corrected selector
- const aHrefJavaVoid = li.querySelector('a');
- const privateOverlay = li.querySelector('img.privateOverlay');
-
- // Determine if the video should be hidden
- const shouldHideByFilterWords = filterWords.length > 0 && filterWords.some(word => word.length >= 3 && liTextContent.includes(word));
- const shouldHideWatchedVideos = hideWatchedState && isWatched; // Corrected condition to check isWatched
- const shouldHidePaidContent = hidePaidContentState && (priceSpan || premiumIcon || privateOverlay || (aHrefJavaVoid && aHrefJavaVoid.getAttribute('href') === 'javascript:void(0)'));
-
- // Hide or show the <li> element based on conditions
- li.style.display = (shouldHideByFilterWords || shouldHideWatchedVideos || shouldHidePaidContent) ? 'none' : 'block';
- });
- }
-
-
-
-
- // Utility function to find all <ul> elements with class 'videos',
- // excluding those with specified IDs
- // used for sortByDuration and sortByTrophy
- function findVideoULs(sortWithinPlaylistsEnabled = true) {
- // Define IDs for <ul> elements that should be excluded when sorting within playlists is disabled
- const playlistIdsToExclude = ['videoPlaylist', 'videoPlaylistSection', 'playListSection'];
-
- // Get all <ul> elements with class 'videos' or 'videoList'
- const allVideoULs = document.querySelectorAll('ul.videos, ul.videoList');
-
- // Convert NodeList to an Array
- const videoULArray = Array.from(allVideoULs);
-
- // Filter <ul> elements: Exclude playlists if sorting within playlists is disabled
- const filteredULs = videoULArray.filter(ul => {
- // Exclude IDs only when sortWithinPlaylistsEnabled is false
- const shouldExclude = !sortWithinPlaylistsEnabled && playlistIdsToExclude.includes(ul.id);
- // Include the <ul> if it should not be excluded
- return !shouldExclude;
- });
-
- return filteredULs;
- }
-
-
- function sortByDuration() {
- function parseDuration(durationString) {
- const [minutes, seconds] = durationString.split(':').map(Number);
- return minutes * 60 + seconds;
- }
-
- function sortLiElementsByDurationDesc(ulElement) {
- const liElements = Array.from(ulElement.querySelectorAll('li'))
- .filter(li => li.querySelector('.duration'));
-
- if (liElements.length === 0) {
- console.warn(`No elements with duration found in the list container.`);
- return;
- }
-
- liElements.sort((a, b) => {
- const durationA = parseDuration(a.querySelector('.duration').textContent);
- const durationB = parseDuration(b.querySelector('.duration').textContent);
- return durationB - durationA;
- });
-
- liElements.forEach(li => {
- ulElement.appendChild(li);
- });
- }
-
- // Use forced disable toggle or check the actual toggle state
- const sortWithinPlaylistsEnabled = getToggleState('sortWithinPlaylistsState');
- const ulsToSort = findVideoULs(sortWithinPlaylistsEnabled);
-
- if (ulsToSort.length === 0) {
- console.warn('No <ul> elements with class "videos" found.');
- return;
- }
-
- ulsToSort.forEach(ulElement => {
- sortLiElementsByDurationDesc(ulElement);
- });
- }
-
- function sortByTrophy() {
- function sortLiElementsByTrophy(ulElement) {
- const liElements = Array.from(ulElement.querySelectorAll('li'));
- const freePremiumVideoItems = [];
- const otherItems = [];
-
- liElements.forEach(li => {
- const childSpan = li.querySelector('span.award-icon');
- if (childSpan) {
- freePremiumVideoItems.push(li);
- } else {
- otherItems.push(li);
- }
- });
-
- const reorderedLiElements = freePremiumVideoItems.concat(otherItems);
- reorderedLiElements.forEach(li => {
- ulElement.appendChild(li);
- });
- }
-
- // Use forced disable toggle or check the actual toggle state
- const sortWithinPlaylistsEnabled = getToggleState('sortWithinPlaylistsState');
- const ulsToSort = findVideoULs(sortWithinPlaylistsEnabled);
-
- if (ulsToSort.length === 0) {
- console.warn('No <ul> elements with class "videos" found.');
- return;
- }
-
- ulsToSort.forEach(ulElement => {
- sortLiElementsByTrophy(ulElement);
- });
- }
-
- function sortByDurationButton() {
- function parseDuration(durationString) {
- const [minutes, seconds] = durationString.split(':').map(Number);
- return minutes * 60 + seconds;
- }
-
- function sortLiElementsByDurationDesc(ulElement) {
- const liElements = Array.from(ulElement.querySelectorAll('li'))
- .filter(li => li.querySelector('.duration'));
-
- if (liElements.length === 0) {
- console.warn(`No elements with duration found in the list container.`);
- return;
- }
-
- liElements.sort((a, b) => {
- const durationA = parseDuration(a.querySelector('.duration').textContent);
- const durationB = parseDuration(b.querySelector('.duration').textContent);
- return durationB - durationA;
- });
-
- liElements.forEach(li => {
- ulElement.appendChild(li);
- });
- }
-
- const ulsToSort = findVideoULs(true);
-
- if (ulsToSort.length === 0) {
- console.warn('No <ul> elements with class "videos" found.');
- return;
- }
-
- ulsToSort.forEach(ulElement => {
- sortLiElementsByDurationDesc(ulElement);
- });
- }
-
- function sortByTrophyButton() {
- function sortLiElementsByTrophy(ulElement) {
- const liElements = Array.from(ulElement.querySelectorAll('li'));
- const freePremiumVideoItems = [];
- const otherItems = [];
-
- liElements.forEach(li => {
- const childSpan = li.querySelector('span.award-icon');
- if (childSpan) {
- freePremiumVideoItems.push(li);
- } else {
- otherItems.push(li);
- }
- });
-
- const reorderedLiElements = freePremiumVideoItems.concat(otherItems);
- reorderedLiElements.forEach(li => {
- ulElement.appendChild(li);
- });
- }
-
- // Use forced disable toggle or check the actual toggle state
- const ulsToSort = findVideoULs(true);
-
- if (ulsToSort.length === 0) {
- console.warn('No <ul> elements with class "videos" found.');
- return;
- }
-
- ulsToSort.forEach(ulElement => {
- sortLiElementsByTrophy(ulElement);
- });
- }
-
-
-
- // this simulates a click on the mute button in the videoplayer
- function clickMuteButton() {
- function simulateMouse(element, eventType) {
- const event = new Event(eventType, {
- view: window,
- bubbles: true,
- cancelable: true
- });
- element.dispatchEvent(event);
- }
- const muteDivs = document.querySelectorAll('div.mgp_volume > div[data-text="Mute"]');
-
- if (muteDivs.length === 0) return;
-
- muteDivs.forEach((div, index) => {
- simulateMouse(div, 'mouseover');
- simulateMouse(div, 'focus');
- simulateMouse(div, 'mousedown');
- simulateMouse(div, 'mouseup');
- simulateMouse(div, 'click');
-
- if (div) {
- const event = new MouseEvent('mouseover', {
- view: window,
- bubbles: true
- });
- div.dispatchEvent(event);
- }
- });
-
- log(`${muteDivs.length} video elements were muted.`);
- }
-
- // Hide the load more buttons, all the items should already show
- function hideElements() {
- log('Hiding elements..');
-
- // Hide the welcoming messages regarding different countries and the store
- if (document.getElementById('countryRedirectMessage')) {
- document.getElementById('countryRedirectMessage').style.display = 'none';
- }
-
- if (document.getElementById('welcome')) {
- document.getElementById('welcome').style.display = 'none';
- }
-
- // This will hide the ugly long empty blocks under videos while going through pages
- // Select all divs with the class 'pornInLangWrapper'
- const divs = document.querySelectorAll('div.pornInLangWrapper');
-
- // Loop through each div and hide it
- divs.forEach(div => {
- div.style.display = 'none';
- });
-
-
- // remove load more buttons
- // under the video
- if (document.getElementById('loadMoreRelatedVideosCenter')) {
- document.getElementById('loadMoreRelatedVideosCenter').style.display = 'none';
- }
- // on the right side of the video
- const recommendedLoadMoreElements = document.querySelectorAll('[data-label="recommended_load_more"]');
- recommendedLoadMoreElements.forEach(element => {
- element.style.display = 'none';
- });
-
- }
-
- // Usage
- // cursorHide(true); // To enable hiding the cursor
- // cursorHide(false); // To disable hiding the cursor
- // this makes use of the class that is added to the videowrapper when a video is playing, it is removed when paused
- function cursorHide(enable) {
- // Check if the style element already exists
- let existingStyle = document.getElementById('cursor-hide-style');
-
- if (enable) {
- if (!existingStyle) {
- log("cursorHide is enabled but the style doesn't exist yet, creating cursorHide style..");
- // Create and append the style element if it doesn't exist
- const style = document.createElement('style');
- style.id = 'cursor-hide-style';
- style.textContent = `
- /* Define the cursor hiding animation */
- @keyframes hideCursor {
- 0% {
- cursor: default;
- }
- 99% {
- cursor: default;
- }
- 100% {
- cursor: none;
- }
- }
-
- /* Apply the animation on hover */
- .mgp_playingState {
- animation: none;
- }
-
- .mgp_playingState:hover {
- animation: hideCursor 3s forwards;
- }
- `;
-
- document.head.appendChild(style);
- log('cursorHide style added.');
- }
- } else {
- if (existingStyle) {
- log("cursorHide is disabled but the style still exists, removing cursorHide style..");
- // Remove the style element if it exists
- existingStyle.remove();
- log('cursorHide style removed.');
- }
- }
- }
-
- // Change the language of the website to English if that is not the case
- // Since this script sometimes uses words to function this is still neccesary
- function redirectToEnglish() {
- var redirectToEnglishStateEnabled = getToggleState('redirectToEnglishState');
- if (redirectToEnglishStateEnabled) {
-
- const isNotEnglish = () => {
- const languageDropdownLI = document.querySelector('li.languageDropdown');
- return !languageDropdownLI || (languageDropdownLI.querySelector('span.networkTab') && languageDropdownLI.querySelector('span.networkTab').textContent.trim().toLowerCase() !== 'en');
- };
-
- const findEnLink = () => {
- const enLanguageOptionLI = document.querySelector('li[data-lang="en"]');
- if (!enLanguageOptionLI) return null;
-
- const enLanguageLink = enLanguageOptionLI.querySelector('a.networkTab');
- return !enLanguageLink ? console.error('Anchor element with class "networkTab" not found within the specified <li> to check the current language.') : enLanguageLink;
- };
-
- function checkAndClick() {
- if (isNotEnglish()) {
- const enLink = findEnLink();
-
- // If we've already tried clicking and it didn't work, stop trying
- if (!enLink) return log('No English link to click. Giving up.');
-
- enLink.click();
- log('Clicked the link:', enLink);
- } else {
- log('Current language is already English. No action needed.');
- }
- }
-
- setTimeout(checkAndClick, 1000); // Adjust delay if necessary
- }
- }
-
-
- // this adds a transparant red square over items if you press delete
- // to show you which you have deleted when editing a playlist
- function addRedOverlay(element) {
- var overlay = document.createElement('div');
- overlay.style.position = 'absolute';
- overlay.style.top = '0';
- overlay.style.left = '0';
- overlay.style.width = '100%';
- overlay.style.height = '100%';
- overlay.style.backgroundColor = 'red';
- overlay.style.opacity = '0.5';
- overlay.style.pointerEvents = 'none';
-
- var parentLi = element.closest('li');
- if (parentLi) {
- parentLi.style.position = 'relative';
- parentLi.appendChild(overlay);
- }
- }
-
- // when editing playlists, whenever the delete button on a video is clicked, this will create a transparent red square around the video
- document.addEventListener('click', function(event) {
- if (event.target && event.target.matches('button[onclick="deleteFromPlaylist(this);"]')) {
- addRedOverlay(event.target);
- log('Added red overlay to the playlist item');
- }
- });
-
- // run updateToggleStates when changing to a tab (using visibilityState to see if it is active/visible) so the state will be synced:
- document.addEventListener('visibilitychange', function() {
- if (document.visibilityState === 'visible') {
- log('Tab is visible, updating toggle states..');
- // update toggle states
- updateToggleStates();
- // this should trigger a DOM change, so runOnMutation should run and things should update
-
- // make sure the menu visibility matches the state
- syncSideMenu();
-
- // change language to English
- redirectToEnglish();
-
- // check if the cursor should be hidden
- initializeCursorHide();
- }
- });
-
- // this will be run when the observer spots mutations
- function initializeEverything() {
- initializeSortByTrophy();
- initializeSortByDuration();
- initializeMuteVideos();
- hideVideos();
- }
-
- // run this when the page is fully loaded
- window.onload = function() {
- // hide 'Load More' buttons and the like
- hideElements();
-
- // create the menu
- createSideMenu();
-
- // change lang to english
- redirectToEnglish();
-
- // check if the cursor should be hidden
- initializeCursorHide();
-
- // no need to initialize everything manually, that will trigger on page load (runOnMutation will take care of the rest)
- // but this makes the page ready to go as soon as it is done loading, so we will keep it for now
- initializeEverything();
-
- // keep checking for mutations using an observer
- function runOnMutation() {
- clearTimeout(runOnMutation.timeout);
- runOnMutation.timeout = setTimeout(() => {
- initializeEverything();
- }, 500);
- }
-
- const observer = new MutationObserver(function(mutations) {
- runOnMutation();
- });
-
- observer.observe(document.body, {
- childList: true,
- subtree: true
- });
-
- };
-
- })();