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) } })()