Adds HD and Newest quick filter buttons on pornstar/creator profiles + auto-shows description and date under the video.
// ==UserScript==
// @name xHamster Tweaks
// @namespace http://tampermonkey.net/
// @version 2.0
// @description Adds HD and Newest quick filter buttons on pornstar/creator profiles + auto-shows description and date under the video.
// @author nereids
// @match https://xhamster.com/pornstars/*
// @match https://xhamster.com/creators/*
// @match https://xhamster.com/videos/*
// @match https://xhamster.com/movies/*
// @icon https://icons.duckduckgo.com/ip3/xhamster.com.ico
// @license MIT
// @grant GM_addStyle
// ==/UserScript==
(function() {
'use strict';
// 1. Unified CSS Styles
GM_addStyle(`
.auto-about-info {
width: fit-content !important;
max-width: 100% !important;
white-space: normal;
}
.xh-custom-filter-btn {
text-decoration: none !important;
margin-left: 2px;
}
#xh-custom-meta-box {
display: inline-block;
width: max-content;
max-width: 100%;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
padding: 16px;
margin-top: 12px;
margin-bottom: 12px;
font-family: sans-serif;
color: #e3e3e3;
box-sizing: border-box;
}
.xh-meta-desc {
font-size: 13px;
word-wrap: break-word;
margin-bottom: 10px;
line-height: 1.5;
white-space: normal;
}
.xh-meta-subline {
display: flex;
gap: 15px;
font-size: 13px;
color: #a0a0a0;
}
.xh-meta-subline a {
color: #ff8c00;
text-decoration: none;
}
`);
// 2. SVG Assets
const svgs = {
hd: {
default: `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M300-440h80v50q0 13 8.5 21.5T410-360q13 0 21.5-8.5T440-390v-180q0-13-8.5-21.5T410-600q-13 0-21.5 8.5T380-570v70h-80v-70q0-13-8.5-21.5T270-600q-13 0-21.5 8.5T240-570v180q0 13 8.5 21.5T270-360q13 0 21.5-8.5T300-390v-50Zm240 80h140q17 0 28.5-11.5T720-400v-160q0-17-11.5-28.5T680-600H540q-8 0-14 6t-6 14v200q0 8 6 14t14 6Zm40-60v-120h80v120h-80ZM160-160q-33 0-56.5-23.5T80-240v-480q0-33 23.5-56.5T160-800h640q33 0 56.5 23.5T880-720v480q0 33-23.5 56.5T800-160H160Zm0-80h640v-480H160v480Zm0 0v-480 480Z"/></svg>`,
selected: `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M300-446.15h92.31V-390q0 10.31 6.77 17.08 6.77 6.77 17.07 6.77 10.31 0 17.08-6.77Q440-379.69 440-390v-180q0-10.31-6.77-17.08-6.77-6.77-17.08-6.77-10.3 0-17.07 6.77T392.31-570v76.15H300V-570q0-10.31-6.77-17.08-6.77-6.77-17.08-6.77-10.3 0-17.07 6.77T252.31-570v180q0 10.31 6.77 17.08 6.77 6.77 17.07 6.77 10.31 0 17.08-6.77Q300-379.69 300-390v-56.15Zm238.08 80h128.07q17.39 0 29.46-12.08 12.08-12.08 12.08-29.46v-144.62q0-17.38-12.08-29.46-12.07-12.08-29.46-12.08H538.08q-7.23 0-12.66 5.43Q520-583 520-575.77v191.54q0 7.23 5.42 12.65 5.43 5.43 12.66 5.43Zm29.61-47.7v-132.3h86.16q2.3 0 4.23 1.92Q660-542.31 660-540v120q0 2.31-1.92 4.23-1.93 1.92-4.23 1.92h-86.16ZM172.31-180Q142-180 121-201q-21-21-21-51.31v-455.38Q100-738 121-759q21-21 51.31-21h615.38Q818-780 839-759q21 21 21 51.31v455.38Q860-222 839-201q-21 21-51.31 21H172.31Z"/></svg>`
},
new: {
default: `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M120-160q-33 0-56.5-23.5T40-240v-480q0-33 23.5-56.5T120-800h720q33 0 56.5 23.5T920-720v480q0 33-23.5 56.5T840-160H120Zm0-80h720v-480H120v480Zm70-260 95 130q3 5 8 7.5t11 2.5h12q10 0 17-7t7-17v-191q0-11-7-18t-18-7q-11 0-18 7t-7 18v115l-93-130q-4-5-9-7.5t-11-2.5h-12q-11 0-18 7t-7 18v190q0 11 7 18t18 7q11 0 18-7t7-18v-115Zm210 140h115q11 0 18-7t7-18q0-11-7-18t-18-7h-75v-44h75q11 0 18-7t7-18q0-11-7-18t-18-7h-75v-46h75q11 0 18-7t7-18q0-11-7-18t-18-7H400q-8 0-14 6t-6 14v200q0 8 6 14t14 6Zm220 0h160q17 0 28.5-11.5T820-400v-175q0-11-7-18t-18-7q-11 0-18 7t-7 18v155h-44v-115q0-11-7-18t-18-7q-11 0-18 7t-7 18v115h-46v-155q0-11-7-18t-18-7q-11 0-18 7t-7 18v175q0 17 11.5 28.5T620-360ZM120-240v-480 480Z"/></svg>`,
selected: `<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#e3e3e3"><path d="M132.31-180Q102-180 81-201q-21-21-21-51.31v-455.38Q60-738 81-759q21-21 51.31-21h695.38Q858-780 879-759q21 21 21 51.31v455.38Q900-222 879-201q-21 21-51.31 21H132.31Zm56.92-336.16L288.46-375q2.62 4.23 6.86 6.54 4.24 2.31 9.33 2.31h10.18q8.48 0 14.52-5.99 6.03-5.99 6.03-14.55v-186.39q0-9.14-5.8-14.95-5.8-5.82-14.92-5.82-9.12 0-14.97 5.82-5.84 5.81-5.84 14.95v129.24L197-585q-3.23-4.61-7.75-6.73t-9.94-2.12h-10.26q-9.39 0-15.38 6.03-5.98 6.04-5.98 15.51v185.39q0 9.14 5.81 14.95 5.8 5.82 14.92 5.82 9.12 0 14.96-5.82 5.85-5.81 5.85-14.95v-129.24Zm215 150.01h108.85q9.14 0 14.95-5.81 5.82-5.8 5.82-14.92 0-9.12-5.82-14.97-5.81-5.84-14.95-5.84h-79.23v-50.16h79.23q9.14 0 14.95-5.8 5.82-5.8 5.82-14.92 0-9.12-5.82-14.97-5.81-5.84-14.95-5.84h-79.23v-52.93h79.23q9.14 0 14.95-5.8 5.82-5.8 5.82-14.92 0-9.12-5.82-14.97-5.81-5.85-14.95-5.85H404.23q-7.23 0-12.65 5.43-5.43 5.42-5.43 12.65v191.54q0 7.23 5.43 12.65 5.42 5.43 12.65 5.43Zm214.23 0h160q14.69 0 24.27-9.58t9.58-24.27v-173.08q0-9.14-5.81-14.95-5.8-5.82-14.92-5.82-9.12 0-14.96 5.82-5.85 5.81-5.85 14.95v159.23h-50.92v-119.23q0-9.14-5.81-14.95-5.8-5.82-14.92-5.82-9.12 0-14.97 5.82-5.84 5.81-5.84 14.95v119.23h-52.16v-159.23q0-9.14-5.8-14.95-5.8-5.82-14.92-5.82-9.12 0-14.97 5.82-5.84 5.81-5.84 14.95V-400q0 14.69 9.57 24.27 9.58 9.58 24.27 9.58Z"/></svg>`
}
};
// 3. Logic for Profile Quick Filters
function getBaseUrl() {
const parts = window.location.pathname.split('/').filter(Boolean);
return `/${parts[0]}/${parts[1]}`;
}
function createCustomButton(text, href, svgIcon, baseClassNames) {
const btn = document.createElement('a');
btn.href = href;
btn.className = `${baseClassNames} xh-custom-filter-btn`;
btn.innerHTML = `
<span class="icon-container" style="display: flex; align-items: center;">${svgIcon}</span>
<span class="body-bold-8643e primary-8643e">${text}</span>
`;
return btn;
}
function handleProfileFilters() {
if (document.querySelector('.xh-custom-filter-btn')) return;
const buttons = Array.from(document.querySelectorAll('button.container-a4c1b.button-a4c1b'));
const filterButton = buttons.find(btn => btn.textContent.trim().includes('Filters'));
if (filterButton) {
// Evaluates path ending with target or target followed immediately by a slash (for pages like /hd/2)
const isHDActive = /\/hd(\/|$)/.test(window.location.pathname);
const isNewActive = /\/newest(\/|$)/.test(window.location.pathname);
const baseUrl = getBaseUrl();
const btnClasses = filterButton.className;
const hdSvg = isHDActive ? svgs.hd.selected : svgs.hd.default;
const newSvg = isNewActive ? svgs.new.selected : svgs.new.default;
const hdBtn = createCustomButton('HD', `${baseUrl}/hd`, hdSvg, btnClasses);
const newBtn = createCustomButton('New', `${baseUrl}/newest`, newSvg, btnClasses);
filterButton.parentNode.insertBefore(hdBtn, filterButton.nextSibling);
filterButton.parentNode.insertBefore(newBtn, hdBtn.nextSibling);
}
}
// 4. Logic for Auto-Displaying Video Meta Details
function handleVideoMetaDisplay() {
if (document.getElementById('xh-custom-meta-box')) return;
const controlsElement = document.querySelector('div.controls');
const abInfo = document.querySelector('div.ab-info[data-role="controls-info"]');
if (controlsElement && abInfo) {
const descEl = abInfo.querySelector('.controls-info__description');
//Uncomment below if you want uploader name in the about box
//const authorEl = abInfo.querySelector('.entity-info-container__author');
const dateEl = abInfo.querySelector('.entity-info-container__date');
if (descEl && dateEl) {
const metaBox = document.createElement('div');
metaBox.id = 'xh-custom-meta-box';
let sublineHTML = '';
//Uncomment below if you want uploader name in the about box
//if (authorEl) {
// sublineHTML += `<span>${authorEl.innerHTML.trim()}</span>`;
//}
sublineHTML += `<span>${dateEl.textContent.trim()}</span>`;
if(dateEl.getAttribute('data-tooltip')) {
sublineHTML += `<span>${dateEl.getAttribute('data-tooltip')}</span>`;
}
metaBox.innerHTML = `
<div class="xh-meta-desc">${descEl.innerHTML.trim()}</div>
<div class="xh-meta-subline">${sublineHTML}</div>
`;
controlsElement.parentNode.insertBefore(metaBox, controlsElement.nextSibling);
}
}
}
// 5. Universal Observer Loop
const observer = new MutationObserver(() => {
const path = window.location.pathname;
if (path.includes('/pornstars/') || path.includes('/creators/')) {
handleProfileFilters();
}
if (path.includes('/videos/') || path.includes('/movies/')) {
handleVideoMetaDisplay();
}
});
observer.observe(document.body, { childList: true, subtree: true });
})();