PornHub+

Removed ads and analytics. Added filters, boss mode, etc.

As of 2022-09-07. See the latest version.

// ==UserScript==
// @name PornHub+
// @namespace -
// @version 1.2.2
// @description Removed ads and analytics. Added filters, boss mode, etc.
// @author NotYou
// @include *pornhub.com/*
// @run-at document-end
// @license GPL-3.0-or-later
// @grant none
// ==/UserScript==

// Nerd Stuff

let style = cE('style'),
    h = cE('div'),
    fs = cE('div'),
    logo = $('#headerContainer .logoWrapper'),
    bodies = [],
    videos = [
        'https://yewtu.be/latest_version?id=XyNlqQId-nk&itag=22&local=true',
        'https://yewtu.be/latest_version?id=NsUWXo8M7UA&itag=22&local=true',
        'https://yewtu.be/latest_version?id=JxS5E-kZc2s&itag=22&local=true'
    ], images = [
        'https://yewtu.be/vi/6FQsIfE7sZM/mqdefault.jpg',
        'https://yewtu.be/vi/hY7m5jjJ9mM/mqdefault.jpg',
        'https://yewtu.be/vi/iRXJXaLV0n4/mqdefault.jpg',
        'https://yewtu.be/vi/jHWKtQHXVJg/mqdefault.jpg',
        'https://yewtu.be/vi/rWNKAXAAFmY/mqdefault.jpg',
        'https://yewtu.be/vi/9xLo0PBwM9U/hqdefault.jpg',
        'https://yewtu.be/vi/46a97ejExuY/mqdefault.jpg',
        'https://yewtu.be/vi/48bIZoOQSUI/mqdefault.jpg',
        'https://yewtu.be/vi/mcYnMbJwFCA/mqdefault.jpg',
        'https://yewtu.be/vi/YHFoYJ7sAlY/mqdefault.jpg',
        'https://yewtu.be/vi/sRPXPkFx9wM/hqdefault.jpg',
        'https://yewtu.be/vi/B0Mxj4d7lEs/mqdefault.jpg'
    ], search =$('#searchInput'),
    srch = search?.value,
    playerLocal = localStorage.getItem('mgp_player')

if(!localStorage.getItem('pp')) localStorage.setItem('pp', '{"filter": {"step": "0", "getero": "0", "bdsm": "0"}, "options": {"premium": "0", "footer": "0", "net": "0"}}')

// Clean Up Btn

$('.networkListContent')?.insertAdjacentHTML('beforeend', `<li data-id="9">
<a id="cleanup-pp" class="networkTab" href="javascript:;" title="Clean up watched videos, player settings, search requests">Clean</a>
</li>`)

$('#cleanup-pp')?.addEventListener('click', cleanUp)

// Ad Block

window.open = function() {}

for (let i = 0; i < 10; i++) bodies.push(`body > [class*="${i}"]`)
style.appendChild(document.createTextNode(`
.cookiesBanner, #pb_template, .adsbytrafficjunky, .adLinks, .adLink, #hd-rightColVideoPage > .clearfix:first-child, #popsByTrafficJunky, ${bodies.join(',')}, #videoSearchResult > :first-child:not(.userCardLi),
#welcome, .container > div[class=""] > :first-child, #vpContentContainer > div:nth-child(2) > :first-child, .video-wrapper > .hd.clear, #hotVideosSection > :first-child, #js-abContainterMain, .t8fer, .t8fer k0g8,
#footerMenu_advertising, .ad-link, #videoCategory > :first-child, body > *:not(div, template, script, style, link, ins, noscript, iframe), #photosAlbumsSection.withAd > :first-child, .gifsWrapper > ul > :first-child,
#hottestVideosSection > :first-child, .carouselOverlay, .cookiesBanner + * + * {
display: none !important;
}
#header.hasAdAlert {
grid-template-rows: unset !important;
}
#headerContainer {
padding-bottom: 10px;
}
#fast-search-pp {
position: fixed;
z-index: 2147483646;
width: 400px;
height: 40px;
padding: 16px 28px 28px 16px;
background-color: rgba(21, 21, 21, 0.57);
border-radius: 3px;
left: 32vw;
top: 20vh;
}
#fast-search-input-parent-pp {
padding: 5px;
display: flex;
border: 0;
height: 40px;
width: 100%;
background-color: rgb(61, 54, 49);
border-radius: 3px;
}
#fast-search-input-parent-pp .ph-icon-search {
margin-top: 10px;
margin-right: 10px;
font-size: 20px;
}
#fast-search-input-pp {
background-color: unset;
width: 100%;
height: 100%;
font-size: 20px;
border: 0;
}
#fast-search-input-pp::placeholder {
font-style: italic;
color: rgb(164, 164, 164);
}
#download-panel-pp {
display: grid;
margin-left: 15px;
}
#download-panel-pp .reset {
background-color: rgb(40, 40, 40);
}
#download-panel-pp h2 {
margin-left: 15px;
}
.download-panel-item-pp {
margin-left: 20px;
margin-bottom: 6px;
}
.download-panel-item-pp a {
background-color: rgb(255, 144, 0);
color: rgb(0, 0, 0);
border-radius: 4px;
padding: 2px;
margin-right: 2px;
text-decoration: none !important;
}
#download-panel-pp h2 i {
font-style: italic;
font-weight: bolder;
}
#embed-mode-download {
float: right;
width: 32px;
height: 32px;
display: block;
position: relative;
top: 5px;
}
.ph-plus-icon-download {
background-image: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNiIgaGVpZ2h0PSIxNiIgZmlsbD0iY3VycmVudENvbG9yIiBjbGFzcz0iYmkgYmktZG93bmxvYWQiIHZpZXdCb3g9IjAgMCAxNiAxNiI+CiAgPHBhdGggZD0iTS41IDkuOWEuNS41IDAgMCAxIC41LjV2Mi41YTEgMSAwIDAgMCAxIDFoMTJhMSAxIDAgMCAwIDEtMXYtMi41YS41LjUgMCAwIDEgMSAwdjIuNWEyIDIgMCAwIDEtMiAySDJhMiAyIDAgMCAxLTItMnYtMi41YS41LjUgMCAwIDEgLjUtLjV6Ii8+CiAgPHBhdGggZD0iTTcuNjQ2IDExLjg1NGEuNS41IDAgMCAwIC43MDggMGwzLTNhLjUuNSAwIDAgMC0uNzA4LS43MDhMOC41IDEwLjI5M1YxLjVhLjUuNSAwIDAgMC0xIDB2OC43OTNMNS4zNTQgOC4xNDZhLjUuNSAwIDEgMC0uNzA4LjcwOGwzIDN6Ii8+Cjwvc3ZnPg==);
background-repeat: no-repeat;
background-position: center;
background-size: contain;
filter: invert(1);
display: block;
width: 32px;
height: 24px;
}`))
document.head.appendChild(style)
if(logo) {
    logo.style.display = 'flex'
    logo.insertAdjacentHTML('beforeend', '<i class="ph-icon-add" style="margin-top: 10px;font-size: 20px;"></i>')
}

// Boss Mode

h.id = 'bossMode'
h.style.width = '100%'
h.style.height = '100vh'
h.style.backgroundColor = 'rgb(255, 255, 255)'
h.style.position = 'fixed'
h.style.left = '0px'
h.style.top = '0px'
h.style.zIndex = '2147483647'
h.style.display = 'none'
h.innerHTML = `
<div style="
height: 70px;
width: 100%;
display: flex;
background: rgb(238, 238, 238);
">

<img src="https://icons.iconarchive.com/icons/papirus-team/papirus-apps/512/anki-icon.png" style="
height: 8vh;
margin-left: 1vw;
margin-top: 1vh;
">

<input type="text" style="
border: 0px !important;
background: rgb(200, 200, 200);
margin: 0 3vw;
width: 70%;
margin-top: 10px !important;
margin-bottom: -10px !important;
color: rgb(15, 15, 15);
padding: 8px;
height: 30px;
border-radius: 25px;
padding-left: 20px;
">

<span style="
border-radius: 20px;
width: 12vw;
height: 20px;
background: rgb(193, 193, 193);
margin-top: 22px;
"></span>

<span style="
border-radius: 50%;
background: rgb(193, 193, 193);
width: 50px;
height: 50px;
margin: 7px 2px 0 2vw;
"></span></div>

<div style="
height: 100%;
width: 100%;
display: flex;
">

<div style="
width: 70%;
height: 60%;
margin-left: 20px;
padding-top: 20px;
">
<video controls="true" src="${videos[~~(Math.random()*videos.length)]}" style="
width: 50vw;
height: 50vh;
"></video>
</div>

<div style="
width: 40vw;
height: 100%;
padding-left: 30px;
padding-top: 30px;
background: rgb(253, 253, 253);
">

<img src="${images[~~(Math.random() * images.length)]}" style="
width: 25vw;
">
<img src="${images[~~(Math.random() * images.length)]}" style="
width: 25vw;
">
<img src="${images[~~(Math.random() * images.length)]}" style="
width: 25vw;
"></div>

</div>`
document.body.appendChild(h)

window.addEventListener('keydown', bossMode)

// No Autoplay

if(playerLocal) {
	let p = JSON.parse(playerLocal)
	if(p.autoplay != true) p.autoplay = false
    localStorage.setItem('mgp_player', JSON.stringify(p))
}

// Remove Analytics / Nerd Stuff v2

$$('[onclick]').forEach(e => {
    if(e.getAttribute('onclick').includes('ga(', '')) e.setAttribute('onclick', e.getAttribute('onclick').replace(/ga\(.+\);?/, ''))
})

$$('[onclick=""]').forEach(e => e.removeAttribute('onclick'))

// Fast Search

fs.id = 'fast-search-pp'
fs.innerHTML = '<span id="fast-search-input-parent-pp"><i class="ph-icon-search"></i><input id="fast-search-input-pp" type="text" placeholder="Fast Search Pornhub"></span>'
fs.style.display = 'none'

let fsi = fs.children[0].children[1],
    fsb = fs.children[0].children[0]

fsi.onkeydown = fastSearch
fsb.onclick = fastSearch
document.body.appendChild(fs)

window.addEventListener('keydown', e => {
	if(e.ctrlKey && (e.key === 'k' || e.code === 'KeyK')) {
        e.preventDefault()
        hide('#fast-search-pp')
        fsi.focus()
    }
})

// Filters & Better Watch Pages

var step = [
    'step',
    'mom', 'mother', 'mommy', 'milf',
    'dad', 'father', 'daddy',
    'bro', 'brother',
    'sis', 'sister',
    'daughter',
    'son',
    'brattysis', 'myfamilypies', 'momsteachsex',
    'mylf', 'sis loves me', 'mommy\'s girl',
    'family sinners', 'pervmom', 'perv mom',
    'dad crush', 'spyfam', 'spy fam'
], get = [
    'lesbian',
    'gay', 'homo', 'homosexual',
    ' bi ', 'bisexual',
    'trans', 'transgender',
    'helloladyboy', 'mommy\'s girl', 'girlsway'
], hard = [
    'hardcore',
    'bdsm',
    'biting',
    'scratching',
    ' dom ', 'femdom', 'maledom', 'domination',
    ' wax ', 'waxing',
    ' gag ', 'gagging',
    ' whip ', 'whiping',
    ' tied ', 'tying',
    'bondage'
],

url = new URL(location.href)

if(url.searchParams.has('viewkey')) {
    let medDef = window[`flashvars_${window.VIDEO_SHOW.video_id}`].mediaDefinitions, urlToParse = medDef[medDef.length-1].videoUrl

    await (async function() {
        if(urlToParse) {
            await fetch(urlToParse)
                .then(c => c.json())
                .then(r => window.media = r)
        }
    })()
    $('#js-shareData > .tab-menu-wrapper-row').insertAdjacentHTML('beforeend', `
<div class="tab-menu-wrapper-cell">
    <a href="https://www.pornhub.com/embed/${location.search.split('viewkey=')[1]}" target="_self">
        <div id="embed_mode-btn" class="flag-btn tab-menu-item tooltipTrig" data-title="Open video in embed mode" role="button" tabindex="0">
            <i class="ph-icon-channel"></i>
            <span>Embed</span>
        </div>
    </a>
</div>`.replaceAll('\n', ''))
    let dw = cE('div'), t = $('.title-container > .title > span')
    dw.id = 'download-panel-pp'
    t.title = 'Click to copy'
    t.onclick = () => navigator.clipboard.writeText(t.innerText)
    dw.innerHTML = `<h2>${window.TRANSLATED_MESSAGE.save}</h2>`
    window.media.reverse().forEach(e => {
        dw.innerHTML += `<span class="download-panel-item-pp"><a href="${e.videoUrl}" target="_blank">${e.quality}p</a>${e.quality > 719 ? '<i class="ph-icon-hd"></i>' : ''}</span>`
    })
    dw.innerHTML += '<div class="reset"></div>'
    $('.video-wrapper > .video-actions-container').insertAdjacentElement('beforebegin', dw)
}

if(url.searchParams.has('search')||url.searchParams.has('page')||url.searchParams.has('o')||(location.pathname === '/video' && url.searchParams.toString() === '')) {
    $('#duration-wrapper').previousElementSibling.outerHTML = `
    <div class="section_bar_sidebar"><div class="section_title"><i class="ph-icon-filter"></i> Filter <span class="subtitle">( PornHub+ )</span></div></div>
    <div class="sidebar_wrapper">
    <!-- pp = (P)ornhub (P)lus -->
            <ul class="nf-categories" id="pp-filter">
                <li>
                    <a class="sidebarIndent pp-a" id="ppStepLike" href="javascript:;">
                    Hide Step-like
                    </a>
                </li>
                <li>
                    <a class="sidebarIndent pp-a" id="ppNonGetero" href="javascript:;">
                    Hide Non-Getero
                    </a>
                </li>
                <li class="sidebarIndent">
                    <a class="sidebarIndent pp-a" id="ppHardcore" href="javascript:;">
                    Hide BDSM & Hardcore
                    </a>
                </li>
            </ul>
        </div>
    <div class="section_bar_sidebar"><div class="section_title"><i class="ph-icon-toolbox"></i> Options <span class="subtitle">( PornHub+ )</span></div></div>
    <div class="sidebar_wrapper">
            <ul class="nf-categories" id="pp-filter">
                <li>
                    <a class="sidebarIndent pp-a" id="ppPremVids" href="javascript:;">
                    Hide Paid Premium Videos
                    </a>
                </li>
                <li>
                    <a class="sidebarIndent pp-a" id="ppFooter" href="javascript:;">
                    Hide Footer
                    </a>
                </li>
                <li class="sidebarIndent">
                    <a class="sidebarIndent pp-a" id="ppNetbar" href="javascript:;">
                    Hide Networkbar
                    </a>
                </li>
            </ul>
        </div>
    <div class="section_bar_sidebar"><div class="section_title">Duration <span class="subtitle">( minutes )</span></div></div>`

    $$('.pp-a').forEach(e =>
        e.addEventListener('click', () => (e.style.color = (e.style.color == 'rgb(255, 153, 0)'||e.style.color == '#f90' ? 'unset' : 'rgb(255, 153, 0)')))
    )

    let step = $('#ppStepLike'),
        geter = $('#ppNonGetero'),
        hardc = $('#ppHardcore'),
        prem = $('#ppPremVids'),
        foot = $('#ppFooter'),
        net = $('#ppNetbar'),
        pp = JSON.parse(localStorage.getItem('pp'))

    for (let i of [
        [step, 'step', hideStepLike],
        [geter, 'getero', () => hideVideo(get)],
        [hardc, 'bdsm', () => hideVideo(hard)],
        [prem, 'premium', () => hide('.nf-videos > .sectionWrapper > .reset + .sectionWrapper'), true],
        [foot, 'footer', () => hide('#footer'), true],
        [net, 'net', () => hide('#js-networkBar'), true]
    ]) {
        let i3 = i[3] ? 'options' : 'filter'
        i[0].addEventListener('click', () => {
            ppControl(i3, i[1])
            i[2]()
        })
        if(pp[i3][i[1]] === '1') {
            i[0].click()
            ppControl(i3, i[1])
        }
    }
}

// Change Stars
if(url.pathname.indexOf('/pornstar/') != -1||url.pathname.indexOf('model') != -1) {
    window.addEventListener('keydown', e => {
        if((e.key === 'ArrowRight'||e.key === 'ArrowLeft') && e.shiftKey) {
            e.preventDefault()
            $(`.pornstarsNavButtons > a${e.key === 'ArrowRight' ? ':last-child' : ':first-child'}`).click()
        }
    })
}

// Download Button in Embed Mode
if(location.pathname.indexOf('/embed/') === 0) {
    fetch(window.mp4).then(r => r.json()).then(c => {
        document.querySelector('.mgp_logo.mgp_isLink').insertAdjacentHTML('afterend', `<a href="${c[0].videoUrl}" target="_blank" id="embed-mode-download"><i class="ph-plus-icon-download"></i></a>`)
    })
}

// Nerd Stuff v3

function $(s) {
    return document.querySelector(s)
}

function $$(s) {
    return document.querySelectorAll(s)
}

function cE(t) {
    return document.createElement(t)
}

function hideStepLike() {
    $$('.clearfix > .title > a').forEach(e => {
        step.forEach(i => {
            let title = e.innerText.toLowerCase(), video = e.parentNode.parentNode.parentNode.parentNode
            if(title.match(`.?step.?${i}.?`)||title.match(`.?${i}.?`)) {
                if(video.style.display == 'none') video.style.display = ''
                else video.style.display = 'none'
            }
        })
    })
}

function hideVideo(arr) {
    $$('.clearfix > .title > a').forEach(e => {
        arr.forEach(i => {
            let title = e.innerText.toLowerCase(), video = e.parentNode.parentNode.parentNode.parentNode
            if(title.match(`.?${i}.?`)) video.style.display = video.style.display === 'none' ? '' : 'none'
        })
    })
}

function hide(selector) {
    let el = $(selector)
    if(el) el.style.display = el.style.display == 'none' ? 'unset' : 'none'
}

function bossMode(e) {
    if(e.key === '`') {
        document.title = 'Funny kitty videos - YouTurb'
        document.head.innerHTML += '<link rel="shortcut icon" href="https://icons.iconarchive.com/icons/papirus-team/papirus-apps/512/anki-icon.png" type="image/x-icon">'
        hide('#bossMode')
        $$('video').forEach(e => {
            if(e && e.pause) e.pause()
        })
    }
}

function ppControl(parent, child) {
    let pp = JSON.parse(localStorage.getItem('pp'))
    pp[parent][child] = pp[parent][child] === '0' ? '1' : '0'
    localStorage.setItem('pp', JSON.stringify(pp))
}

function cleanUp() {
    for (let i of ['watchedVideoStorage', 'watchedVideoIds', 'recentSearch', 'currentTimeStamp', 'mgp_player']) if(localStorage.getItem(i)) localStorage.removeItem(i)
}

function fastSearch(e) {
    function search() {
        let input = fsi.value.replaceAll(/[^0-9a-zA-Z\s-]+/g, ''),
            recSearch = localStorage.getItem('recentSearch')

        if(!recSearch) localStorage.setItem('recentSearch', '[]')

        let parsed = JSON.parse(recSearch)
        parsed.push(input)
        localStorage.setItem('recentSearch', JSON.stringify(parsed))
        location.replace('https://www.pornhub.com/video/search?search='+input.replaceAll(/\s/g, '+'))
    }
    if((e.type === 'keydown' && e.key === 'Enter') || e.type === 'click') search()
}

console.log(
    `Porn%cHub%c+ Loaded! (Time: ${new Date().toLocaleTimeString()}; Document State: ${document.readyState})`,
    'background: #f90;color: #000;border-radius: 3px;padding: 1px;margin-right: -5px;'
)



































// There is some eggs...
if([...Array(100).keys()][~~(Math.random() * 100)] === 99) {
    logo.querySelector('img').src = [
        'https://di.phncdn.com/pics/logos/571.png',
        'https://di.phncdn.com/pics/logos/2001.png',
        'https://di.phncdn.com/pics/logos/2221.png',
        'https://di.phncdn.com/pics/logos/4851.png',
        'https://di.phncdn.com/pics/logos/4931.png',
        'https://di.phncdn.com/pics/logos/5901.png',
        'https://di.phncdn.com/pics/logos/7191.png',
        'https://di.phncdn.com/pics/logos/7291.png'
    ][~~(Math.random() * 8)]
}