Sleazy Fork is available in English.

[精简版]Pornhub 视频一键下载

视频一键下载

// ==UserScript==
// @icon         https://ci.phncdn.com/www-static/favicon.ico
// @name         [精简版]Pornhub 视频一键下载
// @namespace    https://github.com/ekoooo/tampermonkey_pornhub_video_download
// @version      1.0
// @description  视频一键下载
// @author       Gemini
// @match        *://*.pornhub.com/view_video.php?viewkey=*
// @match        *://*.pornhubpremium.com/view_video.php?viewkey=*
// @grant        GM_addStyle
// @grant        GM_notification
// @require      https://cdn.jsdelivr.net/npm/jquery@4.0.0-beta.2/dist/jquery.min.js
// @license MIT
// ==/UserScript==

GM_addStyle(`
.download-urls ul {
  padding: 10px;
  font-weight: bold;
  line-height: 1.5;
}
.download-urls ul li {
  display: flex;
  align-items: center;
  height: 20px;
  max-width:400px;
}
.download-url-label {
  text-align: right;
}
.download-url-open {
  flex: 100;
}
.download-url-input {
  flex: 3;
  font-size: 12px;
  padding: 0 5px;
  border: 1px solid #ffff;
  margin: 0 5px;
}
`);

(function () {
  'use strict';

  const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  const mutationObserver = new MutationObserver(mutations => {
    mutationObserver.disconnect();
    setTimeout(() => {
      VideoParsing.init();
    }, 200);
  });

  const playerDiv = document.querySelector('#player');

  if (playerDiv) {
    mutationObserver.observe(playerDiv, {
      childList: true,
      subtree: true,
    });
  } else {
    console.warn('视频一键下载未生效!');
  }
})();

(function () {
  class VideoParsing {
    static getObjectValueByStartsWithChar(obj, char) {
      return Object.keys(obj)
        .filter(key => key.startsWith(char))
        .map(key => ({ key: key, value: obj[key] }));
    }

    static getUrlInfo() {
      const flashvars = this.getObjectValueByStartsWithChar(unsafeWindow, 'flashvars_');
      if (!flashvars.length) {
        console.error('错误,未获取视频地址!', flashvars);
        return [];
      }

      let videosInfo = [];
      try {
        videosInfo = flashvars[0]['value']['mediaDefinitions'];
      } catch (e) {
        console.error('错误,获取视频信息失败!', e, flashvars);
        return [];
      }

      let remoteAddress = videosInfo.find(video => video['remote'])?.videoUrl;
      let urlInfo = [];

      if (remoteAddress) {
        $.ajax({
          url: remoteAddress,
          async: false,
          success: (data) => {
            if (data && data.length) {
              urlInfo = data.map(item => ({
                quality: item.quality + '.' + item.format,
                url: item.videoUrl
              }));
            }
          }
        });
      }

      console.log(videosInfo);
      return urlInfo;
    }

    static injectUrls2Dom(urlInfo) {
      const li = urlInfo.map(item => `
        <li>
          <span class="download-url-label">[ ${item.quality} ]</span>
          <input class="download-url-input" value="${item.url}" />
          <a target="_blank" class="download-url-open" href="${item.url}">在新标签页中打开</a>
        </li>
      `);

      $('#player').after(`<div class="download-urls"><h3>不同分辨率视频下载地址:</h3><ul>${li.join('')}</ul></div>`);
    }

    static init() {
      this.injectUrls2Dom(this.getUrlInfo());
    }
  }

  window.VideoParsing = VideoParsing;
})();