Pure Fun – Pornhub Video Downloader

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

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 or Violentmonkey 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               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
// ==/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()
})();