DoctorEye's Perfect PornHub Downloader

Improved downloader script using video title for saved file name

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         DoctorEye's Perfect PornHub Downloader
// @namespace    DoctorEye
// @version      1.2
// @description  Improved downloader script using video title for saved file name
// @author       DoctorEye
// @license      UNLICENSED
// @match        https://www.pornhub.com/view_video.php?*
// @match        *://www.pornhub.com/view_video.php*
// @match        *://*.pornhub.com/view_video.php*
// @match        *://pornhub.com/view_video.php*
// @match        https://www.pornhubpremium.com/view_video.php
// @match        https://www.pornhubpremium.com/view_video.php*
// @match        *://www.pornhubpremium.com/view_video.php*
// @match        *://*.pornhubpremium.com/view_video.php*
// @match        *://pornhubpremium.com/view_video.php*
// @grant        GM.xmlHttpRequest
// ==/UserScript==

(function () {
    // Get video title from h1.title
    let titleElement = document.querySelector('h1.title span.inlineFree');
    let videoName = titleElement ? titleElement.textContent.trim() + '.mp4' : 'Default_Video_Title.mp4';
    
    // Sanitize filename
    videoName = videoName.replace(/[\/\\:*?"<>|]/g, '');

    // Locate video data
    let [id, flashvars] = Object.entries(unsafeWindow).find(([key, value]) => /^flashvars_\d+$/.test(key)) || [null, null];
    var medias = flashvars.mediaDefinitions;

    for (var key in medias) {
        var reg = new RegExp("https:\/\/([a-zA-Z0-9]+)\.pornhub(premium)?.com\/video\/get_media\?.+");
        if (reg.test(medias[key].videoUrl)) {
            GM.xmlHttpRequest({
                method: "GET",
                url: medias[key].videoUrl,
                responseType: "json",
                onload: function (xhr) {
                    var mp4files = JSON.parse(xhr.responseText);
                    var element = document.getElementsByClassName("ratingInfo")[0];

                    for (var key in mp4files) {
                        if (mp4files[key].format == "mp4") {
                            var link = document.createElement("a");
                            link.setAttribute('target', '_blank');
                            link.setAttribute('rel', 'noopener noreferrer');
                            link.setAttribute('href', mp4files[key].videoUrl);
                            link.setAttribute('style', 'padding-left:2px');
                            link.textContent = mp4files[key].quality; // Display only resolution

                            // Add download functionality
                            link.addEventListener('click', async (e) => {
                                e.preventDefault();
                                const fileURL = mp4files[key].videoUrl;
                                await downloadVideo(fileURL, videoName);
                            });

                            element.appendChild(link);
                            
                            var space = document.createElement("a");
                            space.textContent = " ";
                            element.appendChild(space);
                        }
                    }
                }
            });
        }
    }

    // Function to download video using fetch
    async function downloadVideo(fileURL, fileName) {
        const response = await fetch(fileURL);
        
        if (!response.ok) throw new Error('Network response was not ok');

        const blob = await response.blob();
        const url = window.URL.createObjectURL(blob);

        const a = document.createElement('a');
        a.style.display = 'none';
        a.href = url;
        a.download = fileName;

        document.body.appendChild(a);
        a.click();

        window.URL.revokeObjectURL(url);
    }
})();