Jump to content

1 Screenshot

About This File

// ==UserScript==
// @name               Pure Fun – Pornhub Video Downloader
// @name:ar            متعة خالصة – برنامج تنزيل فيديوهات Pornhub
// @name:bg            Чиста Забава – Изтегляне на видео от Pornhub
// @name:cs            Čistá Zábava – Stahovač videí Pornhub
// @name:da            Ren Sjov – Pornhub Video Downloader
// @name:de            Reiner Spaß – Pornhub Video Downloader
// @name:el            Καθαρή Διασκέδαση – Λήψη βίντεο Pornhub
// @name:en            Pure Fun – Pornhub Video Downloader
// @name:eo            Pura Ĝuo – Pornhub Video Elŝutilo
// @name:es            Pura Diversión – Descargador de videos de Pornhub
// @name:fi            Puhtaa Huvia – Pornhub Videon Lataaja
// @name:fr            Plaisir Pur – Téléchargeur de vidéos Pornhub
// @name:fr-CA         Plaisir Pur – Téléchargeur de vidéos Pornhub
// @name:he            כיף טהור – מוריד סרטוני Pornhub
// @name:hr            Čista Zabava – Pornhub Video Downloader
// @name:hu            Tiszta Szórakozás – Pornhub Videó Letöltő
// @name:id            Keseruan Murni – Pengunduh Video Pornhub
// @name:it            Divertimento Puro – Downloader Video Pornhub
// @name:ja            ピュアファン – Pornhubビデオダウンローダー
// @name:ka            სუფთა გართობა – Pornhub ვიდეო ჩამტვირთავი
// @name:ko            순수한 즐거움 – Pornhub 비디오 다운로더
// @name:nb            Ren Moro – Pornhub Video Downloader
// @name:nl            Puur Plezier – Pornhub Video Downloader
// @name:pl            Czysta Frajda – Pornhub Video Downloader
// @name:pt-BR         Diversão Pura – Downloader de Vídeos Pornhub
// @name:ro            Distracție Pură – Pornhub Video Downloader
// @name:ru            Чистое Развлечение – Загрузчик видео Pornhub
// @name:sk            Čistá Zábava – Pornhub Video Downloader
// @name:sr            Чиста Забава – Pornhub Video Downloader
// @name:sv            Ren Nöje – Pornhub Video Downloader
// @name:th            ความสนุกบริสุทธิ์ – ตัวดาวน์โหลดวิดีโอ Pornhub
// @name:tr            Saf Eğlence – Pornhub Video İndirici
// @name:ug            پاكىلايدىغان خۇشاللىق – Pornhub ۋىدىئو چۈشۈرگۈچ
// @name:uk            Чисте Задоволення – Завантажувач відео Pornhub
// @name:vi            Niềm Vui Tinh Khiết – Trình Tải Video Pornhub
// @name:zh            纯粹乐趣 – Pornhub 视频下载器
// @name:zh-CN         纯粹乐趣 – Pornhub 视频下载器
// @name:zh-HK         純粹樂趣 – Pornhub 視頻下載器
// @name:zh-SG         纯粹乐趣 – Pornhub 视频下载器
// @name:zh-TW         純粹樂趣 – Pornhub 視頻下載器
// @description        Pornhub video download with one click | pornhub.com | Download directly without login | Download free to watch paid videos | Download videos that are prohibited | Download all viewable resolutions
// @description:ar     تنزيل فيديوهات Pornhub بنقرة واحدة | pornhub.com | التحميل مباشرة بدون تسجيل دخول | شاهد الفيديوهات المدفوعة مجاناً | تنزيل الفيديوهات المحظورة | تنزيل جميع الدقات المتاحة
// @description:bg     Изтегляне на видео от Pornhub с едно щракване | pornhub.com | Изтегляне директно без регистрация | Гледайте платени видеа безплатно | Изтегляне на забранени видеа | Изтегляне на всички налични резолюции
// @description:cs     Stáhnout video Pornhub jedním kliknutím | pornhub.com | Stáhnout přímo bez přihlášení | Sledujte placená videa zdarma | Stáhnout zakázaná videa | Stáhnout všechna dostupná rozlišení
// @description:da     Download Pornhub-video med ét klik | pornhub.com | Download direkte uden login | Se betalte videoer gratis | Download forbudte videoer | Download alle tilgængelige opløsninger
// @description:de     Pornhub Video mit einem Klick herunterladen | pornhub.com | Direkt herunterladen ohne Anmeldung | Kostenpflichtige Videos kostenlos ansehen | Verbotene Videos herunterladen | Alle verfügbaren Auflösungen herunterladen
// @description:el     Λήψη βίντεο Pornhub με ένα κλικ | pornhub.com | Κατεβάστε απευθείας χωρίς σύνδεση | Παρακολουθήστε επί πληρωμή βίντεο δωρεάν | Λήψη απαγορευμένων βίντεο | Λήψη όλων των διαθέσιμων αναλύσεων
// @description:en     Pornhub video download with one click | pornhub.com | Download directly without login | Download free to watch paid videos | Download videos that are prohibited | Download all viewable resolutions
// @description:eo     Elŝuto de Pornhub-video per unu klako | pornhub.com | Elŝutu rekte sen ensaluto | Senpage spekti pagitajn videojn | Elŝutu malpermesitajn videojn | Elŝutu ĉiujn videblajn rezoluciojn
// @description:es     Descarga de videos de Pornhub con un solo clic | pornhub.com | Descarga directamente sin iniciar sesión | Mira videos de pago gratis | Descarga videos prohibidos | Descarga todas las resoluciones disponibles
// @description:fi     Lataa Pornhub-video yhdellä napsautuksella | pornhub.com | Lataa suoraan ilman kirjautumista | Katso maksullisia videoita ilmaiseksi | Lataa kiellettyjä videoita | Lataa kaikki katsottavissa olevat resoluutiot
// @description:fr     Téléchargement vidéo Pornhub en un clic | pornhub.com | Télécharger directement sans connexion | Visionner des vidéos payantes gratuitement | Télécharger des vidéos interdites | Télécharger toutes les résolutions disponibles
// @description:fr-CA  Téléchargement vidéo Pornhub en un clic | pornhub.com | Télécharger directement sans connexion | Visionner des vidéos payantes gratuitement | Télécharger des vidéos interdites | Télécharger toutes les résolutions disponibles
// @description:he     הורדת סרטוני Pornhub בלחיצה אחת | pornhub.com | הורד ישירות בלי להתחבר | צפה בחינם בסרטונים בתשלום | הורד סרטונים אסורים | הורד את כל הרזולוציות הזמינות
// @description:hr     Preuzimanje Pornhub videa jednim klikom | pornhub.com | Preuzmite izravno bez prijave | Besplatno gledajte plaćene videozapise | Preuzmite zabranjene videozapise | Preuzmite sve dostupne rezolucije
// @description:hu     Pornhub videó letöltése egy kattintással | pornhub.com | Közvetlen letöltés bejelentkezés nélkül | Fizetős videók ingyenes megtekintése | Tiltott videók letöltése | Az összes elérhető felbontás letöltése
// @description:id     Unduh video Pornhub dengan satu klik | pornhub.com | Unduh langsung tanpa login | Tonton video berbayar gratis | Unduh video yang dilarang | Unduh semua resolusi yang tersedia
// @description:it     Download video Pornhub con un clic | pornhub.com | Scarica direttamente senza login | Guarda video a pagamento gratuitamente | Scarica video vietati | Scarica tutte le risoluzioni disponibili
// @description:ja     ワンクリックでPornhubビデオをダウンロード | pornhub.com | ログインなしで直接ダウンロード | 有料動画を無料で視聴 | 禁止動画をダウンロード | 全ての解像度をダウンロード
// @description:ka     Pornhub ვიდეო ჩამოტვირთვა ერთი დაჭერით | pornhub.com | პირდაპირ გადმოწერა შესვლის გარეშე | გადახდილი ვიდეოების უფასო ყურება | აკრძალული ვიდეოების ჩამოტვირთვა | ყველა შესაძლო რეზოლუციის ჩამოტვირთვა
// @description:ko     한 번의 클릭으로 Pornhub 비디오 다운로드 | pornhub.com | 로그인 없이 직접 다운로드 | 유료 영상 무료 보기 | 금지된 영상 다운로드 | 모든 해상도 다운로드
// @description:nb     Last ned Pornhub-video med ett klikk | pornhub.com | Last ned direkte uten innlogging | Se betalte videoer gratis | Last ned forbudte videoer | Last ned alle tilgjengelige oppløsninger
// @description:nl     Pornhub-video downloaden met één klik | pornhub.com | Direct downloaden zonder in te loggen | Betaalde video's gratis bekijken | Verboden video's downloaden | Alle beschikbare resoluties downloaden
// @description:pl     Pobierz wideo Pornhub jednym kliknięciem | pornhub.com | Pobierz bez logowania | Oglądaj płatne filmy za darmo | Pobierz zabronione filmy | Pobierz wszystkie dostępne rozdzielczości
// @description:pt-BR  Baixar vídeos do Pornhub com um clique | pornhub.com | Baixe diretamente sem login | Assista vídeos pagos de graça | Baixe vídeos proibidos | Baixe todas as resoluções disponíveis
// @description:ro     Descărcare video Pornhub cu un singur clic | pornhub.com | Descărcați direct fără autentificare | Vizionați gratuit videoclipuri plătite | Descărcați videoclipuri interzise | Descărcați toate rezoluțiile disponibile
// @description:ru     Скачать видео Pornhub одним щелчком | pornhub.com | Скачать напрямую без входа | Смотреть платные видео бесплатно | Скачать запрещенные видео | Скачать все доступные разрешения
// @description:sk     Stiahnutie videa Pornhub jedným kliknutím | pornhub.com | Stiahnutie priamo bez prihlásenia | Sledujte platené videá zadarmo | Stiahnutie zakázaných videí | Stiahnutie všetkých dostupných rozlíšení
// @description:sr     ПорнХуб Видео Довнлоад са једним кликом | pornhub.com | Преузмите директно без пријаве | Гледајте плаћене видео снимке бесплатно | Преузмите забрањене видео снимке | Преузмите све доступне резолуције
// @description:sv     Pornhub video nedladdning med ett klick | pornhub.com | Ladda ner direkt utan inloggning | Titta på betalda videor gratis | Ladda ner förbjudna videor | Ladda ner alla tillgängliga upplösningar
// @description:th     ดาวน์โหลดวิดีโอ Pornhub ด้วยคลิกเดียว | pornhub.com | ดาวน์โหลดโดยตรงโดยไม่ต้องเข้าสู่ระบบ | ดูวิดีโอแบบชำระเงินฟรี | ดาวน์โหลดวิดีโอที่ถูกห้าม | ดาวน์โหลดทุกความละเอียดที่สามารถดูได้
// @description:tr     Tek Tıkla Pornhub Video İndir | pornhub.com | Giriş yapmadan direkt indir | Ücretli videoları ücretsiz izle | Yasaklı videoları indir | Tüm mevcut çözünürlükleri indir
// @description:ug     Pornhub سىن بىر چېكىش ئارقىلىق چۈشۈرۈش | pornhub.com | كىرىشسىز بىۋاسىتە چۈشۈرۈش | پۇللىق ۋىدىئولارنى ھەقسىز كۆرۈش | تىگەلمەس ۋىدىئولارنى چۈشۈرۈش | بارلىق كۆرۈنۈشلۈك رېزولۇتسىيلارنى چۈشۈرۈش
// @description:uk     Завантажити відео Pornhub одним клацанням | pornhub.com | Завантажити без входу | Дивитися платні відео безкоштовно | Завантажити заборонені відео | Завантажити всі доступні роздільності
// @description:vi     Tải video Pornhub chỉ với một cú nhấp chuột | pornhub.com | Tải trực tiếp mà không cần đăng nhập | Xem video trả phí miễn phí | Tải video bị cấm | Tải tất cả độ phân giải có thể xem
// @description:zh     Pornhub 视频一键下载 | pornhub.com | 免登录直接下载 | 免费观看付费视频 | 下载被禁止的视频 | 下载所有可观看分辨率
// @description:zh-CN  Pornhub 视频一键下载 | pornhub.com | 免登录直接下载 | 免费观看付费视频 | 下载被禁止的视频 | 下载所有可观看分辨率
// @description:zh-HK  Pornhub 視頻一鍵下載 | pornhub.com | 免登入直接下載 | 免費觀看付費視頻 | 下載被禁止的視頻 | 下載所有可觀看分辨率
// @description:zh-SG  Pornhub 视频一键下载 | pornhub.com | 免登录直接下载 | 免费观看付费视频 | 下载被禁止的视频 | 下载所有可观看分辨率
// @description:zh-TW  Pornhub 視頻一鍵下載 | pornhub.com | 免登入直接下載 | 免費觀看付費視頻 | 下載被禁止的視頻 | 下載所有可觀看分辨率
// @namespace          pure_fun_script_87
// @version            1.1.2
// @license            MIT
// @author             Matthew,人民的勤务员
// @icon               data:image/svg+xml;charset=utf-8;base64,Cjxzdmcgd2lkdGg9IjE5OCIgaGVpZ2h0PSI3MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHJlY3Qgd2lkdGg9IjE5OCIgaGVpZ2h0PSI3MCIvPgo8cmVjdCB4PSIxMDgiIHk9IjEwIiB3aWR0aD0iODAiIGhlaWdodD0iNTAiIHJ4PSI0IiBmaWxsPSIjZjc5NzFkIi8+Cgo8ZyB0cmFuc2Zvcm09Im1hdHJpeCguMSAwIDAgLjEgODYuODUgMzAuMTUpIiBzdHJva2Utd2lkdGg9IjEwIj4KPHBhdGggZD0ibTg4Ny0zMGMtNS0yLTExLTMtMTctMy0yNC0yLTU0IDctNjggMTlsMy05N2gtNTd2MzAxaDUzdi0xN2MyNSAxNCA0MyAyMSA2NiAyMSA2Ni01IDkzLTY0IDkzLTExNi0xLTUyLTIzLTk3LTczLTEwOHptLTMyIDE3OWMtMzUgMC01MC00MS01MC03M3MxMS02NSA0OC02NSA0OCA0MSA0OCA3MGMwIDMyLTExIDY4LTQ2IDY4em0tMjAwLTg1YzAgMzEtMiA1MC01IDU4LTggMTgtMjQgMjgtNDIgMjktMTgtMS0yNi0xMC0zMy0yMy0yLTctMy0yNi0zLTU2di0xMDBoLTU4djEzOGMtMSA0OSAyNSA4NCA3MyA4NCAyNiAwIDU0LTkgNzItMjh2MjNoNTN2LTIxN2gtNTd6bS0yNDEtOTdjLTI4LTEtNTkgNi03NCAyMHYtOThoLTU3djMwMGg1N3YtMTA5YzAtMTggMi0zMiA1LTQxIDktMTggMjQtMjggNDMtMjggMTYgMCAyNSA4IDMyIDIwIDIgNiAzIDIxIDMgNDR2MTE1aDU4di0xMjhjMC0yMC0xLTM0LTMtNDMtMTItMzQtMzYtNTEtNjQtNTIiLz4KPHBhdGggZD0ibTY4LTQ1Yy0yNC0xLTYzIDgtNzUgMjd2LTIyaC01NnYyMjloNjB2LTEwM2MwLTI2IDItNDMgNS01MyA4LTIwIDI2LTMxIDQ1LTMxIDE4IDAgMjcgOSAzNCAyMyAyIDcgNCAyMyA0IDQ4djExNmg2MHYtMTQyYzAtMTgtMS0zMS0zLTQxLTEwLTM1LTQxLTUwLTc0LTUxem0tMjU3IDI3di0yMmgtNTZ2MjI5aDYwdi03MGMwLTM5IDItNjUgNS03NyA0LTEyIDgtMjEgMTQtMjYgNi00IDEzLTcgMjItNyA4IDAgMTggNCAyOCAxMGwxOS01MmMtMTMtOC0yNi0xMi00MC0xMi0yMCAxLTQwIDEyLTUyIDI3em0tMjA1LTI3Yy0yMiAwLTQyIDUtNjAgMTUtMTkgMTAtMzMgMjQtNDMgNDNzLTE1IDM4LTE1IDU5YzAgMjYgNSA0OCAxNSA2NiAxMCAxOSAyNSAzMyA0NCA0MiAxOSAxMCAzOSAxNCA2MCAxNCAzNCAwIDYyLTExIDg0LTM0IDIzLTIzIDM0LTUxIDM0LTg2IDAtMzQtMTEtNjMtMzMtODUtMjMtMjMtNTEtMzQtODYtMzRtNDAgMTcyYy0xMCAxMi0yNCAxOC0zOSAxOC0xNiAwLTI5LTYtNDAtMThzLTE2LTMwLTE2LTUyYzAtMjMgNS00MCAxNi01MnMyNC0xOCA0MC0xOGMxNSAwIDI5IDYgMzkgMTggMTEgMTIgMTYgMjkgMTYgNTEgMCAyMy01IDQxLTE2IDUzbS0zMTAtMjU0aC0xMDN2MzE2aDY0di0xMTloNDJjNTEgMiAxMDItNiAxMjYtNTEgNy0xMyAxMC0yOSAxMC00OSAwLTQzLTI0LTgxLTYzLTkyLTEyLTMtMzctNS03Ni01em00NyAxMzhjLTkgNC0yNiA1LTUxIDVoLTM1di04OWgzMWMyMyAwIDM4IDAgNDYgMiAyMiA1IDM2IDIyIDM2IDQyLTEgMTktMTEgMzQtMjcgNDAiIGZpbGw9IiNmZmYiLz4KPC9nPgo8L3N2Zz4K
// @match              *://*.pornhub.com/view_video.php?viewkey=*
// @match              *://*.pornhubpremium.com/view_video.php?viewkey=*
// @connect             phncdn.com
// @grant               GM_setClipboard
// @grant               unsafeWindow
// @grant               GM_setClipboard
// @grant               GM_download
// @grant               GM_addStyle
// @downloadURL https://update.sleazyfork.org/scripts/551131/Pure Fun – Pornhub Video Downloader.user.js
// @updateURL https://update.sleazyfork.org/scripts/551131/Pure Fun – Pornhub Video Downloader.meta.js
// ==/UserScript==

/**
 * !Matthew modified from the following script. Thanks to heckles and liuwanlin.
 * !This script follows the MIT License. Based on the original author’s work, the code structure and UI have been optimized for a more polished appearance.
 * https://greasyfork.org/zh-CN/scripts/491333
 * https://greasyfork.org/zh-CN/scripts/491329
 * https://sleazyfork.org/en/scripts/528800
 */

(function () {
    'use strict'
    const userLang = (navigator.languages && navigator.languages[0]) || navigator.language || 'en'
    const translations = {
        'en': {
            downloading: 'Downloading...',
            finderror: 'Video download link not found',
            fetcherror: 'Error fetching video, please check the console for details',
            downloadsuccess: 'Download successful',
            downloaderror: 'Error downloading video, please check the console for details',
            downloadfailed: 'Download failed',
            downloadfailed_nosize: 'Unable to retrieve file size',
            copydownloadbtn: 'Copy',
            copysuccess: 'Copy successful',
            downloadbtn: 'Download',
            linkTip: 'Video download URL:'
        },
        'zh-CN,zh,zh-SG': {
            downloading: '下载中...',
            finderror: '未找到视频下载链接',
            fetcherror: '获取视频时出错,请到控制台查看详细信息',
            downloadsuccess: '下载成功',
            downloaderror: '下载视频时出错,请到控制台查看详细信息',
            downloadfailed: '下载失败',
            downloadfailed_nosize: '无法获取文件大小',
            copydownloadbtn: '复制',
            copysuccess: '复制成功',
            downloadbtn: '下载',
            linkTip: '视频下载地址:'
        },
        'zh-TW,zh-HK,zh-MO': {
            downloading: '下載中...',
            finderror: '未找到視頻下載連結',
            fetcherror: '獲取視頻時出錯,請到控制台查看詳細信息',
            downloadsuccess: '下載成功',
            downloaderror: '下載視頻時出錯,請到控制台查看詳細信息',
            downloadfailed: '下載失敗',
            downloadfailed_nosize: '無法獲取文件大小',
            copydownloadbtn: '複製',
            copysuccess: '複製成功',
            downloadbtn: '下載',
            linkTip: '視頻下載地址:'
        },
        'ja': {
            downloading: 'ダウンロード中...',
            finderror: 'ビデオのダウンロードリンクが見つかりません',
            fetcherror: 'ビデオの取得中にエラーが発生しました。詳細はコンソールを確認してください',
            downloadsuccess: 'ダウンロード成功',
            downloaderror: 'ビデオのダウンロード中にエラーが発生しました。詳細はコンソールを確認してください',
            downloadfailed: 'ダウンロード失敗',
            downloadfailed_nosize: 'ファイルサイズを取得できません',
            copydownloadbtn: 'コピー',
            copysuccess: 'コピー成功',
            downloadbtn: 'ダウンロード',
            linkTip: 'ビデオダウンロードURL:'
        }
    }

    const getTranslations = (lang) => {
        for (const key in translations) {
            if (key === lang || key.split(',').includes(lang)) {
                return translations[key];
            }
        }
        return translations['en'];
    }
    const translate = new Proxy(
        function (key) {
            const lang = userLang;
            const strings = getTranslations(lang);
            return strings[key] || translations['en'][key];
        },
        {
            get(target, prop) {
                const lang = userLang;
                const strings = getTranslations(lang);
                return strings[prop] || translations['en'][prop];
            }
        }
    )
    unsafeWindow.translate = translate;
    
    function Toast(msg, duration = 3000, backgroundColor = 'rgba(0, 0, 0, 0.7)', textColor = 'rgb(255, 255, 255)', position = 'bottom-right') {
        const toast = document.createElement('div');
        toast.className = 'toast';
        toast.innerHTML = msg;
        toast.style.cssText = `
            max-width: 80%;
            min-width: 150px;
            padding: 5px;
            height: auto;
            color: ${textColor};
            line-height: 1.5;
            text-align: center;
            border-radius: 5px;
            position: fixed;
            z-index: 2147483647;
            background: ${backgroundColor};
            font-size: 15px;
            transition: opacity 0.5s ease-in, transform 0.5s ease-in;
            word-wrap: break-word;
        `;
    
        // 使用位置参数设置位置样式
        const positions = {
            'top': 'top: 10%; left: 50%; transform: translate(-50%, 0);',
            'bottom': 'bottom: 10%; left: 50%; transform: translate(-50%, 0);',
            'left': 'top: 50%; left: 10%; transform: translate(0, -50%);',
            'right': 'top: 50%; right: 10%; transform: translate(0, -50%);',
            'top-left': 'top: 10%; left: 10%; transform: translate(0, 0);',
            'top-right': 'top: 10%; right: 10%; transform: translate(0, 0);',
            'bottom-left': 'bottom: 10%; left: 10%; transform: translate(0, 0);',
            'bottom-right': 'bottom: 10%; right: 10%; transform: translate(0, 0);',
            'center': 'top: 50%; left: 50%; transform: translate(-50%, -50%);',
        };
    
        toast.style.cssText += positions[position] || positions['bottom-right'];
    
        document.body.appendChild(toast);
    
        setTimeout(() => {
            toast.style.opacity = '0';
            setTimeout(() => document.body.removeChild(toast), 500);
        }, duration);
    
        const mediaQuery = `
            @media only screen and (max-width: 600px) {
                .toast {
                    font-size: 14px;
                    padding: 10px;
                    max-width: 90%;
                    min-width: 0;
                }
            }
        `;
        const style = document.createElement('style');
        style.textContent = mediaQuery;
        document.head.appendChild(style);
    }

    class VideoParsing {
        
        static addStyle(){
            GM_addStyle(`
                .download-urls {
                    margin: 15px 0px;
                    padding: 12px;
                    background: #000;
                    border: 1px solid #6f6f6f;
                    border-radius: 5px;
                    font-size: 14px;
                    max-width: 600px;
                }
                .download-urls h3 {
                    margin-bottom: 8px;
                    font-size: 16px;
                    font-weight: bold;
                    color: #333;
                }
                .download-urls ul {
                    padding: 0;
                    margin: 0;
                    list-style: none;
                }
                .download-urls ul li {
                    display: flex;
                    align-items: center;
                    gap: 10px;
                    margin-bottom: 8px;
                }
                .download-url-label {
                    flex: 0 0 90px;
                    font-weight: bold;
                    color: #FFF;
                }
                .download-url-input {
                    flex: 1;
                    font-size: 12px;
                    padding: 3px 6px;
                    border: 1px solid #ccc;
                    border-radius: 5px;
                    background: #fff;
                    color:#000;
                }
                .download-url-copy, .download-url-mp4 {
                    padding: 4px 10px;
                    border-radius: 5px;
                    border: none;
                    cursor: pointer;
                    font-size: 12px;
                }
                .download-url-copy {
                    background: #eee;
                    color: #333;
                }
                .download-url-mp4 {
                    background: #ff9000;
                    color: #fff;
                }
                .download-url-copy:hover {
                    background: #ddd;
                }
                .download-url-mp4:hover {
                    background: #ffa31a;
                }
            `);
        }
        
        static getObjectValueByStartsWithChar(obj, char) {
            const vars = []
            Object.keys(obj).forEach(key => {
                if (key.startsWith(char)) {
                    vars.push({
                        key: key,
                        value: obj[key]
                    })
                }
            })
            return vars;
        }

        static getUrlInfo() {
            const flashvars = this.getObjectValueByStartsWithChar(unsafeWindow, 'flashvars_')
            if (!flashvars.length) {
                console.warn(translate.finderror)
                return
            }
            let videosInfo = []
            try {
                videosInfo = flashvars[0]['value']['mediaDefinitions']
            } catch (e) {
                console.error(translate.fetcherror, e)
                return
            }
            let remoteAddress
            let urlInfo = []
            for (let i = 0; i < videosInfo.length; i++) {
                if (videosInfo[i]['remote']) {
                    remoteAddress = videosInfo[i]['videoUrl']
                    break
                }
            }

            if (remoteAddress) {
                const xhr = new XMLHttpRequest()
                xhr.open("GET", remoteAddress, false)
                xhr.onload = function () {
                    if (xhr.status === 200) {
                        try {
                            const data = JSON.parse(xhr.responseText)
                            if (Array.isArray(data)) {
                                urlInfo = urlInfo.concat(data.map(item => ({
                                    quality: item.quality + '.' + item.format,
                                    url: item.videoUrl
                                })));
                            }
                        } catch (err) {
                            console.error(err)
                        }
                    }
                }
                xhr.send()
            }
            return urlInfo
        }

        static injectUrls2Dom(urlInfo) {
            const container = document.createElement("div");
            container.className = "download-urls";
            
            const title = document.createElement("h3");
            title.textContent = translate.linkTip;
            container.appendChild(title);

            if (urlInfo && urlInfo.length>0){
                const ul = document.createElement("ul");
                urlInfo.forEach(item => {
                    const li = document.createElement("li");
                
                    const label = document.createElement("span");
                    label.className = "download-url-label";
                    label.textContent = `[ ${item.quality} ]`;
                
                    const input = document.createElement("input");
                    input.className = "download-url-input";
                    input.value = item.url;
                    input.readOnly = true;
                
                    const copyBtn = document.createElement("button");
                    copyBtn.className = "download-url-copy";
                    copyBtn.textContent = translate.copydownloadbtn;
                    copyBtn.dataset.href = item.url;
                
                    const dlBtn = document.createElement("button");
                    dlBtn.className = "download-url-mp4";
                    dlBtn.textContent = translate.downloadbtn;
                    dlBtn.dataset.href = item.url;
                
                    li.appendChild(label);
                    li.appendChild(input);
                    li.appendChild(copyBtn);
                    li.appendChild(dlBtn);
                    ul.appendChild(li);
                });
                container.appendChild(ul)
            }
            
            const player = document.querySelector("#player");
            if (player){
                player.insertAdjacentElement("afterend", container);
            }

            const playerWrapper = document.querySelector(".playerWrapper")
            if (playerWrapper){
                playerWrapper.insertAdjacentElement("afterend", container);
            }
        }

        static initEvens() {
            document.addEventListener("click", function (e) {
                if (e.target.classList.contains("download-url-copy")) {
                    e.preventDefault();
                    const url = e.target.dataset.href;
                    GM_setClipboard(url);
                    Toast(translate.copysuccess, 3000, 'rgb(18, 219, 18)', '#ffffff', 'top');
                }
            })
        }

        static initDownEvens() {
            document.addEventListener("click", function (e) {
                if (e.target.classList.contains("download-url-mp4")) {
                    e.preventDefault()
                    downloadMp4(e.target.dataset.href, e.target);
                }
            })
        }
        
        static init() {
            this.addStyle();
            this.injectUrls2Dom(this.getUrlInfo())
            this.initEvens()
            this.initDownEvens()
        }
    }
    unsafeWindow.VideoParsing = VideoParsing;
    
    function getHumanReadableSize(sizeb) {
        const sizes = ['B', 'KB', 'MB', 'GB', 'TB']
        const size = sizeb
        let i = parseInt(Math.floor(Math.log(size) / Math.log(1024)))
        const humanReadableSize = (size / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i]
        return humanReadableSize
    }
    function sanitizeTitle() {
        var title = document.title
        title = title.replace(/- Pornhub\.com/, '')
        return title.replace(/[/:*?"<>|]/g, '_').trim();
    }

    async function downloadMp4(videoUrl, element) {
        try {
            const response = await fetch(videoUrl)
            if (!response.ok) {
                element.textContent = translate('downloadfailed');
            }
 
            const contentLength = response.headers.get('Content-Length');
            if (!contentLength) {
                element.textContent = translate('downloadfailed_nosize');
                return;
            }
            const reader = response.body.getReader();
            const totalSize = contentLength ? parseInt(contentLength, 10) : 0;
            let downloadedSize = 0;
            const chunks = [];
            while (true) {
                const { done, value } = await reader.read()
                if (done) break
                downloadedSize += value.length
                chunks.push(value)
                if (totalSize) {
                    const progress = ((downloadedSize / totalSize) * 100).toFixed(2)
                    element.textContent = `${translate('downloading')} ${progress}% (${getHumanReadableSize(downloadedSize)} / ${getHumanReadableSize(totalSize)})`;
                } else {
                    element.textContent = `${translate('downloading')} ${getHumanReadableSize(downloadedSize)}`;
                }
            }
            const blob = new Blob(chunks);
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = sanitizeTitle()+".mp4";
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            document.body.removeChild(a);
            Toast(translate('downloadsuccess'), 3000, 'rgb(18, 219, 18)', '#ffffff', 'top');
        } catch (error) {
            Toast(translate('downloaderror'), 3000, 'rgb(173, 7, 7)', '#ffffff', 'top');
            console.error(translate('downloaderror'), error);
        }
    }
    VideoParsing.init()
})();

 


User Feedback

Recommended Comments

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Add a comment...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...