NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name PornHub Channel Videos Link Grabber
// @description This adds an "Get all video links" button on channel pages (in the tab -> videos) which opens an popup and show all video links from this channel as list
// @version 0.0.2
// @license MIT
// @match https://pornhub.com/channels/*
// @match https://*.pornhub.com/channels/*
// @match https://pornhubpremium.com/channels/*
// @match https://*.pornhubpremium.com/channels/*
// @updateURL https://openuserjs.org/meta/SuperPanda/PornHub_Channel_Videos_Link_Grabber.meta.js
// @downloadURL https://openuserjs.org/install/SuperPanda/PornHub_Channel_Videos_Link_Grabber.user.js
// @copyright 2020, SuperPanda (https://openuserjs.org/users/SuperPanda)
// @grant GM.xmlHttpRequest
// ==/UserScript==
(function () {
'use strict'
addcss(`.loader-links {
position: fixed;
top: 40vh;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.loader-links-wrapper {
align-items: center;
position: fixed;
background-color: rgba(0,0,0,0.8);
display: flex;
height: 100vh;
width: 100%;
justify-content: center;
margin: 0;
z-index: 500;
overflow: hidden;
}
.loader-links {
width: 60px;
}
.loader-links-wheel {
animation: spin 1s infinite linear;
border: 2px solid rgba(30, 30, 30, 0.5);
border-left: 4px solid #fff;
border-radius: 50%;
height: 50px;
margin-bottom: 10px;
width: 50px;
}
.loader-links-text {
color: #fff;
font-family: arial, sans-serif;
}
.loader-links-text:after {
content: 'Loading';
animation: load 2s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
@keyframes load {
0% {
content: 'Loading';
}
33% {
content: 'Loading.';
}
67% {
content: 'Loading..';
}
100% {
content: 'Loading...';
}
}`)
var activeLog = true
var linkList = []
var currentUrl = window.location.href
var paginationBaseUrl = currentUrl
var btnContainer = document.querySelector('.rightSide .sectionChannelsWrapper div.title')
var linkGrabberBtn = document.createElement('a')
linkGrabberBtn.text = 'Get all video links'
linkGrabberBtn.onclick = startGettingAllTheLinks
linkGrabberBtn.classList.add('greyButton')
linkGrabberBtn.classList.add('float-right')
btnContainer.appendChild(linkGrabberBtn)
function startGettingAllTheLinks () {
Promise.resolve(ShowLoader())
.then(getLinks)
.then(() => {
if (activeLog == true) { console.log('found ' + linkList.length + ' links') }
for (var i = 0; i < linkList.length; i++) {
if (activeLog == true) { console.log(linkList[i].href) }
}
})
.then(showLinks)
}
const wait = ms => new Promise((resolve) => setTimeout(resolve, ms))
const addQueryParam = function (url, paramName, paramValue) {
if (url.indexOf('?') !== -1) {
let newUrl = new URL(url)
if (newUrl.searchParams.has(paramName)) {
newUrl.searchParams.delete(paramName)
}
newUrl.searchParams.append(paramName, paramValue)
return newUrl.toString()
} else {
return url + '?' + paramName + '=' + paramValue
}
}
const getLinks = async function (index = 1) {
let url
let responseData
if (currentUrl.indexOf('/videos') === -1) {
url = currentUrl + '/videos?page=' + index
} else {
url = currentUrl + '?page=' + index
}
try {
responseData = await makeRequest('GET', url)
} catch (error) {
if (activeLog == true) { console.log(error) }
}
if (responseData) {
if (responseData.status && responseData.status >= 200 && responseData.status < 300) {
extractLinks(responseData.response)
if (activeLog == true) { console.log('parsed page ' + index) }
await getLinks(index + 1)
} else {
switch (responseData.status) {
case 404:
if (activeLog == true) { console.log('404 for page ' + index + '. Looks like ' + (index - 1) + ' is the last page.') }
break
case 429:
if (activeLog == true) { console.log('Too many requests. I\'ll wait a bit and try again') }
await wait(1000)
await getLinks(index)
break
default:
console.error('Augh, there was an error!', responseData.status, responseData.statusText, index)
break
}
}
} else {
if (activeLog == true) { console.log('now this is unexpected ...') }
}
}
function extractLinks (response) {
var links = response.querySelectorAll('div.sectionChannelsWrapper ul.videos li .title a')
for (var i = 0; i < links.length; i++) {
linkList.push(links[i])
}
}
function makeRequest (method, url) {
if (activeLog == true) { console.log('new Request ' + method + ' ' + url) }
return new Promise(function (resolve, reject) {
GM.xmlHttpRequest({
method: method,
url: url,
onload: function (response) {
var responseXML = null
responseXML = new DOMParser()
.parseFromString(response.responseText, 'text/html')
resolve({
response: responseXML,
status: response.status,
statusText: response.statusText
})
},
onerror: function (response) {
reject(new Error('the request ' + method + ' ' + url + ' failed'))
}
})
})
}
function ShowLoader () {
var loader_wrapper = document.createElement('div')
loader_wrapper.className = 'loader-links-wrapper'
loader_wrapper.id = 'createLinksLoader'
var loader = document.createElement('div')
var loader_wheel = document.createElement('div')
var loader_text = document.createElement('div')
loader.className = 'loader-links'
loader_wheel.className = 'loader-links-wheel'
loader_text.className = 'loader-links-text'
loader_wrapper.appendChild(loader)
loader.appendChild(loader_wheel)
loader.appendChild(loader_text)
var addLoader = document.body
addLoader.insertBefore(loader_wrapper, addLoader.childNodes[0])
}
function RemoveLoader () {
var loader = document.getElementById('createLinksLoader')
if (loader) {
loader.style.transition = '.5s';
loader.style.opacity = '0';
loader.style.visibility = 'hidden';
}
}
function addcss (css) {
var head = document.getElementsByTagName('head')[0]
var s = document.createElement('style')
s.setAttribute('type', 'text/css')
if (s.styleSheet) {
s.styleSheet.cssText = css
} else {
s.appendChild(document.createTextNode(css))
}
head.appendChild(s)
}
function showLinks () {
var outerModalDiv = document.createElement('div')
var innerModalDiv = document.createElement('div')
outerModalDiv.id = 'pornstarVidsLinkContainingModalPanel'
outerModalDiv.style.display = 'block'
outerModalDiv.style.position = 'fixed'
outerModalDiv.style.zIndex = '100'
outerModalDiv.style.paddingTop = '100px'
outerModalDiv.style.left = '0'
outerModalDiv.style.top = '0'
outerModalDiv.style.width = '100%'
outerModalDiv.style.height = '100%'
outerModalDiv.style.overflow = 'auto'
outerModalDiv.style.backgroundColor = 'rgb(0,0,0)'
outerModalDiv.style.backgroundColor = 'rgb(0,0,0,0.4)'
var closeButtonContainer = document.createElement('div')
closeButtonContainer.className = 'userButtons'
var closeButton = CreateButton('X', null, RemoveOuterModalPanel)
closeButton.style.cssFloat = 'right'
closeButtonContainer.appendChild(closeButton)
innerModalDiv.appendChild(closeButtonContainer)
innerModalDiv.style.backgroundColor = '#1b1b1b'
innerModalDiv.style.margin = 'auto'
innerModalDiv.style.padding = '20px'
innerModalDiv.style.border = '1px solid #888'
innerModalDiv.style.width = '50%'
innerModalDiv.style.color = '#ababab'
innerModalDiv.style.textAlign = 'center'
var founded = document.createElement('p')
founded.innerHTML = 'I have found '+ linkList.length + ' video links.'
innerModalDiv.appendChild(founded)
var linkListDiv
linkListDiv = document.createElement('textarea')
linkListDiv.readOnly = true;
linkListDiv.style.width = '600px'
linkListDiv.style.height = '300px'
for (var i = 0; i < linkList.length; i++) {
var span = document.createElement('p')
span.innerHTML = linkList[i].href + ' '
linkListDiv.innerHTML += linkList[i].href + ' ';
}
RemoveLoader()
innerModalDiv.appendChild(linkListDiv)
outerModalDiv.appendChild(innerModalDiv)
document.body.appendChild(outerModalDiv)
}
function CreateButton (text, id, onClickEvent) {
var innerbutton = document.createElement('button')
innerbutton.innerText = text
innerbutton.className = 'buttonBase'
innerbutton.style.backgroundColor = '#f90'
innerbutton.style.color = '#000'
innerbutton.style.fontWeight = '700'
innerbutton.display = 'inline-block'
var button = document.createElement('div')
if (id) button.id = id
button.style.padding = '5px 10px'
button.style.lineHeight = '1.2em'
button.style.borderRadius = '4px'
button.onclick = onClickEvent
button.appendChild(innerbutton)
return button
}
function RemoveOuterModalPanel () {
var toRemove = document.getElementById('pornstarVidsLinkContainingModalPanel')
toRemove.parentNode.removeChild(toRemove)
}
})()