- // ==UserScript==
- // @name XVideos+
- // @namespace -
- // @version 2.3.3
- // @description ad block, download ability without signing in, remember player settings and fast search
- // @author NotYou
- // @match *://xvideos.com/*
- // @match *://xvideos2.com/*
- // @match *://xvideos3.com/*
- // @match *://xvideos4.com/*
- // @match *://xvideos5.com/*
- // @match *://xvideos53.com/*
- // @match *://www.xvideos.com/*
- // @match *://www.xvideos2.com/*
- // @match *://www.xvideos3.com/*
- // @match *://www.xvideos4.com/*
- // @match *://www.xvideos5.com/*
- // @match *://www.xvideos53.com/*
- // @run-at document-end
- // @license GPL-3.0-or-later
- // @grant none
- // ==/UserScript==
-
- (function() {
- const TITLE = 'XVideos+'
- const LOCAL_VIDEO_SETTINGS = 'video_settings_xp'
-
- const DEFAULT_SETTINGS = JSON.stringify({
- volume: 1,
- muted: false,
- quality: 'Auto',
- speed: 1,
- loop: false
- })
-
- class CSS {
- static init() {
- const _CSS = `
- #site-logo-link {
- text-decoration: none;
- }
-
- #plus-xp {
- float: right;
- position: relative;
- margin-top: -10px;
- left: -6px;
- font-size: 36px;
- color: rgb(255, 255, 255);
- user-select: none;
- height: 0;
- }
-
- .no-text-dec, .no-text-dec:hover {
- text-decoration: none !important;
- }
-
- #fs-xp {
- background-color: rgba(213, 213, 213, .7);
- position: fixed;
- z-index: 2147483647;
- top: 50px;
- left: calc(60% / 2); /* 100% - 40% = 60% */
- width: 40%;
- border-radius: 5px;
- }
-
- #fs-input-parent-xp {
- display: flex;
- padding: .5rem;
- }
-
- #fs-input-parent-xp i {
- margin-top: 5px;
- margin-right: 5px;
- color: rgb(222, 38, 0);
- }
-
- #fs-input-parent-xp i::before {
- font-size: 20px;
- }
-
- #fs-input-xp {
- width: 100%;
- border-radius: 4px;
- height: 40px;
- }
-
- .tab-xp {
- background-color: rgb(247, 247, 247);
- margin: 0 0 10px 0;
- padding: 15px 10px;
- }
-
- #tabDownloadXp {
- text-align: center;
- font-size: 15px;
- }
-
- /* DARK-THEME */
-
- .dark-theme-xp #fs-xp {
- background-color: rgba(0, 0, 0, .7);
- }
-
- .dark-theme-xp .tab-xp {
- background-color: rgb(46, 46, 46);
- }`
-
- addStyle(_CSS)
- }
- }
-
- class DarkThemeChecker {
- static init() {
- let isDarkTheme
-
- setupDarkThemeClass()
-
- const DARK_THEME_OBS = new MutationObserver(setupDarkThemeClass)
-
- DARK_THEME_OBS.observe(document.body, {
- childList: true,
- subtree: true,
- })
-
- function setupDarkThemeClass() {
- setTheme()
- setDarkThemeClass()
- }
-
- function setTheme() {
- isDarkTheme = getTheme() === 'black'
- }
-
- function getTheme() {
- const USER_FAVORITE_THEME = localStorage.user_theme_fav
- const THEME = JSON.parse(USER_FAVORITE_THEME).i
-
- return THEME
- }
-
- function setDarkThemeClass() {
- document.documentElement.classList[isDarkTheme ? 'add' : 'remove']('dark-theme-xp')
- }
- }
- }
-
- class AntiAntiAdBlock {
- static init() {
- Object.defineProperty(window, 'fuckAdBlock', {
- get() {
- return fakeFuckAdBlockObj()
- }
- })
-
- function fakeFuckAdBlockObj() {
- return {
- _creatBait: blank('undef'),
- _destroyBait: blank('undef'),
- _checkBait: blank('undef'),
- _log: blank('undef'),
- _stopLoop: blank('undef'),
-
- onDetected: blank(),
- onNotDetected: blank(),
- on: blank(),
- setOptions: blank(),
- setOption: blank(),
- check: blank('false'),
- emitEvent: blank(),
- clearEvent: blank('undef'),
- }
- }
-
- function blank(type) {
- let returnValue
-
- switch (type) {
- case 'undef': break
- case 'false': returnValue = false; break
- default: returnValue = this; break
- }
-
- return function() {
- return returnValue
- }
- }
- }
- }
-
- class AdBlock {
- static init() {
- let css = ''
- const SELECTORS = [
- '#video-ad',
- '#video-ad + div[class]',
- '#ad-footer',
- '#ad-footer + .remove-ads',
- '#ad-footer2',
- '#video-sponsor-links',
- '.videoad-title',
- '.ad-footermobile',
- '.ad-support-tablet',
- '#ad-header-mobile-contener',
- '#v-actions .tabs .dl',
- '#content > :first-child > .clearfix',
- '.thumb-block-profile > .thumb-inside > .prof-thumb-title',
- '.thumb-ad'
- ]
-
- for (let i = 0; i < SELECTORS.length; i++) {
- const SELECTOR = SELECTORS[i]
-
- css += SELECTOR + '{ display: none !important; }'
- }
-
- addStyle(css)
- }
- }
-
- class PlusSymbol {
- static init() {
- let plus = document.createElement('span')
- plus.id = 'plus-xp'
- plus.className = 'noselect'
- plus.textContent = '+'
-
- let svgLogo = document.querySelector('#site-logo')
-
- if(svgLogo) {
- svgLogo.insertAdjacentElement('afterend', plus)
- }
- }
- }
-
- class FastSearch {
- static init() {
- let fastSearch = document.createElement('div')
- let fastSearchInputParent = document.createElement('div')
- let fastSearchIcon = document.createElement('i')
- let fastSearchInput = document.createElement('input')
-
- fastSearch.id = 'fs-xp'
- fastSearchInput.id = 'fp-input-xp'
- fastSearchInputParent.id = 'fs-input-parent-xp'
-
- fastSearchInput.placeholder = 'Fast Search XVideos'
- fastSearchInput.className = 'form-control'
-
- fastSearchIcon.className = 'icon-f icf-search'
-
- fastSearchIcon.addEventListener('click', fastSearchEventHandler)
- fastSearchInput.addEventListener('keydown', fastSearchEventHandler)
-
- fastSearchInputParent.appendChild(fastSearchIcon)
- fastSearchInputParent.appendChild(fastSearchInput)
- fastSearch.appendChild(fastSearchInputParent)
-
- toggleVisibility(fastSearch)
-
- document.body.appendChild(fastSearch)
-
- window.addEventListener('keydown', e => {
- if(e.code === 'KeyK' && (e.ctrlKey || e.metaKey)) {
- e.preventDefault()
- toggleVisibility(fastSearch)
- fastSearchInput.focus()
- }
- })
-
- function fastSearchEventHandler(e) {
- if(e.type === 'click' || e.code === 'Enter') {
- search(fastSearchInput.value)
- }
- }
- }
- }
-
- class CopyableTitle {
- static init() {
- const VIDEO_TITLE_NODE = document.querySelector('#title-auto-tr') || document.querySelector('.page-title')
-
- VIDEO_TITLE_NODE.addEventListener('click', () => {
- let videoTitleText = VIDEO_TITLE_NODE.firstChild.textContent.trim()
-
- if(!videoTitleText) {
- videoTitleText = window.html5player.video_title
- }
-
- navigator.clipboard.writeText(videoTitleText)
- })
- }
- }
-
- class FastButtons {
- static init() {
- const VIDEO_TITLE = window.html5player.video_title
-
- let actionsTabs = document.querySelector('#v-actions .tabs')
- let videoTabs = document.querySelector('#video-tabs > .tabs')
- let dlBtnOrigin = actionsTabs.querySelector('.dl')
-
- let embedBtn = document.createElement('button')
- let embedLink = document.createElement('a')
-
- let dlBtn = document.createElement('button')
- let dlTab = document.createElement('div')
- let dlOptions = createDownloadOptions()
-
- embedLink.className = 'no-text-dec'
- embedLink.target = '_blank'
- embedLink.href = '/embedframe/' + window.html5player.id_video
- embedLink.innerHTML = '<span class="icon-f icf-embed"></span><span>Embed</span>'
-
- dlBtn.className = 'dl-xp'
- dlBtn.innerHTML = '<span class="icon-f icf-download"></span><span>Download (XVideos+)</span>'
- dlBtn.addEventListener('click', onDlClick)
-
- toggleVisibility(dlTab)
- dlTab.className = 'tab-xp'
- dlTab.id = 'tabDownloadXp'
- dlTab.innerHTML = 'Download ' + dlOptions
- .createOption('HIGH', window.html5player.url_high, 'High quality')
- .createOption('LOW', window.html5player.url_low, 'Low quality')
- .create()
- + ' quality video.'
-
- embedBtn.appendChild(embedLink)
- actionsTabs.appendChild(embedBtn)
-
- dlBtnOrigin.insertAdjacentElement('beforebegin', dlBtn)
- videoTabs.appendChild(dlTab)
-
- function onDlClick() {
- return toggleVisibility(dlTab)
- }
-
- function createDownloadOptions() {
- let options = ''
-
- return {
- createOption(label, url, desc) {
- options += `<strong><a href="${url}" title="${desc}" target="_blank">${label}</a></strong> / `
-
- return this
- },
-
- create() {
- return options.slice(0, -3)
- }
- }
- }
- }
- }
-
- class SaveVideoSettings {
- static init() {
- let video = window.html5player.video || document.querySelector('#html5video video')
-
- class Settings {
- static getSettings() {
- return JSON.parse(localStorage.getItem(LOCAL_VIDEO_SETTINGS))
- }
-
- static getItem(key) {
- let settings = this.getSettings()
-
- return settings[key]
- }
-
- static setItem(key, value) {
- let settings = this.getSettings()
-
- settings[key] = value
-
- localStorage.setItem(LOCAL_VIDEO_SETTINGS, JSON.stringify(settings))
- }
- }
-
- class Player {
- static get volume() {
- return video.volume
- }
-
- static set volume(volume) {
- window.html5player.setVolume(volume)
- }
-
- static get isMuted() {
- return video.muted
- }
-
- static mute() {
- return window.html5player.mute()
- }
-
- static get quality() {
- return window.html5player.qualitiesmenubuttonlabel
- }
-
- static set quality(quality) {
- let qualityMenu = window.html5player.qualitymenu
-
- if(qualityMenu) {
- setQuality()
- } else {
- let obs = new MutationObserver(() => {
- if(window.html5player.qualitymenu) {
- qualityMenu = window.html5player.qualitymenu
-
- if(qualityMenu) {
- setQuality()
- obs.disconnect()
- }
- }
- })
-
- obs.observe(document.body, {
- childList: true,
- subtree: true,
- })
- }
-
- function setQuality() {
- let qualityEls = qualityMenu.querySelectorAll('span')
-
- for (let i = 0; i < qualityEls.length; i++) {
- let qualityEl = qualityEls[i]
-
- if(qualityEl.textContent.trim().toLowerCase() === quality.toLowerCase()) {
- return qualityEl.parentNode.click()
- }
- }
-
- log('Cannot find quality "' + quality + '"')
- }
- }
-
- static get speed() {
- return window.html5player.speed
- }
-
- static set speed(speed) {
- window.html5player.speed = speed
- }
-
- static get isLooped() {
- return window.html5player.loopbtn.querySelector('img[src*="1.svg"]') !== null
- }
-
- static loop() {
- let isLooped = this.isLooped
-
- if(!isLooped) {
- window.html5player.loopbtn.click()
- }
- }
- }
-
- restoreVideoSettings()
-
- const TARGET_NODE = document.querySelector('#hlsplayer') || document.body
-
- let obs = new MutationObserver((mutationList) => {
- for (let i = 0; i < mutationList.length; i++) {
- const MUTATION_RECORD = mutationList[i]
- const TARGET = MUTATION_RECORD.target
-
- if(TARGET.matches('.buttons-bar *, .settings-menu *')) {
- return setVideoSettings()
- }
- }
- })
-
- obs.observe(TARGET_NODE, {
- childList: true,
- subtree: true,
- })
-
- function setVideoSettings() {
- const VOLUME = Player.volume
- const MUTED = Player.isMuted
- const QUALITY = Player.quality
- const SPEED = Player.speed
- const LOOPED = Player.isLooped
-
- Settings.setItem('volume', VOLUME)
- Settings.setItem('muted', MUTED)
- Settings.setItem('quality', QUALITY)
- Settings.setItem('speed', SPEED)
- Settings.setItem('loop', LOOPED)
- }
-
- function restoreVideoSettings() {
- Player.volume = Settings.getItem('volume')
-
- const WAS_MUTED = Settings.getItem('muted')
-
- if(WAS_MUTED) {
- Player.mute()
- }
-
- Player.quality = Settings.getItem('quality')
- Player.speed = Settings.getItem('speed')
-
- const WAS_LOOPED = Settings.getItem('loop')
-
- if(WAS_LOOPED) {
- Player.loop()
- }
- }
- }
- }
-
- class BetterVideoPage {
- static init() {
- const IS_VIDEO = isVideoPage()
-
- if(IS_VIDEO) {
- const MODULES = [
- CopyableTitle,
- FastButtons,
- SaveVideoSettings
- ]
-
- initModules(MODULES)
- }
- }
- }
-
- class Main {
- static init() {
- if(!localStorage.getItem(LOCAL_VIDEO_SETTINGS)) {
- localStorage.setItem(LOCAL_VIDEO_SETTINGS, DEFAULT_SETTINGS)
- }
-
- const MODULES = [
- CSS,
- DarkThemeChecker,
- AntiAntiAdBlock,
- AdBlock,
- PlusSymbol,
- FastSearch,
- BetterVideoPage
- ]
-
- initModules(MODULES)
-
- log('Loaded')
- }
- }
-
- Main.init()
-
- function initModules(modules) {
- for (let i = 0; i < modules.length; i++) {
- const MODULE = modules[i]
-
- initModule(MODULE)
- }
- }
-
- function initModule(module) {
- try {
- module.init()
- } catch(e) {
- console.error(TITLE, module.name + ' module, has error:', e)
- }
- }
-
- function addStyle(css) {
- let styleNode = document.createElement('style')
- styleNode.appendChild(document.createTextNode(css))
- document.head.appendChild(styleNode)
- }
-
- function toggleVisibility(el) {
- if(el.style.display === 'none') {
- el.style.display = 'block'
-
- return void 0
- }
-
- el.style.display = 'none'
- }
-
- function log(msg) {
- const CSS_LOG_DEFAULT = 'background: rgb(0, 0, 0);font-weight: 800;padding: 1px;'
-
- console.log('%cX%cVIDEOS+',
- CSS_LOG_DEFAULT + 'color: rgb(222, 38, 0);',
- CSS_LOG_DEFAULT + 'color: rgb(255, 255, 255);margin-right: -5px;',
- ' -',
- msg
- )
- }
-
- function isVideoPage() {
- return location.pathname.match(/video\d/)
- }
-
- function search(q) {
- return replaceLocation(location.origin + '/?k=' + toSearchFormat(q))
- }
-
- function toSearchFormat(str) {
- return encodeURIComponent(str.trim()).replace(/%20+/g, '+')
- }
-
- function replaceLocation(newUrl) {
- if(location.replace) {
- return location.replace(newUrl)
- }
-
- location.href = newUrl
- }
- })();
-
-
-
-
-
-
-
-
-
-
-
-