Skip to content

Commit ee01cb7

Browse files
committed
refactor: 优化代码,来自[纯粹乐趣 – Pornhub 视频下载器](https://greasyfork.org/zh-CN/scripts/551131)
1 parent 42c142f commit ee01cb7

File tree

2 files changed

+121
-88
lines changed

2 files changed

+121
-88
lines changed

pornhub-download/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# **🛠️ Pornhub 视频一键下载 更新日志**
22

3+
### **📅 2026.3.31.1**
4+
5+
**优化**: 优化代码,来自[纯粹乐趣 – Pornhub 视频下载器](https://greasyfork.org/zh-CN/scripts/551131)
6+
7+
---
8+
39
### **📅 2025.05.01.0128**
410

511
**修复**: 删除掉下载视频时,文件名尾随空格[#296954](https://greasyfork.org/scripts/528800/discussions/296954)

pornhub-download/pornhub-download.user.js

Lines changed: 115 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,7 @@
8686
// @match *://*.pornhub.com/view_video.php?viewkey=*
8787
// @match *://*.pornhubpremium.com/view_video.php?viewkey=*
8888
// @require https://update.greasyfork.org/scripts/498897/1404834/Toastnew.js
89-
// @require https://code.jquery.com/jquery-3.7.1.min.js
90-
// @author liuwanlin,heckles,人民的勤务员 <china.qinwuyuan@gmail.com>
89+
// @author liuwanlin,heckles,MatthewXY,人民的勤务员 <china.qinwuyuan@gmail.com>
9190
// @namespace https://github.com/ChinaGodMan/UserScripts
9291
// @supportURL https://github.com/ChinaGodMan/UserScripts/issues
9392
// @homepageURL https://github.com/ChinaGodMan/UserScripts
@@ -101,23 +100,16 @@
101100
// @compatible opera
102101
// @compatible safari
103102
// @compatible kiwi
104-
// @version 2025.05.01.0128
103+
// @version 2026.3.31.1
105104
// @created 2025-03-05 01:45:13
106105
// @modified 2025-03-05 01:45:13
107106
// ==/UserScript==
108107

109108
//!人民的勤务员修改自以下脚本 感谢heckles和liuwanlin
110109
/*https://greasyfork.org/zh-CN/scripts/491333
111110
https://greasyfork.org/zh-CN/scripts/491329
111+
https://greasyfork.org/zh-CN/scripts/551131
112112
*/
113-
GM_addStyle(`
114-
.download-urls ul { padding: 10px; font-weight: bold; line-height: 1.5; }
115-
.download-urls ul li { display: flex; align-items: center; height: 20px; max-width:400px; }
116-
.download-url-label { /* width: 100px; */ text-align: right; }
117-
.download-url-copy { flex: 1; }
118-
.download-url-mp4 { flex: 1; }
119-
.download-url-input { flex: 3; font-size: 12px; padding: 0 5px; border: 1px solid #ffff; margin: 0 5px; }
120-
`);
121113

122114
(function () {
123115
'use strict'
@@ -131,9 +123,9 @@ GM_addStyle(`
131123
downloaderror: 'Error downloading video, please check the console for details',
132124
downloadfailed: 'Download failed',
133125
downloadfailed_nosize: 'Unable to retrieve file size',
134-
copydownloadbtn: 'Copy address',
126+
copydownloadbtn: 'Copy',
135127
copysuccess: 'Copy successful',
136-
downloadbtn: 'Download video',
128+
downloadbtn: 'Download',
137129
linkTip: 'Video download URL:'
138130
},
139131
'zh-CN,zh,zh-SG': {
@@ -144,9 +136,9 @@ GM_addStyle(`
144136
downloaderror: '下载视频时出错,请到控制台查看详细信息',
145137
downloadfailed: '下载失败',
146138
downloadfailed_nosize: '无法获取文件大小',
147-
copydownloadbtn: '复制地址',
139+
copydownloadbtn: '复制',
148140
copysuccess: '复制成功',
149-
downloadbtn: '下载视频',
141+
downloadbtn: '下载',
150142
linkTip: '视频下载地址:'
151143
},
152144
'zh-TW,zh-HK,zh-MO': {
@@ -157,9 +149,9 @@ GM_addStyle(`
157149
downloaderror: '下載視頻時出錯,請到控制台查看詳細信息',
158150
downloadfailed: '下載失敗',
159151
downloadfailed_nosize: '無法獲取文件大小',
160-
copydownloadbtn: '複製地址',
152+
copydownloadbtn: '複製',
161153
copysuccess: '複製成功',
162-
downloadbtn: '下載視頻',
154+
downloadbtn: '下載',
163155
linkTip: '視頻下載地址:'
164156
},
165157
'ja': {
@@ -246,30 +238,22 @@ GM_addStyle(`
246238
unsafeWindow.VideoParsing.init()
247239
}, 200)
248240
})
249-
//PC和非PC,注意判断条件里不能用$简写,不知为问什么
250-
let playerdiv//let可以先不赋值,用在这里
251-
if (document.querySelector('#player')) {
252-
playerdiv = document.querySelector('#player')
253-
}
254-
else {
255-
console.log('安卓')
256-
playerdiv = document.querySelector('.playerWrapper')
257-
}
258-
const playerDom = playerdiv
259-
//
260-
261-
if (playerDom) {
262-
mutationObserver.observe(playerDom, {
263-
childList: true,
264-
subtree: true
265-
})
266-
} else {
267-
Toast(translate('finderror'), 3000, 'rgb(219, 18, 35)', '#ffffff', 'top')
268-
}
269-
})();
270241

271-
(function () {
272242
class VideoParsing {
243+
static addStyle() {
244+
GM_addStyle(`
245+
.download-urls { margin: 15px 0px; padding: 12px; background: #000; border: 1px solid #6f6f6f; border-radius: 5px; font-size: 14px; max-width: 600px; }
246+
.download-urls h3 { margin-bottom: 8px; font-size: 16px; font-weight: bold; color: #333; }
247+
.download-urls ul { padding: 0; margin: 0; list-style: none; }
248+
.download-urls ul li { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
249+
.download-url-label { flex: 0 0 90px; font-weight: bold; color: #FFF; }
250+
.download-url-input { flex: 1; font-size: 12px; padding: 3px 6px; border: 1px solid #ccc; border-radius: 5px; background: #fff; color: #000; }
251+
.download-url-copy, .download-url-mp4 { padding: 4px 10px; border-radius: 5px; border: none; cursor: pointer; font-size: 12px; }
252+
.download-url-copy { background: #eee; color: #333; }
253+
.download-url-mp4 { background: #ff9000; color: #fff; }
254+
.download-url-copy:hover { background: #ddd; }
255+
`)
256+
}
273257
// 根据 key 开头字母获取对象中的值,返回数组
274258
static getObjectValueByStartsWithChar(obj, char) {
275259
const vars = []
@@ -289,17 +273,18 @@ GM_addStyle(`
289273
const flashvars = this.getObjectValueByStartsWithChar(unsafeWindow, 'flashvars_')
290274
if (!flashvars.length) {
291275
Toast(translate('fetcherror'), 3000, 'rgb(219, 18, 35)', '#ffffff', 'top')
276+
console.warn(translate.finderror)
292277
return
293278
}
294279
let videosInfo = []
295280
try {
296281
videosInfo = flashvars[0]['value']['mediaDefinitions']
297282
} catch (e) {
298283
Toast(translate('fetcherror'), 3000, 'rgb(219, 18, 35)', '#ffffff', 'top')
299-
console.error(translate('fetcherror'), e, flashvars)
284+
console.error(translate.fetcherror, e)
300285
return
301286
}
302-
let remoteAddress = undefined
287+
let remoteAddress
303288
let urlInfo = []
304289
for (let i = 0; i < videosInfo.length; i++) {
305290
if (videosInfo[i]['remote']) {
@@ -308,59 +293,103 @@ GM_addStyle(`
308293
}
309294
}
310295

311-
// MP4 信息
312296
if (remoteAddress) {
313-
$.ajax({
314-
url: remoteAddress,
315-
async: false,
316-
success: (data) => {
317-
if (data && data.length) {
318-
urlInfo = urlInfo.concat(data.map(item => ({
319-
quality: item.quality + '.' + item.format,
320-
url: item.videoUrl
321-
})))
297+
const xhr = new XMLHttpRequest()
298+
xhr.open('GET', remoteAddress, false)
299+
xhr.onload = function () {
300+
if (xhr.status === 200) {
301+
try {
302+
const data = JSON.parse(xhr.responseText)
303+
if (Array.isArray(data)) {
304+
urlInfo = urlInfo.concat(data.map(item => ({
305+
quality: item.quality + '.' + item.format,
306+
url: item.videoUrl
307+
})))
308+
}
309+
} catch (err) {
310+
console.error(err)
322311
}
323312
}
324-
})
313+
}
314+
xhr.send()
325315
}
326-
console.log(videosInfo)
327316
return urlInfo
328317
}
329318

330319
// 注入到下载面板
331320
static injectUrls2Dom(urlInfo) {
332-
const li = []
333-
urlInfo.forEach(item => {
334-
li.push(`
335-
<li>
336-
<span class="download-url-label">[ ${item.quality} ]</span>
337-
<input class="download-url-input" value="${item.url}" style="width: 50px;" />
338-
<a target="_blank" class="download-url-copy" data-href="${item.url}" href="javascript: void(0);">${translate('copydownloadbtn')}</a>
339-
<a target="_blank" class="download-url-mp4" data-href="${item.url}" href="javascript: void(0);">${translate('downloadbtn')}</a>
340-
</li>
341-
`)
342-
})
343-
//pc和非PC两种情况都加上
344-
$('.playerWrapper').after(`<div class="download-urls"><h3>${translate('linkTip')}</h3><ul>${li.join('')}</ul></div>`)
345-
$('#player').after(`<div class="download-urls"><h3>${translate('linkTip')}</h3><ul>${li.join('')}</ul></div>`)
321+
const container = document.createElement('div')
322+
container.className = 'download-urls'
323+
324+
const title = document.createElement('h3')
325+
title.textContent = translate.linkTip
326+
container.appendChild(title)
327+
328+
if (urlInfo && urlInfo.length > 0) {
329+
const ul = document.createElement('ul')
330+
urlInfo.forEach(item => {
331+
const li = document.createElement('li')
332+
333+
const label = document.createElement('span')
334+
label.className = 'download-url-label'
335+
label.textContent = `[ ${item.quality} ]`
336+
337+
const input = document.createElement('input')
338+
input.className = 'download-url-input'
339+
input.value = item.url
340+
input.readOnly = true
341+
342+
const copyBtn = document.createElement('button')
343+
copyBtn.className = 'download-url-copy'
344+
copyBtn.textContent = translate.copydownloadbtn
345+
copyBtn.dataset.href = item.url
346+
347+
const dlBtn = document.createElement('button')
348+
dlBtn.className = 'download-url-mp4'
349+
dlBtn.textContent = translate.downloadbtn
350+
dlBtn.dataset.href = item.url
351+
352+
li.appendChild(label)
353+
li.appendChild(input)
354+
li.appendChild(copyBtn)
355+
li.appendChild(dlBtn)
356+
ul.appendChild(li)
357+
})
358+
container.appendChild(ul)
359+
}
360+
361+
const player = document.querySelector('#player')
362+
if (player) {
363+
player.insertAdjacentElement('afterend', container)
364+
}
365+
366+
const playerWrapper = document.querySelector('.playerWrapper')
367+
if (playerWrapper) {
368+
playerWrapper.insertAdjacentElement('afterend', container)
369+
}
346370
}
347371

348372
// 初始化事件
349373
static initEvens() {
350-
// 点击下载复制到粘贴板中
351-
$(document).on('click', '.download-url-copy', function (e) {
352-
e.preventDefault()
353-
GM_setClipboard($(this).data('href'))
354-
Toast(translate('copysuccess'), 3000, 'rgb(18, 219, 18)', '#ffffff', 'top')
374+
document.addEventListener('click', function (e) {
375+
if (e.target.classList.contains('download-url-copy')) {
376+
e.preventDefault()
377+
const url = e.target.dataset.href
378+
GM_setClipboard(url)
379+
Toast(translate.copysuccess, 3000, 'rgb(18, 219, 18)', '#ffffff', 'top')
380+
}
355381
})
356382
}
357383
static initDownEvens() {
358-
$(document).on('click', '.download-url-mp4', function (e) {
359-
e.preventDefault()
360-
downloadMp4($(this).data('href'), $(this))
384+
document.addEventListener('click', function (e) {
385+
if (e.target.classList.contains('download-url-mp4')) {
386+
e.preventDefault()
387+
downloadMp4(e.target.dataset.href, e.target)
388+
}
361389
})
362390
}
363391
static init() {
392+
this.addStyle()
364393
this.injectUrls2Dom(this.getUrlInfo())
365394
this.initEvens()
366395
this.initDownEvens()
@@ -379,47 +408,44 @@ GM_addStyle(`
379408
function sanitizeTitle() {
380409
var title = document.title
381410
title = title.replace(/- Pornhub\.com/, '')
382-
return title.replace(/[/:*?"<>|]/g, '_')
411+
return title.replace(/[/:*?"<>|]/g, '_').trim()
383412
}
384413

385-
386414
//下载函数
387-
async function downloadMp4(videoUrl, targetElement) {
415+
async function downloadMp4(videoUrl, element) {
388416
try {
389417
const response = await fetch(videoUrl)
390418
if (!response.ok) {
391-
$(targetElement).text(translate('downloadfailed'))
419+
element.textContent = translate('downloadfailed')
392420
}
393421

394422
const contentLength = response.headers.get('Content-Length')
395423
if (!contentLength) {
396-
$(targetElement).text(translate('downloadfailed_nosize'))
397-
424+
element.textContent = translate('downloadfailed_nosize')
398425
return
399426
}
400427
const reader = response.body.getReader()
401-
const totalSize = contentLength ? parseInt(contentLength, 10) : 0 // 文件总大小
402-
let downloadedSize = 0 // 已下载大小
403-
const chunks = [] // 存储数据块
428+
const totalSize = contentLength ? parseInt(contentLength, 10) : 0
429+
let downloadedSize = 0
430+
const chunks = []
404431
while (true) {
405432
const { done, value } = await reader.read()
406433
if (done) break
407-
// 更新下载大小
408434
downloadedSize += value.length
409435
chunks.push(value)
410436
if (totalSize) {
411437
const progress = ((downloadedSize / totalSize) * 100).toFixed(2)
412-
$(targetElement).text(`${translate('downloading')} ${progress}% (${getHumanReadableSize(downloadedSize)} / ${getHumanReadableSize(totalSize)})`)
438+
element.textContent = `${translate('downloading')} ${progress}% (${getHumanReadableSize(downloadedSize)} / ${getHumanReadableSize(totalSize)})`
413439
} else {
414-
$(targetElement).text(`${translate('downloading')} ${getHumanReadableSize(downloadedSize)}`)
440+
element.textContent = `${translate('downloading')} ${getHumanReadableSize(downloadedSize)}`
415441
}
416442
}
417443
const blob = new Blob(chunks)
418444
const url = window.URL.createObjectURL(blob)
419445
const a = document.createElement('a')
420446
a.style.display = 'none'
421447
a.href = url
422-
a.download = sanitizeTitle().trim() + '.mp4'
448+
a.download = sanitizeTitle() + '.mp4'
423449
document.body.appendChild(a)
424450
a.click()
425451
window.URL.revokeObjectURL(url)
@@ -430,4 +456,5 @@ GM_addStyle(`
430456
console.error(translate('downloaderror'), error)
431457
}
432458
}
459+
VideoParsing.init()
433460
})()

0 commit comments

Comments
 (0)