Sleazy Fork is available in English.

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

视频一键下载

  1. // ==UserScript==
  2. // @icon https://ci.phncdn.com/www-static/favicon.ico
  3. // @name [精简版]Pornhub 视频一键下载
  4. // @namespace https://github.com/ekoooo/tampermonkey_pornhub_video_download
  5. // @version 1.0
  6. // @description 视频一键下载
  7. // @author Gemini
  8. // @match *://*.pornhub.com/view_video.php?viewkey=*
  9. // @match *://*.pornhubpremium.com/view_video.php?viewkey=*
  10. // @grant GM_addStyle
  11. // @grant GM_notification
  12. // @require https://cdn.jsdelivr.net/npm/jquery@4.0.0-beta.2/dist/jquery.min.js
  13. // @license MIT
  14. // ==/UserScript==
  15.  
  16. GM_addStyle(`
  17. .download-urls ul {
  18. padding: 10px;
  19. font-weight: bold;
  20. line-height: 1.5;
  21. }
  22. .download-urls ul li {
  23. display: flex;
  24. align-items: center;
  25. height: 20px;
  26. max-width:400px;
  27. }
  28. .download-url-label {
  29. text-align: right;
  30. }
  31. .download-url-open {
  32. flex: 100;
  33. }
  34. .download-url-input {
  35. flex: 3;
  36. font-size: 12px;
  37. padding: 0 5px;
  38. border: 1px solid #ffff;
  39. margin: 0 5px;
  40. }
  41. `);
  42.  
  43. (function () {
  44. 'use strict';
  45.  
  46. const MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
  47. const mutationObserver = new MutationObserver(mutations => {
  48. mutationObserver.disconnect();
  49. setTimeout(() => {
  50. VideoParsing.init();
  51. }, 200);
  52. });
  53.  
  54. const playerDiv = document.querySelector('#player');
  55.  
  56. if (playerDiv) {
  57. mutationObserver.observe(playerDiv, {
  58. childList: true,
  59. subtree: true,
  60. });
  61. } else {
  62. console.warn('视频一键下载未生效!');
  63. }
  64. })();
  65.  
  66. (function () {
  67. class VideoParsing {
  68. static getObjectValueByStartsWithChar(obj, char) {
  69. return Object.keys(obj)
  70. .filter(key => key.startsWith(char))
  71. .map(key => ({ key: key, value: obj[key] }));
  72. }
  73.  
  74. static getUrlInfo() {
  75. const flashvars = this.getObjectValueByStartsWithChar(unsafeWindow, 'flashvars_');
  76. if (!flashvars.length) {
  77. console.error('错误,未获取视频地址!', flashvars);
  78. return [];
  79. }
  80.  
  81. let videosInfo = [];
  82. try {
  83. videosInfo = flashvars[0]['value']['mediaDefinitions'];
  84. } catch (e) {
  85. console.error('错误,获取视频信息失败!', e, flashvars);
  86. return [];
  87. }
  88.  
  89. let remoteAddress = videosInfo.find(video => video['remote'])?.videoUrl;
  90. let urlInfo = [];
  91.  
  92. if (remoteAddress) {
  93. $.ajax({
  94. url: remoteAddress,
  95. async: false,
  96. success: (data) => {
  97. if (data && data.length) {
  98. urlInfo = data.map(item => ({
  99. quality: item.quality + '.' + item.format,
  100. url: item.videoUrl
  101. }));
  102. }
  103. }
  104. });
  105. }
  106.  
  107. console.log(videosInfo);
  108. return urlInfo;
  109. }
  110.  
  111. static injectUrls2Dom(urlInfo) {
  112. const li = urlInfo.map(item => `
  113. <li>
  114. <span class="download-url-label">[ ${item.quality} ]</span>
  115. <input class="download-url-input" value="${item.url}" />
  116. <a target="_blank" class="download-url-open" href="${item.url}">在新标签页中打开</a>
  117. </li>
  118. `);
  119.  
  120. $('#player').after(`<div class="download-urls"><h3>不同分辨率视频下载地址:</h3><ul>${li.join('')}</ul></div>`);
  121. }
  122.  
  123. static init() {
  124. this.injectUrls2Dom(this.getUrlInfo());
  125. }
  126. }
  127.  
  128. window.VideoParsing = VideoParsing;
  129. })();