From 713353b5c780a8b52bfa5386a65d65664311ca6d Mon Sep 17 00:00:00 2001 From: hoothin Date: Wed, 6 May 2026 10:04:33 +0900 Subject: [PATCH 01/14] Update BingBgForBaidu.user.js --- BingBgForBaidu/BingBgForBaidu.user.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/BingBgForBaidu/BingBgForBaidu.user.js b/BingBgForBaidu/BingBgForBaidu.user.js index 6c86b1050dd..ba0fa832396 100644 --- a/BingBgForBaidu/BingBgForBaidu.user.js +++ b/BingBgForBaidu/BingBgForBaidu.user.js @@ -2,7 +2,7 @@ // @name 百Bing图 // @name:en BingBgForBaidu // @namespace hoothin -// @version 2.3.44 +// @version 2.3.45 // @description 给百度首页换上Bing的背景图,并添加背景图链接与日历组件 // @description:en Just change the background image of baidu.com to bing.com // @author hoothin @@ -124,7 +124,10 @@ } }; var skinContainer=document.getElementsByTagName("body")[0]; - GM_addStyle(".s-news-rank-content{max-height: 180px; width: 99%; overflow-y: auto; overflow-x: hidden;}.s-top-right .ai-entry-right-nologin,.s-top-right .operate-wrapper-nologin{right:362px;}.hot-refresh{padding-bottom:7px;}.hot-title>div,.hot-refresh{border-radius: 3px 3px 0 0}.s-hotsearch-title>a,.s-hotsearch-title>a>div{padding: 5px;background-color: #f0f8ff95;border-radius: 5px;}.s-hotsearch-content{position: absolute; background-color: #f0f8ff95; border-radius: 5px;padding: 5px;}.s_ipt{margin:0!important;}.s_ipt_wr{border-radius: 10px 4px 4px 10px;border-radius: 10px 0 0 10px;background: #fff!important;}#qrcodeCon{display:none}body{position:fixed;_position:absolute;top:0;left:0;height:100%;width:100%;min-width:1000px;z-index:-10;background-position:center 0;background-repeat:no-repeat;background-size:cover;-webkit-background-size:cover;-o-background-size:cover;zoom:1;}"); + if (!document.querySelector(".aigc-skin-bg,#s_mancard_main")) { + GM_addStyle(".s-news-rank-content{max-height: 180px; width: 99%; overflow-y: auto; overflow-x: hidden;}.s-top-right .ai-entry-right-nologin,.s-top-right .operate-wrapper-nologin{right:362px;}.hot-refresh{padding-bottom:7px;}.hot-title>div,.hot-refresh{border-radius: 3px 3px 0 0}.s-hotsearch-title>a,.s-hotsearch-title>a>div{padding: 5px;background-color: #f0f8ff95;border-radius: 5px;}.s-hotsearch-content{position: absolute; background-color: #f0f8ff95; border-radius: 5px;padding: 5px;}"); + } + GM_addStyle(".s_ipt{margin:0!important;}.s_ipt_wr{border-radius: 10px 4px 4px 10px;border-radius: 10px 0 0 10px;background: #fff!important;}#qrcodeCon{display:none}body{position:fixed;_position:absolute;top:0;left:0;height:100%;width:100%;min-width:1000px;z-index:-10;background-position:center 0;background-repeat:no-repeat;background-size:cover;-webkit-background-size:cover;-o-background-size:cover;zoom:1;}"); var inputsu=document.querySelector("input#su"); var clickHandler=e=>{ if(skinContainer)skinContainer.style.backgroundImage=""; From 66fbf83c7d6fb28dda07be3eae0111fffb02cb78 Mon Sep 17 00:00:00 2001 From: Vieller Date: Fri, 22 May 2026 07:48:28 +0200 Subject: [PATCH 02/14] Update pagetualRules.json Added xhamster main site and mirror sites rules. --- Pagetual/pagetualRules.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index f72854a3737..1f9005bf3d9 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6487,5 +6487,14 @@ "replaceElement": "div.product-card", "pageElement": "div.products-catalog__list", "action": 2 -} +}, +{ + "name": "xHamster", + "url": "^https://([\\w]+\\.)?(xhamster|xhaccess|xhamster19)\\.(com|desi)/", + "pageElement": "//div[contains(@class, 'thumb-list__item') and not(contains(@class, 'loading'))]", + "nextLink": "//a[@data-page='next' or @rel='next']", + "action": 0, + "pageInit": "if (!window._pagetualMasterTemplate) { let masterElem = document.querySelector('.thumb-list__item'); if (masterElem) window._pagetualMasterTemplate = masterElem.innerHTML; } let template = document.querySelector('.thumb-list__item'); let inner = window._pagetualMasterTemplate || (template ? template.innerHTML : ''); if (!inner) return; let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch(e) { return; } function find(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null; if (obj.videoThumbProps?.length) return obj.videoThumbProps; for (let k in obj) if (obj.hasOwnProperty(k)) { let r = find(obj[k], depth+1); if (r) return r; } return null; } let props = find(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s/3600), m = Math.floor((s%3600)/60), sec = s%60; if (h) return h+':'+(m<10?'0'+m:m)+':'+(sec<10?'0'+sec:sec); return m+':'+(sec<10?'0'+sec:sec); } function formatViews(v) { if (v>=1e6) return Math.floor(v/1e6)+'M'; if (v>=1e3) return Math.floor(v/1e3)+'K'; return v.toString(); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] .tiny-8643e'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let uhd = div.querySelector('.xh-icon'); if (uhd && !data.isUHD) uhd.style.display = 'none'; let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; if (data.isWatched) { let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); w.innerHTML = '
Watched
'; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", + "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); });" + } ] From f084d7e6a75548d6287802cbe7da3ae4d16b854e Mon Sep 17 00:00:00 2001 From: hoothin-update Date: Fri, 22 May 2026 05:51:06 +0000 Subject: [PATCH 03/14] Update version of Pagetual rules to 106 --- Pagetual/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pagetual/version b/Pagetual/version index f96ac067218..fe4afb0df86 100644 --- a/Pagetual/version +++ b/Pagetual/version @@ -1 +1 @@ -105 +106 From 35de1658cf920551d2b01b24d6d6dc310132545c Mon Sep 17 00:00:00 2001 From: Vieller Date: Fri, 22 May 2026 12:34:09 +0200 Subject: [PATCH 04/14] Update pagetualRules.json xHamster Rule Update: - UI polish: fixed view count formatting when the first decimal digit is 0. - Prevented conflicts with obfuscated class names (e.g. tiny-XXX, tiny-bold-XXX) on the video-duration element. - Set onVideo element to z-index: 20 so it displays above the trailer. --- Pagetual/pagetualRules.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index 1f9005bf3d9..d2c03398f5a 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6494,7 +6494,7 @@ "pageElement": "//div[contains(@class, 'thumb-list__item') and not(contains(@class, 'loading'))]", "nextLink": "//a[@data-page='next' or @rel='next']", "action": 0, - "pageInit": "if (!window._pagetualMasterTemplate) { let masterElem = document.querySelector('.thumb-list__item'); if (masterElem) window._pagetualMasterTemplate = masterElem.innerHTML; } let template = document.querySelector('.thumb-list__item'); let inner = window._pagetualMasterTemplate || (template ? template.innerHTML : ''); if (!inner) return; let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch(e) { return; } function find(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null; if (obj.videoThumbProps?.length) return obj.videoThumbProps; for (let k in obj) if (obj.hasOwnProperty(k)) { let r = find(obj[k], depth+1); if (r) return r; } return null; } let props = find(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s/3600), m = Math.floor((s%3600)/60), sec = s%60; if (h) return h+':'+(m<10?'0'+m:m)+':'+(sec<10?'0'+sec:sec); return m+':'+(sec<10?'0'+sec:sec); } function formatViews(v) { if (v>=1e6) return Math.floor(v/1e6)+'M'; if (v>=1e3) return Math.floor(v/1e3)+'K'; return v.toString(); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] .tiny-8643e'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let uhd = div.querySelector('.xh-icon'); if (uhd && !data.isUHD) uhd.style.display = 'none'; let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; if (data.isWatched) { let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); w.innerHTML = '
Watched
'; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", + "pageInit": "let candidates = Array.from(document.querySelectorAll('.thumb-list__item')); let bestCandidate = candidates.find(c => c.querySelector('[data-role=\"video-duration\"]')); if (!bestCandidate && candidates.length) bestCandidate = candidates[0]; if (!window._pagetualMasterTemplate) { if (bestCandidate) { window._pagetualMasterTemplate = bestCandidate.innerHTML; let durationSpan = bestCandidate.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) { let tinyClass = Array.from(durationSpan.classList).find(c => c.startsWith('tiny-')); if (tinyClass) { let suffix = tinyClass.split('-').pop(); if (suffix) window._pagetualSuffix = suffix; } } } } let inner = window._pagetualMasterTemplate || (bestCandidate ? bestCandidate.innerHTML : ''); if (!inner) return; if (!window._pagetualSuffix) window._pagetualSuffix = '8643e'; let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch (e) { return; } function find(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null; if (obj.videoThumbProps?.length) return obj.videoThumbProps; for (let k in obj) if (obj.hasOwnProperty(k)) { let r = find(obj[k], depth + 1); if (r) return r; } return null; } let props = find(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec); } function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; } function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString(); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let uhd = div.querySelector('.xh-icon'); if (uhd && !data.isUHD) uhd.style.display = 'none'; let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); });" } ] From 72034bfa4dced1dab167420bca604fc1db3b94bb Mon Sep 17 00:00:00 2001 From: Vieller Date: Fri, 22 May 2026 14:51:52 +0200 Subject: [PATCH 05/14] Update pagetualRules.json Added "author" line to xHamster rule --- Pagetual/pagetualRules.json | 1 + 1 file changed, 1 insertion(+) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index d2c03398f5a..058745a652f 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6491,6 +6491,7 @@ { "name": "xHamster", "url": "^https://([\\w]+\\.)?(xhamster|xhaccess|xhamster19)\\.(com|desi)/", + "author": "Vieller", "pageElement": "//div[contains(@class, 'thumb-list__item') and not(contains(@class, 'loading'))]", "nextLink": "//a[@data-page='next' or @rel='next']", "action": 0, From 048259e2674805df18667c196038ac1560088eb8 Mon Sep 17 00:00:00 2001 From: hoothin-update Date: Fri, 22 May 2026 12:53:13 +0000 Subject: [PATCH 06/14] Update version of Pagetual rules to 107 --- Pagetual/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pagetual/version b/Pagetual/version index fe4afb0df86..e34885bbc6e 100644 --- a/Pagetual/version +++ b/Pagetual/version @@ -1 +1 @@ -106 +107 From 2d42e4034c2891e049a36401ab7ec456e6118fe0 Mon Sep 17 00:00:00 2001 From: Vieller Date: Sat, 23 May 2026 19:48:16 +0200 Subject: [PATCH 07/14] Update pagetualRules.json (xHamster - Photo hydration) xHamster: Photo gallery hydration and bug fixes - Implemented photo gallery support: distinct logic for standard gallery pages, search results, and user profile. - Enhanced pageElement to improve UX (filters out mixed photo/video content). - Recursive search for video data (findVideoProps) to work across different sections of the site - Fixed bug: video master template now strips badges, guaranteeing a pristine structure. --- Pagetual/pagetualRules.json | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index 058745a652f..e7cc1a01fa3 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6489,13 +6489,14 @@ "action": 2 }, { - "name": "xHamster", - "url": "^https://([\\w]+\\.)?(xhamster|xhaccess|xhamster19)\\.(com|desi)/", - "author": "Vieller", - "pageElement": "//div[contains(@class, 'thumb-list__item') and not(contains(@class, 'loading'))]", - "nextLink": "//a[@data-page='next' or @rel='next']", - "action": 0, - "pageInit": "let candidates = Array.from(document.querySelectorAll('.thumb-list__item')); let bestCandidate = candidates.find(c => c.querySelector('[data-role=\"video-duration\"]')); if (!bestCandidate && candidates.length) bestCandidate = candidates[0]; if (!window._pagetualMasterTemplate) { if (bestCandidate) { window._pagetualMasterTemplate = bestCandidate.innerHTML; let durationSpan = bestCandidate.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) { let tinyClass = Array.from(durationSpan.classList).find(c => c.startsWith('tiny-')); if (tinyClass) { let suffix = tinyClass.split('-').pop(); if (suffix) window._pagetualSuffix = suffix; } } } } let inner = window._pagetualMasterTemplate || (bestCandidate ? bestCandidate.innerHTML : ''); if (!inner) return; if (!window._pagetualSuffix) window._pagetualSuffix = '8643e'; let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch (e) { return; } function find(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object' || Array.isArray(obj)) return null; if (obj.videoThumbProps?.length) return obj.videoThumbProps; for (let k in obj) if (obj.hasOwnProperty(k)) { let r = find(obj[k], depth + 1); if (r) return r; } return null; } let props = find(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec); } function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; } function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString(); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let uhd = div.querySelector('.xh-icon'); if (uhd && !data.isUHD) uhd.style.display = 'none'; let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", - "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); });" - } + "name": "xHamster", + "url": "^https://([\\w]+\\.)?(xhamster|xhaccess|xhamster19)\\.(com|desi)/", + "author": "Vieller", + "pageElement": "div[data-ecommerce-list-name=\"default\"] div[class*=\"thumb-list__item\"]:not([class*=\"loading\"]), div[class*=\"galleryList\"] > div[class*=\"container\"] > div[class*=\"wrapper\"], div[class*=\"content\"] div[class*=\"wrapper-\"], div[class*=\"content\"] div[class*=\"default\"], [class*=\"photosList\"] > div[style]", + "nextLink": "a[data-page='next'], a[rel='next']", + "action": 0, + "init": "let candidates = Array.from(document.querySelectorAll('.thumb-list__item')); let bestCandidate = candidates.find(c => c.querySelector('[data-role=\"video-duration\"]')); if (!bestCandidate && candidates.length) bestCandidate = candidates[0]; if (!window._pagetualMasterTemplateVideo) { if (bestCandidate) { let clone = bestCandidate.cloneNode(true); let badgeElements = clone.querySelectorAll('[data-role=\"video-watched\"], [data-brand=\"full video\"]'); badgeElements.forEach(badge => badge.remove()); let xhIcons = clone.querySelectorAll('.xh-icon'); xhIcons.forEach(icon => icon.remove()); window._pagetualMasterTemplateVideo = clone.innerHTML; let durationSpan = clone.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) { let tinyClass = Array.from(durationSpan.classList).find(c => c.startsWith('tiny-')); if (tinyClass) { let suffix = tinyClass.split('-').pop(); if (suffix) window._pagetualSuffix = suffix; } } } } if (!window._pagetualMasterGallery) { let galleryCandidates = Array.from(document.querySelectorAll('[class*=\"container-\"] > [class*=\"wrapper\"]')); if (!galleryCandidates.length) galleryCandidates = Array.from(document.querySelectorAll('div[class*=\"wrapper\"]')).filter(el => el.querySelector('[class*=\"author-\"]')); let bestGallery = galleryCandidates.find(g => g.querySelector('[class*=\"author-\"]')); if (!bestGallery && galleryCandidates.length) bestGallery = galleryCandidates[0]; if (bestGallery) { let clone = bestGallery.cloneNode(true); window._pagetualMasterGallery = clone.innerHTML; let captionSpan = clone.querySelector('[class*=\"caption-\"]'); if (captionSpan) { let captionClass = Array.from(captionSpan.classList).find(c => c.startsWith('caption-')); if (captionClass) window._pagetualCaptionSuffix = captionClass.split('-').pop(); } let bodySpan = clone.querySelector('[class*=\"body-bold-\"]'); if (bodySpan) { let bodyClass = Array.from(bodySpan.classList).find(c => c.startsWith('body-bold-')); if (bodyClass) window._pagetualBodySuffix = bodyClass.split('-').pop(); } } } if (!window._pagetualSuffix) window._pagetualSuffix = '8643e'; if (!window._pagetualCaptionSuffix) window._pagetualCaptionSuffix = '8643e'; if (!window._pagetualBodySuffix) window._pagetualBodySuffix = '8643e';", + "pageInit": "/* Extract data from window.initials and handle different page types */ let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch (e) { return; } /* Photo galleries main page – remove skeleton overlays only */ if (initials.photosPage !== undefined || initials.galleryPage !== undefined) { for (let ele of eles) { let skeleton = ele.querySelector('a[class*=\"cover\"] > div[class*=\"container-\"][class*=\"primaryColor-\"]'); if (skeleton && skeleton.querySelector('span[class*=\"dot\"]')) { skeleton.remove(); } } return; } function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; } function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString(); } /* Photo gallery search results – full hydration using gallery template */ if (initials.searchResultsPhotoComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.searchResultsPhotoComponent.list; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let authorContainer = div.querySelector('[class*=\"author-\"]'); if (authorContainer && data.author) { authorContainer.href = data.author.link; let nameSpan = authorContainer.querySelector('[class*=\"name-\"]'); if (nameSpan) { nameSpan.textContent = data.author.name; } } let avatarImg = div.querySelector('[class*=\"avatar-\"] img'); if (avatarImg && data.author && data.author.img) { avatarImg.src = data.author.img; avatarImg.alt = data.author.name; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* User profile photo gallery – full hydration */ if (initials.contentComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.contentComponent.items; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* Video pages – full hydration using video template */ let inner = window._pagetualMasterTemplateVideo; if (!inner) return; function findVideoProps(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object') return null; if (Array.isArray(obj) && obj.length > 0) { let first = obj[0]; if (first && typeof first === 'object' && 'id' in first && 'duration' in first && 'title' in first && 'pageURL' in first && 'views' in first) { return obj; } } for (let k in obj) if (obj.hasOwnProperty(k)) { let r = findVideoProps(obj[k], depth + 1); if (r) return r; } return null; } let props = findVideoProps(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", + "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); }); if (typeof window._pagetualPageCounter === 'undefined') { window._pagetualPageCounter = 1; let pagetualDebug = document.createElement('div'); pagetualDebug.id = 'pagetual-debug'; pagetualDebug.style.cssText = 'position: fixed; bottom: 10px; right: 10px; background: rgba(0,0,0,0.8); color: #0f0; font-family: monospace; font-size: 12px; padding: 3px 4px; border-radius: 5px; z-index: 99999; display: block !important; transform: scale(0.8); transform-origin: bottom right;'; document.body.appendChild(pagetualDebug); } else { window._pagetualPageCounter++; } let debugDiv = document.getElementById('pagetual-debug'); if (debugDiv) debugDiv.textContent = 'P ' + window._pagetualPageCounter; setTimeout(() => { let allThumbs = document.querySelectorAll('.thumb-list__item:not(.loading)'); let hasVisible = Array.from(allThumbs).some(ele => { let style = window.getComputedStyle(ele); return style.display !== 'none' && style.visibility !== 'hidden' && ele.offsetParent !== null; }); if (!hasVisible && !window._pagetualAutoScrollTriggered) { window._pagetualAutoScrollTriggered = true; setTimeout(() => { window.scrollBy(0, 1); setTimeout(() => { window.scrollBy(0, -1); setTimeout(() => { window._pagetualAutoScrollTriggered = false; }, 200); }, 200); }, 50); } }, 500);" +} ] From 443bb2edbf9dd69db9d0ce5397b248588e79b8d9 Mon Sep 17 00:00:00 2001 From: Vieller Date: Sat, 23 May 2026 19:55:32 +0200 Subject: [PATCH 08/14] Update pagetualRules.json Removed debug code in pageAction Ready to commit --- Pagetual/pagetualRules.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index e7cc1a01fa3..6b1b76a4ac2 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6497,6 +6497,6 @@ "action": 0, "init": "let candidates = Array.from(document.querySelectorAll('.thumb-list__item')); let bestCandidate = candidates.find(c => c.querySelector('[data-role=\"video-duration\"]')); if (!bestCandidate && candidates.length) bestCandidate = candidates[0]; if (!window._pagetualMasterTemplateVideo) { if (bestCandidate) { let clone = bestCandidate.cloneNode(true); let badgeElements = clone.querySelectorAll('[data-role=\"video-watched\"], [data-brand=\"full video\"]'); badgeElements.forEach(badge => badge.remove()); let xhIcons = clone.querySelectorAll('.xh-icon'); xhIcons.forEach(icon => icon.remove()); window._pagetualMasterTemplateVideo = clone.innerHTML; let durationSpan = clone.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) { let tinyClass = Array.from(durationSpan.classList).find(c => c.startsWith('tiny-')); if (tinyClass) { let suffix = tinyClass.split('-').pop(); if (suffix) window._pagetualSuffix = suffix; } } } } if (!window._pagetualMasterGallery) { let galleryCandidates = Array.from(document.querySelectorAll('[class*=\"container-\"] > [class*=\"wrapper\"]')); if (!galleryCandidates.length) galleryCandidates = Array.from(document.querySelectorAll('div[class*=\"wrapper\"]')).filter(el => el.querySelector('[class*=\"author-\"]')); let bestGallery = galleryCandidates.find(g => g.querySelector('[class*=\"author-\"]')); if (!bestGallery && galleryCandidates.length) bestGallery = galleryCandidates[0]; if (bestGallery) { let clone = bestGallery.cloneNode(true); window._pagetualMasterGallery = clone.innerHTML; let captionSpan = clone.querySelector('[class*=\"caption-\"]'); if (captionSpan) { let captionClass = Array.from(captionSpan.classList).find(c => c.startsWith('caption-')); if (captionClass) window._pagetualCaptionSuffix = captionClass.split('-').pop(); } let bodySpan = clone.querySelector('[class*=\"body-bold-\"]'); if (bodySpan) { let bodyClass = Array.from(bodySpan.classList).find(c => c.startsWith('body-bold-')); if (bodyClass) window._pagetualBodySuffix = bodyClass.split('-').pop(); } } } if (!window._pagetualSuffix) window._pagetualSuffix = '8643e'; if (!window._pagetualCaptionSuffix) window._pagetualCaptionSuffix = '8643e'; if (!window._pagetualBodySuffix) window._pagetualBodySuffix = '8643e';", "pageInit": "/* Extract data from window.initials and handle different page types */ let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch (e) { return; } /* Photo galleries main page – remove skeleton overlays only */ if (initials.photosPage !== undefined || initials.galleryPage !== undefined) { for (let ele of eles) { let skeleton = ele.querySelector('a[class*=\"cover\"] > div[class*=\"container-\"][class*=\"primaryColor-\"]'); if (skeleton && skeleton.querySelector('span[class*=\"dot\"]')) { skeleton.remove(); } } return; } function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; } function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString(); } /* Photo gallery search results – full hydration using gallery template */ if (initials.searchResultsPhotoComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.searchResultsPhotoComponent.list; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let authorContainer = div.querySelector('[class*=\"author-\"]'); if (authorContainer && data.author) { authorContainer.href = data.author.link; let nameSpan = authorContainer.querySelector('[class*=\"name-\"]'); if (nameSpan) { nameSpan.textContent = data.author.name; } } let avatarImg = div.querySelector('[class*=\"avatar-\"] img'); if (avatarImg && data.author && data.author.img) { avatarImg.src = data.author.img; avatarImg.alt = data.author.name; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* User profile photo gallery – full hydration */ if (initials.contentComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.contentComponent.items; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* Video pages – full hydration using video template */ let inner = window._pagetualMasterTemplateVideo; if (!inner) return; function findVideoProps(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object') return null; if (Array.isArray(obj) && obj.length > 0) { let first = obj[0]; if (first && typeof first === 'object' && 'id' in first && 'duration' in first && 'title' in first && 'pageURL' in first && 'views' in first) { return obj; } } for (let k in obj) if (obj.hasOwnProperty(k)) { let r = findVideoProps(obj[k], depth + 1); if (r) return r; } return null; } let props = findVideoProps(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", - "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); }); if (typeof window._pagetualPageCounter === 'undefined') { window._pagetualPageCounter = 1; let pagetualDebug = document.createElement('div'); pagetualDebug.id = 'pagetual-debug'; pagetualDebug.style.cssText = 'position: fixed; bottom: 10px; right: 10px; background: rgba(0,0,0,0.8); color: #0f0; font-family: monospace; font-size: 12px; padding: 3px 4px; border-radius: 5px; z-index: 99999; display: block !important; transform: scale(0.8); transform-origin: bottom right;'; document.body.appendChild(pagetualDebug); } else { window._pagetualPageCounter++; } let debugDiv = document.getElementById('pagetual-debug'); if (debugDiv) debugDiv.textContent = 'P ' + window._pagetualPageCounter; setTimeout(() => { let allThumbs = document.querySelectorAll('.thumb-list__item:not(.loading)'); let hasVisible = Array.from(allThumbs).some(ele => { let style = window.getComputedStyle(ele); return style.display !== 'none' && style.visibility !== 'hidden' && ele.offsetParent !== null; }); if (!hasVisible && !window._pagetualAutoScrollTriggered) { window._pagetualAutoScrollTriggered = true; setTimeout(() => { window.scrollBy(0, 1); setTimeout(() => { window.scrollBy(0, -1); setTimeout(() => { window._pagetualAutoScrollTriggered = false; }, 200); }, 200); }, 50); } }, 500);" + "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); });" } ] From afefd0ae788c1d04c282dafbe4195367c5670f35 Mon Sep 17 00:00:00 2001 From: Vieller Date: Sat, 23 May 2026 23:06:08 +0200 Subject: [PATCH 09/14] Update pagetualRules.json (xHamster) pageElement: added new selector for channel videos --- Pagetual/pagetualRules.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index 6b1b76a4ac2..b9c19d5e4e1 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6492,11 +6492,11 @@ "name": "xHamster", "url": "^https://([\\w]+\\.)?(xhamster|xhaccess|xhamster19)\\.(com|desi)/", "author": "Vieller", - "pageElement": "div[data-ecommerce-list-name=\"default\"] div[class*=\"thumb-list__item\"]:not([class*=\"loading\"]), div[class*=\"galleryList\"] > div[class*=\"container\"] > div[class*=\"wrapper\"], div[class*=\"content\"] div[class*=\"wrapper-\"], div[class*=\"content\"] div[class*=\"default\"], [class*=\"photosList\"] > div[style]", + "pageElement": "div[data-ecommerce-list-name=\"default\"] div[class*=\"thumb-list__item\"]:not([class*=\"loading\"]), div[data-role=\"video-section-content-role\"] div[class*=\"thumb-list__item\"]:not([class*=\"loading\"]), div[class*=\"galleryList\"] > div[class*=\"container\"] > div[class*=\"wrapper\"], div[class*=\"content\"] div[class*=\"wrapper-\"], div[class*=\"content\"] div[class*=\"default\"], [class*=\"photosList\"] > div[style]", "nextLink": "a[data-page='next'], a[rel='next']", "action": 0, "init": "let candidates = Array.from(document.querySelectorAll('.thumb-list__item')); let bestCandidate = candidates.find(c => c.querySelector('[data-role=\"video-duration\"]')); if (!bestCandidate && candidates.length) bestCandidate = candidates[0]; if (!window._pagetualMasterTemplateVideo) { if (bestCandidate) { let clone = bestCandidate.cloneNode(true); let badgeElements = clone.querySelectorAll('[data-role=\"video-watched\"], [data-brand=\"full video\"]'); badgeElements.forEach(badge => badge.remove()); let xhIcons = clone.querySelectorAll('.xh-icon'); xhIcons.forEach(icon => icon.remove()); window._pagetualMasterTemplateVideo = clone.innerHTML; let durationSpan = clone.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) { let tinyClass = Array.from(durationSpan.classList).find(c => c.startsWith('tiny-')); if (tinyClass) { let suffix = tinyClass.split('-').pop(); if (suffix) window._pagetualSuffix = suffix; } } } } if (!window._pagetualMasterGallery) { let galleryCandidates = Array.from(document.querySelectorAll('[class*=\"container-\"] > [class*=\"wrapper\"]')); if (!galleryCandidates.length) galleryCandidates = Array.from(document.querySelectorAll('div[class*=\"wrapper\"]')).filter(el => el.querySelector('[class*=\"author-\"]')); let bestGallery = galleryCandidates.find(g => g.querySelector('[class*=\"author-\"]')); if (!bestGallery && galleryCandidates.length) bestGallery = galleryCandidates[0]; if (bestGallery) { let clone = bestGallery.cloneNode(true); window._pagetualMasterGallery = clone.innerHTML; let captionSpan = clone.querySelector('[class*=\"caption-\"]'); if (captionSpan) { let captionClass = Array.from(captionSpan.classList).find(c => c.startsWith('caption-')); if (captionClass) window._pagetualCaptionSuffix = captionClass.split('-').pop(); } let bodySpan = clone.querySelector('[class*=\"body-bold-\"]'); if (bodySpan) { let bodyClass = Array.from(bodySpan.classList).find(c => c.startsWith('body-bold-')); if (bodyClass) window._pagetualBodySuffix = bodyClass.split('-').pop(); } } } if (!window._pagetualSuffix) window._pagetualSuffix = '8643e'; if (!window._pagetualCaptionSuffix) window._pagetualCaptionSuffix = '8643e'; if (!window._pagetualBodySuffix) window._pagetualBodySuffix = '8643e';", "pageInit": "/* Extract data from window.initials and handle different page types */ let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch (e) { return; } /* Photo galleries main page – remove skeleton overlays only */ if (initials.photosPage !== undefined || initials.galleryPage !== undefined) { for (let ele of eles) { let skeleton = ele.querySelector('a[class*=\"cover\"] > div[class*=\"container-\"][class*=\"primaryColor-\"]'); if (skeleton && skeleton.querySelector('span[class*=\"dot\"]')) { skeleton.remove(); } } return; } function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; } function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString(); } /* Photo gallery search results – full hydration using gallery template */ if (initials.searchResultsPhotoComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.searchResultsPhotoComponent.list; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let authorContainer = div.querySelector('[class*=\"author-\"]'); if (authorContainer && data.author) { authorContainer.href = data.author.link; let nameSpan = authorContainer.querySelector('[class*=\"name-\"]'); if (nameSpan) { nameSpan.textContent = data.author.name; } } let avatarImg = div.querySelector('[class*=\"avatar-\"] img'); if (avatarImg && data.author && data.author.img) { avatarImg.src = data.author.img; avatarImg.alt = data.author.name; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* User profile photo gallery – full hydration */ if (initials.contentComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.contentComponent.items; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* Video pages – full hydration using video template */ let inner = window._pagetualMasterTemplateVideo; if (!inner) return; function findVideoProps(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object') return null; if (Array.isArray(obj) && obj.length > 0) { let first = obj[0]; if (first && typeof first === 'object' && 'id' in first && 'duration' in first && 'title' in first && 'pageURL' in first && 'views' in first) { return obj; } } for (let k in obj) if (obj.hasOwnProperty(k)) { let r = findVideoProps(obj[k], depth + 1); if (r) return r; } return null; } let props = findVideoProps(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", - "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); });" + "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); }); if (typeof window._pagetualPageCounter === 'undefined') { window._pagetualPageCounter = 1; let pagetualDebug = document.createElement('div'); pagetualDebug.id = 'pagetual-debug'; pagetualDebug.style.cssText = 'position: fixed; bottom: 10px; right: 10px; background: rgba(0,0,0,0.8); color: #0f0; font-family: monospace; font-size: 12px; padding: 3px 4px; border-radius: 5px; z-index: 99999; display: block !important; transform: scale(0.8); transform-origin: bottom right;'; document.body.appendChild(pagetualDebug); } else { window._pagetualPageCounter++; } let debugDiv = document.getElementById('pagetual-debug'); if (debugDiv) debugDiv.textContent = 'P ' + window._pagetualPageCounter; setTimeout(() => { let allThumbs = document.querySelectorAll('.thumb-list__item:not(.loading)'); let hasVisible = Array.from(allThumbs).some(ele => { let style = window.getComputedStyle(ele); return style.display !== 'none' && style.visibility !== 'hidden' && ele.offsetParent !== null; }); if (!hasVisible && !window._pagetualAutoScrollTriggered) { window._pagetualAutoScrollTriggered = true; setTimeout(() => { window.scrollBy(0, 1); setTimeout(() => { window.scrollBy(0, -1); setTimeout(() => { window._pagetualAutoScrollTriggered = false; }, 200); }, 200); }, 50); } }, 500);" } ] From a24a3de4873a41c67ccde79e141d1bddca6285b0 Mon Sep 17 00:00:00 2001 From: hoothin-update Date: Sat, 23 May 2026 23:16:38 +0000 Subject: [PATCH 10/14] Update version of Pagetual rules to 108 --- Pagetual/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pagetual/version b/Pagetual/version index e34885bbc6e..3b20426c050 100644 --- a/Pagetual/version +++ b/Pagetual/version @@ -1 +1 @@ -107 +108 From f54034e0ed5ca3fcb8127be5e3fc04b40118c203 Mon Sep 17 00:00:00 2001 From: vieller Date: Tue, 26 May 2026 14:34:54 +0200 Subject: [PATCH 11/14] Update pagetualRules.json (xHamster working 100%) - New "pageElement": fixes incorrect placement of new pages in some scenarios. - Switch to action:1, fixes empty container elements being fetched in some cases. - Videos: added "Friends Only" overlay for restricted content. - Heuristically locate photo metadata array inside window.initials . - Fixed conflict between uBlock Origin and mouse event listeners for video preview on hover. - Refactor to improve code clarity and maintainability --- Pagetual/pagetualRules.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Pagetual/pagetualRules.json b/Pagetual/pagetualRules.json index b9c19d5e4e1..2b81ff29282 100644 --- a/Pagetual/pagetualRules.json +++ b/Pagetual/pagetualRules.json @@ -6491,12 +6491,12 @@ { "name": "xHamster", "url": "^https://([\\w]+\\.)?(xhamster|xhaccess|xhamster19)\\.(com|desi)/", - "author": "Vieller", - "pageElement": "div[data-ecommerce-list-name=\"default\"] div[class*=\"thumb-list__item\"]:not([class*=\"loading\"]), div[data-role=\"video-section-content-role\"] div[class*=\"thumb-list__item\"]:not([class*=\"loading\"]), div[class*=\"galleryList\"] > div[class*=\"container\"] > div[class*=\"wrapper\"], div[class*=\"content\"] div[class*=\"wrapper-\"], div[class*=\"content\"] div[class*=\"default\"], [class*=\"photosList\"] > div[style]", + "author": "vieller", + "pageElement": "div:has(+ *[data-role*='pagination']), div:has(+ *[class*='pager-section']), div:has(+ *[class*='pagination-'])", "nextLink": "a[data-page='next'], a[rel='next']", - "action": 0, - "init": "let candidates = Array.from(document.querySelectorAll('.thumb-list__item')); let bestCandidate = candidates.find(c => c.querySelector('[data-role=\"video-duration\"]')); if (!bestCandidate && candidates.length) bestCandidate = candidates[0]; if (!window._pagetualMasterTemplateVideo) { if (bestCandidate) { let clone = bestCandidate.cloneNode(true); let badgeElements = clone.querySelectorAll('[data-role=\"video-watched\"], [data-brand=\"full video\"]'); badgeElements.forEach(badge => badge.remove()); let xhIcons = clone.querySelectorAll('.xh-icon'); xhIcons.forEach(icon => icon.remove()); window._pagetualMasterTemplateVideo = clone.innerHTML; let durationSpan = clone.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) { let tinyClass = Array.from(durationSpan.classList).find(c => c.startsWith('tiny-')); if (tinyClass) { let suffix = tinyClass.split('-').pop(); if (suffix) window._pagetualSuffix = suffix; } } } } if (!window._pagetualMasterGallery) { let galleryCandidates = Array.from(document.querySelectorAll('[class*=\"container-\"] > [class*=\"wrapper\"]')); if (!galleryCandidates.length) galleryCandidates = Array.from(document.querySelectorAll('div[class*=\"wrapper\"]')).filter(el => el.querySelector('[class*=\"author-\"]')); let bestGallery = galleryCandidates.find(g => g.querySelector('[class*=\"author-\"]')); if (!bestGallery && galleryCandidates.length) bestGallery = galleryCandidates[0]; if (bestGallery) { let clone = bestGallery.cloneNode(true); window._pagetualMasterGallery = clone.innerHTML; let captionSpan = clone.querySelector('[class*=\"caption-\"]'); if (captionSpan) { let captionClass = Array.from(captionSpan.classList).find(c => c.startsWith('caption-')); if (captionClass) window._pagetualCaptionSuffix = captionClass.split('-').pop(); } let bodySpan = clone.querySelector('[class*=\"body-bold-\"]'); if (bodySpan) { let bodyClass = Array.from(bodySpan.classList).find(c => c.startsWith('body-bold-')); if (bodyClass) window._pagetualBodySuffix = bodyClass.split('-').pop(); } } } if (!window._pagetualSuffix) window._pagetualSuffix = '8643e'; if (!window._pagetualCaptionSuffix) window._pagetualCaptionSuffix = '8643e'; if (!window._pagetualBodySuffix) window._pagetualBodySuffix = '8643e';", - "pageInit": "/* Extract data from window.initials and handle different page types */ let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials=')); } if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')'); } catch (e) { return; } /* Photo galleries main page – remove skeleton overlays only */ if (initials.photosPage !== undefined || initials.galleryPage !== undefined) { for (let ele of eles) { let skeleton = ele.querySelector('a[class*=\"cover\"] > div[class*=\"container-\"][class*=\"primaryColor-\"]'); if (skeleton && skeleton.querySelector('span[class*=\"dot\"]')) { skeleton.remove(); } } return; } function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier; } function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString(); } /* Photo gallery search results – full hydration using gallery template */ if (initials.searchResultsPhotoComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.searchResultsPhotoComponent.list; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let authorContainer = div.querySelector('[class*=\"author-\"]'); if (authorContainer && data.author) { authorContainer.href = data.author.link; let nameSpan = authorContainer.querySelector('[class*=\"name-\"]'); if (nameSpan) { nameSpan.textContent = data.author.name; } } let avatarImg = div.querySelector('[class*=\"avatar-\"] img'); if (avatarImg && data.author && data.author.img) { avatarImg.src = data.author.img; avatarImg.alt = data.author.name; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* User profile photo gallery – full hydration */ if (initials.contentComponent !== undefined) { let inner = window._pagetualMasterGallery; if (!inner) return; let items = initials.contentComponent.items; if (!items?.length) return; for (let i = 0; i < eles.length && i < items.length; i++) { let ele = eles[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL; } let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || ''; } let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || ''; } let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); } return; } /* Video pages – full hydration using video template */ let inner = window._pagetualMasterTemplateVideo; if (!inner) return; function findVideoProps(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object') return null; if (Array.isArray(obj) && obj.length > 0) { let first = obj[0]; if (first && typeof first === 'object' && 'id' in first && 'duration' in first && 'title' in first && 'pageURL' in first && 'views' in first) { return obj; } } for (let k in obj) if (obj.hasOwnProperty(k)) { let r = findVideoProps(obj[k], depth + 1); if (r) return r; } return null; } let props = findVideoProps(initials, 0); if (!props?.length) return; function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec); } for (let ele of eles) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || ''); } let img = div.querySelector('img.thumb-image-container__image'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || ''; } let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id; } let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || ''; } let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase(); } let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name; } } else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove(); } } let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w); } } if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b); } } while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild); }", - "pageAction": "eles.forEach(container => { let anchor = container.querySelector('a[data-role=\"thumb-link\"]'); if (!anchor) return; let trailerUrl = anchor.getAttribute('data-previewvideo'); if (!trailerUrl) return; if (getComputedStyle(anchor).position !== 'relative') anchor.style.position = 'relative'; let videoElem = null; anchor.addEventListener('mouseenter', () => { if (videoElem) return; videoElem = Object.assign(document.createElement('video'), { src: trailerUrl, loop: true, muted: true, autoplay: true, playsInline: true }); Object.assign(videoElem.style, { position: 'absolute', top: 0, left: 0, width: '100%', height: '100%', objectFit: 'cover', zIndex: 10, pointerEvents: 'none', backgroundColor: 'black' }); anchor.appendChild(videoElem); videoElem.play(); }); anchor.addEventListener('mouseleave', () => { if (!videoElem) return; videoElem.pause(); videoElem.remove(); videoElem = null; }); }); if (typeof window._pagetualPageCounter === 'undefined') { window._pagetualPageCounter = 1; let pagetualDebug = document.createElement('div'); pagetualDebug.id = 'pagetual-debug'; pagetualDebug.style.cssText = 'position: fixed; bottom: 10px; right: 10px; background: rgba(0,0,0,0.8); color: #0f0; font-family: monospace; font-size: 12px; padding: 3px 4px; border-radius: 5px; z-index: 99999; display: block !important; transform: scale(0.8); transform-origin: bottom right;'; document.body.appendChild(pagetualDebug); } else { window._pagetualPageCounter++; } let debugDiv = document.getElementById('pagetual-debug'); if (debugDiv) debugDiv.textContent = 'P ' + window._pagetualPageCounter; setTimeout(() => { let allThumbs = document.querySelectorAll('.thumb-list__item:not(.loading)'); let hasVisible = Array.from(allThumbs).some(ele => { let style = window.getComputedStyle(ele); return style.display !== 'none' && style.visibility !== 'hidden' && ele.offsetParent !== null; }); if (!hasVisible && !window._pagetualAutoScrollTriggered) { window._pagetualAutoScrollTriggered = true; setTimeout(() => { window.scrollBy(0, 1); setTimeout(() => { window.scrollBy(0, -1); setTimeout(() => { window._pagetualAutoScrollTriggered = false; }, 200); }, 200); }, 50); } }, 500);" + "action": 1, + "init": "let candidates=Array.from(document.querySelectorAll('.thumb-list__item'));let bestCandidate=candidates.find(c=>c.querySelector('[data-role=\"video-duration\"]'));if(!bestCandidate&&candidates.length) bestCandidate=candidates[0];if(!window._pagetualMasterTemplateVideo){if(bestCandidate){let clone=bestCandidate.cloneNode(true);let badgeElements=clone.querySelectorAll('[data-role=\"video-watched\"], [data-brand=\"full video\"]');badgeElements.forEach(badge=>badge.remove());let xhIcons=clone.querySelectorAll('.xh-icon');xhIcons.forEach(icon=>icon.remove());window._pagetualMasterTemplateVideo=clone.innerHTML;let durationSpan=clone.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]');if(durationSpan){let tinyClass=Array.from(durationSpan.classList).find(c=>c.startsWith('tiny-'));if(tinyClass){let suffix=tinyClass.split('-').pop();if(suffix) window._pagetualSuffix=suffix;}}}} if(!window._pagetualMasterGallery){let galleryCandidates=Array.from(document.querySelectorAll('[class*=\"container-\"] > [class*=\"wrapper\"]'));if(!galleryCandidates.length) galleryCandidates=Array.from(document.querySelectorAll('div[class*=\"wrapper\"]')).filter(el=>el.querySelector('[class*=\"author-\"]'));let bestGallery=galleryCandidates.find(g=>g.querySelector('[class*=\"author-\"]'));if(!bestGallery&&galleryCandidates.length) bestGallery=galleryCandidates[0];if(bestGallery){let clone=bestGallery.cloneNode(true);window._pagetualMasterGallery=clone.innerHTML;let captionSpan=clone.querySelector('[class*=\"caption-\"]');if(captionSpan){let captionClass=Array.from(captionSpan.classList).find(c=>c.startsWith('caption-'));if(captionClass) window._pagetualCaptionSuffix=captionClass.split('-').pop();} let bodySpan=clone.querySelector('[class*=\"body-bold-\"]');if(bodySpan){let bodyClass=Array.from(bodySpan.classList).find(c=>c.startsWith('body-bold-'));if(bodyClass) window._pagetualBodySuffix=bodyClass.split('-').pop();}}} if(!window._pagetualSuffix) window._pagetualSuffix='8643e';if(!window._pagetualCaptionSuffix) window._pagetualCaptionSuffix='8643e';if(!window._pagetualBodySuffix) window._pagetualBodySuffix='8643e';if(!window._pagetualFriendsOnlyTemplate){let rootClass='root-'+window._pagetualSuffix;let iconClass='icon-'+window._pagetualSuffix;window._pagetualFriendsOnlyTemplate=`
Friends only
`;}", + "pageInit": "let container = eles[0]; if (!container) return; /* Extract data from window.initials and handle different page types */ let script = doc.querySelector('script#initials-script'); if (!script) { script = Array.from(doc.querySelectorAll('script')).find(s => s.textContent.includes('window.initials='));} if (!script) return; let scriptText = script.textContent; let match = scriptText.match(/window\\.initials\\s*=\\s*(\\{[\\s\\S]*?\\});/); if (!match) return; let jsonStr = match[1]; let initials; try { initials = eval('(' + jsonStr + ')');} catch (e) { return;} /* Regular photo gallery (no hydration, remove skeleton overlays only) */ let skeletonSelector = 'a[class*=\"cover\"] > div[class*=\"container-\"][class*=\"primaryColor-\"]'; let loadingSkeleton = container.querySelector(skeletonSelector); /* if (initials.photosPage !== undefined || initials.galleryPage !== undefined) { */ if (loadingSkeleton) { let galleryItemSelector = 'div[class*=\"wrapper\"], div[style]:not([class])'; let galleryItems = container.querySelectorAll(galleryItemSelector); for (let ele of galleryItems) { /* let skeleton = ele.querySelector('a[class*=\"cover\"] > div[class*=\"container-\"][class*=\"primaryColor-\"]'); */ let skeleton = ele.querySelector(skeletonSelector); if (skeleton && skeleton.querySelector('span[class*=\"dot\"]')) { skeleton.remove();}} return;} function round(value, precision) { let multiplier = Math.pow(10, precision || 0); return Math.round(value * multiplier) / multiplier;} function formatViews(v) { if (v >= 1e6) return round(v / 1e6, 1) + 'M'; if (v >= 1e3) return round(v / 1e3, 1) + 'K'; return v.toString();} /* Heuristics: locate photo gallery metadata array in initials */ function findPhotoItems(initials, expectedCount, tolerance = 2) { function search(obj, targetLen, depth = 0) { if (depth > 12) return null; if (!obj || typeof obj !== 'object') return null; if (Array.isArray(obj) && obj.length === targetLen && obj.length > 0) { let first = obj[0]; if (first && typeof first === 'object') { let hasPhotoProps = ('pageURL' in first || 'imageURL' in first) && ('titleLocalized' in first || 'title' in first) && ('imgCount' in first || 'views' in first); if (hasPhotoProps) return obj;}} for (let k in obj) { if (obj.hasOwnProperty(k)) { let result = search(obj[k], targetLen, depth + 1); if (result) return result;}} return null;} let exactMatch = search(initials, expectedCount); if (exactMatch) return exactMatch; for (let delta = -tolerance; delta <= tolerance; delta++) { if (delta === 0) continue; let len = expectedCount + delta; if (len <= 0) continue; let match = search(initials, len); if (match) return match;} return null;} /* Generic photo gallery hydration (heuristics-based) */ let photoItemSelector = 'div[class*=\"container-\"] > div[class*=\"wrapper-\"], div[class*=\"container-\"] > div[class*=\"default-\"]'; let photoItems = container.querySelectorAll(photoItemSelector); if (photoItems.length && window._pagetualMasterGallery) { let items = findPhotoItems(initials, photoItems.length, 4); if (items?.length) { let inner = window._pagetualMasterGallery; for (let i = 0; i < photoItems.length && i < items.length; i++) { let ele = photoItems[i]; let data = items[i]; let div = document.createElement('div'); div.innerHTML = inner; let coverLink = div.querySelector('a[class*=\"coverLink-\"]'); if (coverLink && data.pageURL) { coverLink.href = data.pageURL;} let img = div.querySelector('img[class*=\"cover-\"]'); if (img) { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.titleLocalized || '';} let titleLink = div.querySelector('[class*=\"title-\"]'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.textContent = data.titleLocalized || '';} let authorContainer = div.querySelector('[class*=\"author-\"]'); if (authorContainer && data.author) { authorContainer.href = data.author.link; let nameSpan = authorContainer.querySelector('[class*=\"name-\"]'); if (nameSpan) { nameSpan.textContent = data.author.name;}} let avatarImg = div.querySelector('[class*=\"avatar-\"] img'); if (avatarImg && data.author && data.author.img) { avatarImg.src = data.author.img; avatarImg.alt = data.author.name;} let photoSpan = div.querySelector('[class*=\"caption\"][class*=\"label\"]'); if (photoSpan) photoSpan.textContent = data.imgCount; let viewsSpan = div.querySelector('[class*=\"viewsText-\"]'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild);} return;}} /* Heuristics: locate video metadata array in initials */ function findVideoProps(obj, depth) { if (depth > 10) return null; if (!obj || typeof obj !== 'object') return null; if (Array.isArray(obj) && obj.length > 0) { let first = obj[0]; if (first && typeof first === 'object' && 'id' in first && 'duration' in first && 'title' in first && 'pageURL' in first && 'views' in first) { return obj;}} for (let k in obj) if (obj.hasOwnProperty(k)) { let r = findVideoProps(obj[k], depth + 1); if (r) return r;} return null;} function formatDuration(s) { let h = Math.floor(s / 3600), m = Math.floor((s % 3600) / 60), sec = s % 60; if (h) return h + ':' + (m < 10 ? '0' + m : m) + ':' + (sec < 10 ? '0' + sec : sec); return m + ':' + (sec < 10 ? '0' + sec : sec);} /* Generic video page hydration (heuristics-based) */ let videoSelector = 'div[class*=\"thumb-list__item\"]:not([class*=\"loading\"])'; let videoItems = container.querySelectorAll(videoSelector); if (videoItems.length && window._pagetualMasterTemplateVideo) { let props = findVideoProps(initials, 0); if (props?.length) { let inner = window._pagetualMasterTemplateVideo; for (let ele of videoItems) { let id = ele.getAttribute('data-video-id'); if (!id) continue; let data = props.find(p => p.id == id); if (!data) continue; let div = document.createElement('div'); div.innerHTML = inner; let noscripts = div.querySelectorAll('noscript'); for (let ns of noscripts) ns.remove(); let link = div.querySelector('a[data-role=\"thumb-link\"]'); if (link && data.pageURL) { link.href = data.pageURL; link.setAttribute('data-previewvideo', data.trailerURL || ''); link.setAttribute('aria-label', data.title || '');} let img = div.querySelector('img.thumb-image-container__image'); if (img) { if (data.icon === 'friends') { let thumbContainer = div.querySelector('[class*=\"thumb-image-container\"]') || img.parentElement; img.remove(); if (thumbContainer && window._pagetualFriendsOnlyTemplate) { thumbContainer.insertAdjacentHTML('beforeend', window._pagetualFriendsOnlyTemplate);}} else { img.src = data.imageURL; img.srcset = data.thumbURL; img.alt = data.title || '';}} let sprite = div.querySelector('.thumb-image-container__sprite'); if (sprite) { sprite.setAttribute('data-sprite', data.spriteURL || ''); sprite.id = id;} let durationSpan = div.querySelector('[data-role=\"video-duration\"] [class*=\"tiny-\"]'); if (durationSpan) durationSpan.textContent = formatDuration(data.duration); let titleLink = div.querySelector('.video-thumb-info__name'); if (titleLink && data.pageURL) { titleLink.href = data.pageURL; titleLink.title = data.title || ''; titleLink.textContent = data.title || '';} let uploaderData = div.querySelector('.video-uploader-data'); if (uploaderData) { if (data.landing && data.landing.name) { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo && data.landing.link) { logo.href = data.landing.link; logo.textContent = data.landing.name.charAt(0).toUpperCase();} let name = uploaderData.querySelector('.video-uploader__name'); if (name && data.landing.link) { name.href = data.landing.link; name.textContent = data.landing.name;}} else { let logo = uploaderData.querySelector('.video-uploader-logo'); if (logo) logo.remove(); let name = uploaderData.querySelector('.video-uploader__name'); if (name) name.remove(); let sep = uploaderData.querySelector('.video-thumb-uploader__separator'); if (sep) sep.remove();}} let viewsSpan = div.querySelector('.video-thumb-views'); if (viewsSpan) viewsSpan.textContent = formatViews(data.views) + ' views'; let onVideo = div.querySelector('.thumb-image-container__on-video'); if (onVideo) onVideo.style.zIndex = '20'; if (data.isWatched) { if (onVideo && !onVideo.querySelector('.thumb-image-container__watched')) { let w = document.createElement('div'); w.className = 'thumb-image-container__watched'; w.setAttribute('data-role', 'video-watched'); let tinyBold = 'tiny-bold-' + window._pagetualSuffix; let invert = 'invert-' + window._pagetualSuffix; w.innerHTML = `
Watched
`; if (onVideo.firstChild) onVideo.insertBefore(w, onVideo.firstChild); else onVideo.appendChild(w);}} if (data.hasProducerBadge) { let a = div.querySelector('a[data-role=\"thumb-link\"]'); if (a && !a.querySelector('.thumb-image-container__badge')) { let b = document.createElement('div'); b.className = 'thumb-image-container__badge'; b.setAttribute('data-role-producer-badge', ''); b.setAttribute('data-brand', 'full video'); b.innerHTML = ''; a.appendChild(b);}} while (ele.firstChild) ele.removeChild(ele.firstChild); while (div.firstChild) ele.appendChild(div.firstChild);}}}", + "pageAction": "if(!window._pagetualVideoPreviewAdded){window._pagetualVideoPreviewAdded=true;document.body.addEventListener('mouseenter',(e)=>{let anchor=e.target.closest('a[data-role=\"thumb-link\"]');if(!anchor) return;let trailerUrl=anchor.getAttribute('data-previewvideo');if(!trailerUrl) return;if(anchor._videoElem) return;if(getComputedStyle(anchor).position!=='relative') anchor.style.position='relative';let videoElem=Object.assign(document.createElement('video'),{src:trailerUrl,loop:true,muted:true,autoplay:true,playsInline:true});Object.assign(videoElem.style,{position:'absolute',top:0,left:0,width:'100%',height:'100%',objectFit:'cover',zIndex:10,pointerEvents:'none',backgroundColor:'black'});anchor.appendChild(videoElem);videoElem.play().catch(e=>console.warn('play error:',e));anchor._videoElem=videoElem;},true);document.body.addEventListener('mouseleave',(e)=>{let anchor=e.target.closest('a[data-role=\"thumb-link\"]');if(!anchor) return;let videoElem=anchor._videoElem;if(!videoElem) return;videoElem.pause();videoElem.remove();anchor._videoElem=null;},true);}" } ] From a1be06f6a4ae16b0c0aef2ed5c8eec82c7bbaf9b Mon Sep 17 00:00:00 2001 From: hoothin Date: Tue, 26 May 2026 21:46:05 +0900 Subject: [PATCH 12/14] Update json-validator.yml --- .github/workflows/json-validator.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/json-validator.yml b/.github/workflows/json-validator.yml index a726236d040..01911cc1730 100644 --- a/.github/workflows/json-validator.yml +++ b/.github/workflows/json-validator.yml @@ -13,9 +13,9 @@ jobs: - uses: actions/checkout@v4 - name: json-yaml-validate - uses: GrantBirki/json-yaml-validate@v3.0.0 + uses: GrantBirki/json-yaml-validate@v5 id: json-yaml-validate with: json_schema: Pagetual/pagetual.schema.json files: | - Pagetual/pagetualRules.json \ No newline at end of file + Pagetual/pagetualRules.json From 9a695f061df9d4f343a809762f6339e4dc4a9ff0 Mon Sep 17 00:00:00 2001 From: hoothin-update Date: Tue, 26 May 2026 12:52:57 +0000 Subject: [PATCH 13/14] Update version of Pagetual rules to 109 --- Pagetual/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Pagetual/version b/Pagetual/version index 3b20426c050..e2a9fee008a 100644 --- a/Pagetual/version +++ b/Pagetual/version @@ -1 +1 @@ -108 +109 From 5ddabf865953685a2c61a9cd46f39051c85b91d6 Mon Sep 17 00:00:00 2001 From: hoothin Date: Mon, 8 Jun 2026 11:29:43 +0900 Subject: [PATCH 14/14] Update pagetual.user.js --- Pagetual/pagetual.user.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Pagetual/pagetual.user.js b/Pagetual/pagetual.user.js index 3ebfba30c69..ae4b3ad94f3 100644 --- a/Pagetual/pagetual.user.js +++ b/Pagetual/pagetual.user.js @@ -31,7 +31,7 @@ // @name:da Pagetual // @name:fr-CA Pagetual // @namespace hoothin -// @version 1.9.37.131 +// @version 1.9.37.132 // @description Perpetual pages - powerful auto-pager script. Auto fetching next paginated web pages and inserting into current page for infinite scroll. Support thousands of web sites without any rule. // @description:zh-CN 终极自动翻页 - 加载并拼接下一分页内容至当前页尾,智能适配任意网页 // @description:zh-TW 終極自動翻頁 - 加載並拼接下一分頁內容至當前頁尾,智能適配任意網頁 @@ -4513,7 +4513,7 @@ const wedataRulesUrl = "http://wedata.net/databases/AutoPagerize/items_all.json"; const wedataMirrorRulesUrl = "https://hoothin.github.io/UserScripts/Pagetual/items_all.json"; const guidePage = /^https?:\/\/.*pagetual.*rule\.html/i; - const ruleImportUrlReg = /greasyfork\.org\/.*scripts\/438684(\-[^\/]*)?(\/discussions|\/?$|\/feedback)|github\.com\/hoothin\/UserScripts\/(tree\/master\/Pagetual|issues)|^https:\/\/pagetual\.hoothin\.com\/.*firstRun\.html/i; + const ruleImportUrlReg = /greasyfork\.org\/.*scripts\/438684(\-[^\/]*)?(\/discussions|\/?$|\/feedback)|github\.com\/hoothin\/UserScripts\/(tree\/master\/Pagetual|issues)|^https:\/\/pagetual\.hoothin\.com\/.*first(Run|-run)\.html/i; const allOfBody = "body>*"; const mainSel = ["article,.article","[role=main],main,.main,#main","#results"]; const nextTextReg1 = new RegExp("\u005e\u7ffb\u003f\u005b\u4e0b\u540e\u5f8c\u6b21\u005d\u005b\u4e00\u30fc\u2500\u0031\u005d\u003f\u005b\u9875\u9801\u5f20\u5f35\u005d\u007c\u005e\u006e\u0065\u0078\u0074\u005b\u005c\u0073\u005f\u002d\u005d\u003f\u0070\u0061\u0067\u0065\u005c\u0073\u002a\u005b\u203a\u003e\u2192\u00bb\u005d\u003f\u0024\u007c\u6b21\u306e\u30da\u30fc\u30b8\u007c\u005e\u6b21\u3078\u0024\u007c\u0412\u043f\u0435\u0440\u0435\u0434\u007c\u005e\u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435", "i");